From d47c7647daa9c8ca352967d8c5176d1a1dbeab71 Mon Sep 17 00:00:00 2001 From: daid Date: Tue, 4 Feb 2014 12:38:19 +0100 Subject: [PATCH] Add more documentation, fix commandline slicing. --- Cura/cura.py | 27 +++++++++++++-------------- Cura/doctest.py | 12 ++++++++++++ Cura/serialCommunication.py | 10 +++++++--- Cura/util/explorer.py | 8 ++++++++ Cura/util/meshLoaders/amf.py | 7 +++++++ Cura/util/meshLoaders/dae.py | 7 +++++++ Cura/util/meshLoaders/obj.py | 7 +++++++ Cura/util/meshLoaders/stl.py | 12 ++++++++++++ Cura/util/polygon.py | 19 ++++++++++++++++++- Cura/util/profile.py | 4 ++++ Cura/util/removableStorage.py | 7 +++++++ Cura/util/resources.py | 4 ++++ Cura/util/sliceEngine.py | 4 ++++ Cura/util/util3d.py | 8 ++++++++ Cura/util/validators.py | 9 +++++++++ Cura/util/version.py | 4 ++++ Cura/util/youmagine.py | 4 ++++ 17 files changed, 135 insertions(+), 18 deletions(-) diff --git a/Cura/cura.py b/Cura/cura.py index 2208d983..a8b22ef5 100644 --- a/Cura/cura.py +++ b/Cura/cura.py @@ -46,26 +46,25 @@ def main(): from Cura.util import meshLoader import shutil - def commandlineProgressCallback(progress, ready): - if progress >= 0 and not ready: - print 'Preparing: %d%%' % (progress * 100) + def commandlineProgressCallback(progress): + if progress >= 0: + #print 'Preparing: %d%%' % (progress * 100) + pass scene = objectScene.Scene() scene.updateMachineDimensions() - slicer = sliceEngine.Slicer(commandlineProgressCallback) + engine = sliceEngine.Engine(commandlineProgressCallback) for m in meshLoader.loadMeshes(args[0]): scene.add(m) - slicer.runSlicer(scene) - slicer.wait() - profile.replaceGCodeTagsFromSlicer(slicer.getGCodeFilename(), slicer) + engine.runEngine(scene) + engine.wait() - if options.output: - shutil.copyfile(slicer.getGCodeFilename(), options.output) - print 'GCode file saved : %s' % options.output - else: - shutil.copyfile(slicer.getGCodeFilename(), args[0] + '.gcode') - print 'GCode file saved as: %s' % (args[0] + '.gcode') + if not options.output: + options.output = args[0] + '.gcode' + with open(options.output, "wb") as f: + f.write(engine.getResult().getGCode()) + print 'GCode file saved : %s' % options.output - slicer.cleanup() + engine.cleanup() else: from Cura.gui import app app.CuraApp(args).MainLoop() diff --git a/Cura/doctest.py b/Cura/doctest.py index 18139c08..3640367e 100644 --- a/Cura/doctest.py +++ b/Cura/doctest.py @@ -11,6 +11,7 @@ import types import random def treeWalk(moduleList, dirname, fnames): + """ Callback from the os.path.walk function, see if the given path is a module and import it to put it in the moduleList """ dirname = dirname.replace("\\", ".").replace("/", ".") if dirname == 'Cura.util.pymclevel': return @@ -33,6 +34,11 @@ def treeWalk(moduleList, dirname, fnames): print "Failed to load: %s" % (fullName) def main(): + """ + Main doctest function. + Calculate how many things are documented and not documented yet. + And report a random selection of undocumented functions/ modules. + """ moduleList = [] os.path.walk("Cura", treeWalk, moduleList) moduleDocCount = 0 @@ -48,6 +54,11 @@ def main(): undocList.append(module.__name__) for name in dir(module): a = getattr(module, name) + try: + if not inspect.getfile(a).startswith('Cura'): + continue + except: + continue if type(a) is types.FunctionType: functionCount += 1 if inspect.getdoc(a): @@ -74,6 +85,7 @@ def main(): print '%d/%d modules have documentation.' % (moduleDocCount, len(moduleList)) print '%d/%d functions have documentation.' % (functionDocCount, functionCount) print '%d/%d types have documentation.' % (typeDocCount, typeCount) + print '%.1f%% documented.' % (float(moduleDocCount + functionDocCount + typeDocCount) / float(len(moduleList) + functionCount + typeCount) * 100.0) print '' print 'You might want to document:' for n in xrange(0, 10): diff --git a/Cura/serialCommunication.py b/Cura/serialCommunication.py index 6a8b1a05..0534a84b 100644 --- a/Cura/serialCommunication.py +++ b/Cura/serialCommunication.py @@ -1,8 +1,12 @@ -__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" +""" +Serial communication with the printer for printing is done from a separate process, +this to ensure that the PIL does not block the serial printing. -# Serial communication with the printer for printing is done from a separate process, -# this to ensure that the PIL does not block the serial printing. +This file is the 2nd process that is started to handle communication with the printer. +And handles all communication with the initial process. +""" +__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import sys import time import os diff --git a/Cura/util/explorer.py b/Cura/util/explorer.py index 35991823..1e2a5a0b 100644 --- a/Cura/util/explorer.py +++ b/Cura/util/explorer.py @@ -1,3 +1,7 @@ +""" +Simple utility module to open "explorer" file dialogs. +The name "explorer" comes from the windows file explorer, which is called explorer. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import sys @@ -5,6 +9,7 @@ import os import subprocess def hasExplorer(): + """Check if we have support for opening file dialog windows.""" if sys.platform == 'win32' or sys.platform == 'cygwin' or sys.platform == 'darwin': return True if sys.platform == 'linux2': @@ -15,17 +20,20 @@ def hasExplorer(): return False def openExplorer(filename): + """Open an file dialog window in the directory of a file, and select the file.""" if sys.platform == 'win32' or sys.platform == 'cygwin': subprocess.Popen(r'explorer /select,"%s"' % (filename)) if sys.platform == 'darwin': subprocess.Popen(['open', '-R', filename]) if sys.platform.startswith('linux'): + #TODO: On linux we cannot seem to select a certain file, only open the specified path. if os.path.isfile('/usr/bin/nautilus'): subprocess.Popen(['/usr/bin/nautilus', os.path.split(filename)[0]]) elif os.path.isfile('/usr/bin/dolphin'): subprocess.Popen(['/usr/bin/dolphin', os.path.split(filename)[0]]) def openExplorerPath(filename): + """Open a file dialog inside a directory, without selecting any file.""" if sys.platform == 'win32' or sys.platform == 'cygwin': subprocess.Popen(r'explorer "%s"' % (filename)) if sys.platform == 'darwin': diff --git a/Cura/util/meshLoaders/amf.py b/Cura/util/meshLoaders/amf.py index 0c63151b..848f8bd0 100644 --- a/Cura/util/meshLoaders/amf.py +++ b/Cura/util/meshLoaders/amf.py @@ -1,3 +1,10 @@ +""" +AMF file reader. +AMF files are the proposed replacement for STL. AMF is an open standard to share 3D manufacturing files. +Many of the features found in AMF are currently not yet support in Cura. Most important the curved surfaces. + +http://en.wikipedia.org/wiki/Additive_Manufacturing_File_Format +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import cStringIO as StringIO diff --git a/Cura/util/meshLoaders/dae.py b/Cura/util/meshLoaders/dae.py index 8798859a..f173ddf1 100644 --- a/Cura/util/meshLoaders/dae.py +++ b/Cura/util/meshLoaders/dae.py @@ -1,3 +1,10 @@ +""" +DAE are COLLADA files. +The DAE reader is a limited COLLADA reader. And has only been tested with DAE exports from SketchUp, http://www.sketchup.com/ +The reason for this reader in Cura is that the free version of SketchUp by default does not support any other format that we can read. + +http://en.wikipedia.org/wiki/COLLADA +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" from xml.parsers.expat import ParserCreate diff --git a/Cura/util/meshLoaders/obj.py b/Cura/util/meshLoaders/obj.py index c5a2be9f..8c1fc083 100644 --- a/Cura/util/meshLoaders/obj.py +++ b/Cura/util/meshLoaders/obj.py @@ -1,3 +1,10 @@ +""" +OBJ file reader. +OBJ are wavefront object files. These are quite common and can be exported from a lot of 3D tools. +Only vertex information is read from the OBJ file, information about textures and normals is ignored. + +http://en.wikipedia.org/wiki/Wavefront_.obj_file +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import os diff --git a/Cura/util/meshLoaders/stl.py b/Cura/util/meshLoaders/stl.py index 029a0b86..dc7c56ed 100644 --- a/Cura/util/meshLoaders/stl.py +++ b/Cura/util/meshLoaders/stl.py @@ -1,3 +1,15 @@ +""" +STL file mesh loader. +STL is the most common file format used for 3D printing right now. +STLs come in 2 flavors. + Binary, which is easy and quick to read. + Ascii, which is harder to read, as can come with windows, mac and unix style newlines. + The ascii reader has been designed so it has great compatibility with all kinds of formats or slightly broken exports from tools. + +This module also contains a function to save objects as an STL file. + +http://en.wikipedia.org/wiki/STL_(file_format) +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import sys diff --git a/Cura/util/polygon.py b/Cura/util/polygon.py index 8772139f..2ec81952 100644 --- a/Cura/util/polygon.py +++ b/Cura/util/polygon.py @@ -1,8 +1,12 @@ +""" +The polygon module has functions that assist in working with 2D convex polygons. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import numpy def convexHull(pointList): + """ Create a convex hull from a list of points. """ def _isRightTurn((p, q, r)): sum1 = q[0]*r[1] + p[0]*q[1] + r[0]*p[1] sum2 = q[0]*p[1] + r[0]*q[1] + p[0]*r[1] @@ -45,6 +49,7 @@ def convexHull(pointList): return numpy.array(upper + lower, numpy.float32) def minkowskiHull(a, b): + """Calculate the minkowski hull of 2 convex polygons""" points = numpy.zeros((len(a) * len(b), 2)) for n in xrange(0, len(a)): for m in xrange(0, len(b)): @@ -52,6 +57,11 @@ def minkowskiHull(a, b): return convexHull(points.copy()) def projectPoly(poly, normal): + """ + Project a convex polygon on a given normal. + A projection of a convex polygon on a infinite line is a finite line. + Give the min and max value on the normal line. + """ pMin = numpy.dot(normal, poly[0]) pMax = pMin for n in xrange(1 , len(poly)): @@ -61,6 +71,7 @@ def projectPoly(poly, normal): return pMin, pMax def polygonCollision(polyA, polyB): + """ Check if convexy polygon A and B collide, return True if this is the case. """ for n in xrange(0, len(polyA)): p0 = polyA[n-1] p1 = polyA[n] @@ -88,6 +99,7 @@ def polygonCollision(polyA, polyB): return True def polygonCollisionPushVector(polyA, polyB): + """ Check if convex polygon A and B collide, return the vector of penetration if this is the case, else return False. """ retSize = 10000000.0 ret = False for n in xrange(0, len(polyA)): @@ -124,8 +136,10 @@ def polygonCollisionPushVector(polyA, polyB): retSize = size return ret -#Check if polyA is fully inside of polyB. def fullInside(polyA, polyB): + """ + Check if convex polygon A is completely inside of convex polygon B. + """ for n in xrange(0, len(polyA)): p0 = polyA[n-1] p1 = polyA[n] @@ -153,9 +167,11 @@ def fullInside(polyA, polyB): return True def isLeft(a, b, c): + """ Check if C is left of the infinite line from A to B """ return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) > 0 def lineLineIntersection(p0, p1, p2, p3): + """ Return the intersection of the infinite line trough points p0 and p1 and infinite line trough points p2 and p3. """ A1 = p1[1] - p0[1] B1 = p0[0] - p1[0] C1 = A1*p0[0] + B1*p0[1] @@ -170,6 +186,7 @@ def lineLineIntersection(p0, p1, p2, p3): return [(B2*C1 - B1*C2)/det, (A1 * C2 - A2 * C1) / det] def clipConvex(poly0, poly1): + """ Cut the convex polygon 0 so that it completely fits in convex polygon 1, any part sticking out of polygon 1 is cut off """ res = poly0 for p1idx in xrange(0, len(poly1)): src = res diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 8a764ac6..1e3e4416 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -1,3 +1,7 @@ +""" +The profile module contains all the settings for Cura. +These settings can be globally accessed and modified. +""" from __future__ import division __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" diff --git a/Cura/util/removableStorage.py b/Cura/util/removableStorage.py index 9bf7e4fd..812e9e98 100644 --- a/Cura/util/removableStorage.py +++ b/Cura/util/removableStorage.py @@ -1,3 +1,10 @@ +""" +This module handles detection and clean ejection of removable storage. (Mainly SD cards) +This is OS depended. + On windows it looks for removable storage drives. + On MacOS it specificly looks for SD cards. + On Linux it looks for anything mounted in /media/ +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import platform import string diff --git a/Cura/util/resources.py b/Cura/util/resources.py index 70ac64e5..1d7bcc47 100644 --- a/Cura/util/resources.py +++ b/Cura/util/resources.py @@ -1,3 +1,7 @@ +""" +Helper module to get easy access to the path where resources are stored. +This is because the resource location is depended on the packaging method and OS +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import os diff --git a/Cura/util/sliceEngine.py b/Cura/util/sliceEngine.py index 12388e76..51e8a59e 100644 --- a/Cura/util/sliceEngine.py +++ b/Cura/util/sliceEngine.py @@ -1,3 +1,7 @@ +""" +Slice engine communication. +This module handles all communication with the slicing engine. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import subprocess import time diff --git a/Cura/util/util3d.py b/Cura/util/util3d.py index db52e791..f923f37b 100644 --- a/Cura/util/util3d.py +++ b/Cura/util/util3d.py @@ -1,9 +1,17 @@ +""" +The util3d module a vector class to work with 3D points. All the basic math operators have been overloaded to work on this object. +This module is deprecated and only used by the SplitModels function. + +Use numpy arrays instead to work with vectors. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import math class Vector3(object): + """ 3D vector object. """ def __init__(self, x=0.0, y=0.0, z=0.0): + """Create a new 3D vector""" self.x = x self.y = y self.z = z diff --git a/Cura/util/validators.py b/Cura/util/validators.py index f920aa97..15673791 100644 --- a/Cura/util/validators.py +++ b/Cura/util/validators.py @@ -1,3 +1,12 @@ +""" +Setting validators. +These are the validators for various profile settings, each validator can be attached to a setting. +The validators can be queried to see if the setting is valid. +There are 3 possible outcomes: + Valid - No problems found + Warning - The value is valid, but not recommended + Error - The value is not a proper number, out of range, or some other way wrong. +""" from __future__ import division __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" diff --git a/Cura/util/version.py b/Cura/util/version.py index 2a34ac38..475e0c46 100644 --- a/Cura/util/version.py +++ b/Cura/util/version.py @@ -1,3 +1,7 @@ +""" +The version utility module is used to get the current Cura version, and check for updates. +It can also see if we are running a development build of Cura. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import os diff --git a/Cura/util/youmagine.py b/Cura/util/youmagine.py index 6e77da7b..6e0615c6 100644 --- a/Cura/util/youmagine.py +++ b/Cura/util/youmagine.py @@ -1,3 +1,7 @@ +""" +YouMagine communication module. +This module handles all communication with the YouMagine API. +""" __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" import json -- 2.30.2