the test cases pass now at least
This commit is contained in:
		
							
								
								
									
										1417
									
								
								cadquery/CQ.py
									
									
									
									
									
								
							
							
						
						
									
										1417
									
								
								cadquery/CQ.py
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										8
									
								
								cadquery/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cadquery/README.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | *** | ||||||
|  | Core CadQuery implementation. | ||||||
|  |  | ||||||
|  | No files should depend on or import FreeCAD , pythonOCC, or other CAD Kernel libraries!!! | ||||||
|  | Dependencies should be on the classes provided by implementation packages, which in turn  | ||||||
|  | can depend on CAD libraries. | ||||||
|  |  | ||||||
|  | *** | ||||||
| @ -19,20 +19,20 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| #these items point to the freecad implementation | #these items point to the freecad implementation | ||||||
| from .freecad_impl.geom import Plane,BoundBox,Vector | from .freecad_impl.geom import Plane,BoundBox,Vector,Matrix,sortWiresByBuildOrder | ||||||
| from .freecad_impl.shapes import Shape,Vertex,Edge,Wire,Solid,Shell,Compound | from .freecad_impl.shapes import Shape,Vertex,Edge,Face,Wire,Solid,Shell,Compound | ||||||
| from .freecad_impl.exporters import SvgExporter, AmfExporter, JsonExporter | from .freecad_impl import exporters | ||||||
|  |  | ||||||
| #these items are the common implementation | #these items are the common implementation | ||||||
| from .CQ import CQ |  | ||||||
| from .workplane import Workplane | #the order of these matter | ||||||
| from . import plugins |  | ||||||
| from . import selectors | from . import selectors | ||||||
|  | from .CQ import CQ,CQContext,Workplane | ||||||
|  |  | ||||||
|  |  | ||||||
| __all__ = [ | __all__ = [ | ||||||
| 	'CQ','Workplane','plugins','selectors','Plane','BoundBox', | 	'CQ','Workplane','plugins','selectors','Plane','BoundBox','Matrix','Vector','sortWiresByBuildOrder', | ||||||
| 	'Shape','Vertex','Edge','Wire','Solid','Shell','Compound', | 	'Shape','Vertex','Edge','Wire','Solid','Shell','Compound','exporters', | ||||||
| 	'SvgExporter','AmfExporter','JsonExporter', |  | ||||||
| 	'plugins' | 	'plugins' | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								cadquery/freecad_impl/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								cadquery/freecad_impl/README.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | It is ok for files in this directory to import FreeCAD, FreeCAD.Base, and FreeCAD.Part. | ||||||
|  |  | ||||||
|  | Other modules should _not_ depend on FreeCAD | ||||||
| @ -17,6 +17,9 @@ | |||||||
| 	License along with this library; If not, see <http://www.gnu.org/licenses/> | 	License along with this library; If not, see <http://www.gnu.org/licenses/> | ||||||
| """ | """ | ||||||
|  |  | ||||||
|  | import FreeCAD | ||||||
|  | from FreeCAD import Drawing | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     import xml.etree.cElementTree as ET |     import xml.etree.cElementTree as ET | ||||||
| except ImportError: | except ImportError: | ||||||
| @ -54,15 +57,8 @@ def guessUnitOfMeasure(shape): | |||||||
|  |  | ||||||
|     return UNITS.MM	 |     return UNITS.MM	 | ||||||
|  |  | ||||||
| class Exporter(object): |  | ||||||
|  |  | ||||||
| 	def export(self): |  | ||||||
| 		""" |  | ||||||
| 			return a string representing the model exported in the specified format |  | ||||||
| 		""" |  | ||||||
| 		raise NotImplementedError() |  | ||||||
| 	 | 	 | ||||||
| class AmfExporter(Exporter): | class AmfExporter(object): | ||||||
|     def __init__(self,tessellation): |     def __init__(self,tessellation): | ||||||
|  |  | ||||||
|         self.units = "mm" |         self.units = "mm" | ||||||
| @ -105,7 +101,7 @@ class AmfExporter(Exporter): | |||||||
|     three.js JSON object notation |     three.js JSON object notation | ||||||
|     https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.0 |     https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.0 | ||||||
| """ | """ | ||||||
| class JsonExporter(Exporter): | class JsonExporter(object): | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|  |  | ||||||
|         self.vertices = []; |         self.vertices = []; | ||||||
| @ -135,10 +131,6 @@ class JsonExporter(Exporter): | |||||||
|             'nFaces' : self.nFaces |             'nFaces' : self.nFaces | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| class SvgExporter(Exporter): |  | ||||||
| 	 |  | ||||||
| 	def export(self): |  | ||||||
| 		pass |  | ||||||
|  |  | ||||||
| def getPaths(freeCadSVG): | def getPaths(freeCadSVG): | ||||||
|     """ |     """ | ||||||
| @ -240,11 +232,15 @@ def getSVG(shape,opts=None): | |||||||
|     #) |     #) | ||||||
|     return svg |     return svg | ||||||
|  |  | ||||||
|  |  | ||||||
| def exportSVG(shape, fileName): | def exportSVG(shape, fileName): | ||||||
|     """ |     """ | ||||||
|  | 		accept a cadquery shape, and export it to the provided file | ||||||
|  | 		TODO: should use file-like objects, not a fileName, and/or be able to return a string instead | ||||||
|         export a view of a part to svg |         export a view of a part to svg | ||||||
|     """ |     """ | ||||||
|     svg = getSVG(shape) | 	 | ||||||
|  |     svg = getSVG(shape.val().wrapped) | ||||||
|     f = open(fileName,'w') |     f = open(fileName,'w') | ||||||
|     f.write(svg) |     f.write(svg) | ||||||
|     f.close() |     f.close() | ||||||
|  | |||||||
| @ -1,20 +1,20 @@ | |||||||
| """ | """ | ||||||
| 	Copyright (C) 2011-2013  Parametric Products Intellectual Holdings, LLC |     Copyright (C) 2011-2013  Parametric Products Intellectual Holdings, LLC | ||||||
|  |  | ||||||
| 	This file is part of CadQuery. |     This file is part of CadQuery. | ||||||
| 	 |      | ||||||
| 	CadQuery is free software; you can redistribute it and/or |     CadQuery is free software; you can redistribute it and/or | ||||||
| 	modify it under the terms of the GNU Lesser General Public |     modify it under the terms of the GNU Lesser General Public | ||||||
| 	License as published by the Free Software Foundation; either |     License as published by the Free Software Foundation; either | ||||||
| 	version 2.1 of the License, or (at your option) any later version. |     version 2.1 of the License, or (at your option) any later version. | ||||||
|  |  | ||||||
| 	CadQuery is distributed in the hope that it will be useful, |     CadQuery is distributed in the hope that it will be useful, | ||||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
| 	Lesser General Public License for more details. |     Lesser General Public License for more details. | ||||||
|  |  | ||||||
| 	You should have received a copy of the GNU Lesser General Public |     You should have received a copy of the GNU Lesser General Public | ||||||
| 	License along with this library; If not, see <http://www.gnu.org/licenses/> |     License along with this library; If not, see <http://www.gnu.org/licenses/> | ||||||
| """ | """ | ||||||
|  |  | ||||||
| import math,sys | import math,sys | ||||||
| @ -48,33 +48,6 @@ def sortWiresByBuildOrder(wireList,plane,result=[]): | |||||||
|  |  | ||||||
|     return result |     return result | ||||||
|  |  | ||||||
| def sortWiresByBuildOrderOld(wireList,plane,result=[]): |  | ||||||
|     """ |  | ||||||
|         Tries to determine how wires should be combined into faces. |  | ||||||
|         Assume: |  | ||||||
|             The wires make up one or more faces, which could have 'holes' |  | ||||||
|             Outer wires are listed ahead of inner wires |  | ||||||
|             there are no wires inside wires inside wires ( IE, islands -- we can deal with that later on ) |  | ||||||
|             none of the wires are construction wires |  | ||||||
|         Compute: |  | ||||||
|             one or more sets of wires, with the outer wire listed first, and inner ones |  | ||||||
|         Returns, list of lists. |  | ||||||
|     """ |  | ||||||
|     outerWire = wireList.pop(0) |  | ||||||
|  |  | ||||||
|     remainingWires = list(wireList) |  | ||||||
|     childWires = [] |  | ||||||
|     for w in wireList: |  | ||||||
|         if plane.isWireInside(outerWire,w): |  | ||||||
|             childWires.append(remainingWires.pop(0)) |  | ||||||
|         else: |  | ||||||
|             #doesnt match, assume this wire is a new outer |  | ||||||
|             result.append([outerWire] + childWires) |  | ||||||
|             return sortWiresByBuildOrder(remainingWires,plane,result) |  | ||||||
|  |  | ||||||
|     result.append([outerWire] + childWires) |  | ||||||
|     return result |  | ||||||
|  |  | ||||||
| class Vector(object): | class Vector(object): | ||||||
|     """ |     """ | ||||||
|         Create a 3-dimensional vector |         Create a 3-dimensional vector | ||||||
| @ -212,6 +185,25 @@ class Vector(object): | |||||||
|     def __eq__(self,other): |     def __eq__(self,other): | ||||||
|         return self.wrapped.__eq__(other) |         return self.wrapped.__eq__(other) | ||||||
|  |  | ||||||
|  | class Matrix: | ||||||
|  |     """ | ||||||
|  |         A 3d , 4x4 transformation matrix.         | ||||||
|  |          | ||||||
|  |         Used to move geometry in space. | ||||||
|  |     """ | ||||||
|  |     def __init__(self,matrix=None): | ||||||
|  |         if matrix == None: | ||||||
|  |             self.wrapped = FreeCAD.Base.Matrix() | ||||||
|  |         else: | ||||||
|  |             self.wrapped = matrix | ||||||
|  |              | ||||||
|  |     def rotateX(self,angle): | ||||||
|  |         self.wrapped.rotateX(angle) | ||||||
|  |          | ||||||
|  |     def rotateY(self,angle): | ||||||
|  |         self.wrapped.rotateY(angle) | ||||||
|  |      | ||||||
|  |      | ||||||
| class Plane: | class Plane: | ||||||
|     """ |     """ | ||||||
|         A 2d coordinate system in space, with the x-y axes on the a plane, and a particular point as the origin. |         A 2d coordinate system in space, with the x-y axes on the a plane, and a particular point as the origin. | ||||||
| @ -329,6 +321,7 @@ class Plane: | |||||||
|  |  | ||||||
|         self.setOrigin3d(origin) |         self.setOrigin3d(origin) | ||||||
|  |  | ||||||
|  |          | ||||||
|     def setOrigin3d(self,originVector): |     def setOrigin3d(self,originVector): | ||||||
|         """ |         """ | ||||||
|             Move the origin of the plane, leaving its orientation and xDirection unchanged. |             Move the origin of the plane, leaving its orientation and xDirection unchanged. | ||||||
| @ -417,6 +410,7 @@ class Plane: | |||||||
|         else: |         else: | ||||||
|             raise ValueError("Dont know how to convert type %s to local coordinates" % str(type(obj))) |             raise ValueError("Dont know how to convert type %s to local coordinates" % str(type(obj))) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def toWorldCoords(self, tuplePoint): |     def toWorldCoords(self, tuplePoint): | ||||||
|         """ |         """ | ||||||
|             Convert a point in local coordinates to global coordinates. |             Convert a point in local coordinates to global coordinates. | ||||||
| @ -433,6 +427,7 @@ class Plane: | |||||||
|             v = Vector(tuplePoint[0],tuplePoint[1],tuplePoint[2]) |             v = Vector(tuplePoint[0],tuplePoint[1],tuplePoint[2]) | ||||||
|         return Vector(self.rG.multiply(v.wrapped)) |         return Vector(self.rG.multiply(v.wrapped)) | ||||||
|  |  | ||||||
|  |          | ||||||
|     def rotated(self,rotate=Vector(0,0,0)): |     def rotated(self,rotate=Vector(0,0,0)): | ||||||
|         """ |         """ | ||||||
|         returns a copy of this plane, rotated about the specified axes, as measured from horizontal |         returns a copy of this plane, rotated about the specified axes, as measured from horizontal | ||||||
| @ -453,7 +448,7 @@ class Plane: | |||||||
|         rotate = rotate.multiply(math.pi / 180.0 ) |         rotate = rotate.multiply(math.pi / 180.0 ) | ||||||
|  |  | ||||||
|         #compute rotation matrix |         #compute rotation matrix | ||||||
|         m = Base.Matrix() |         m = FreeCAD.Base.Matrix() | ||||||
|         m.rotateX(rotate.x) |         m.rotateX(rotate.x) | ||||||
|         m.rotateY(rotate.y) |         m.rotateY(rotate.y) | ||||||
|         m.rotateZ(rotate.z) |         m.rotateZ(rotate.z) | ||||||
| @ -473,7 +468,7 @@ class Plane: | |||||||
|         #ok i will be really honest-- i cannot understand exactly why this works |         #ok i will be really honest-- i cannot understand exactly why this works | ||||||
|         #something bout the order of the transaltion and the rotation. |         #something bout the order of the transaltion and the rotation. | ||||||
|         # the double-inverting is strange, and i dont understand it. |         # the double-inverting is strange, and i dont understand it. | ||||||
|         r = Base.Matrix() |         r = FreeCAD.Base.Matrix() | ||||||
|  |  | ||||||
|         #forward transform must rotate and adjust for origin |         #forward transform must rotate and adjust for origin | ||||||
|         (r.A11, r.A12, r.A13 ) = (self.xDir.x, self.xDir.y, self.xDir.z ) |         (r.A11, r.A12, r.A13 ) = (self.xDir.x, self.xDir.y, self.xDir.z ) | ||||||
| @ -484,7 +479,14 @@ class Plane: | |||||||
|         (invR.A14,invR.A24,invR.A34) = (self.origin.x,self.origin.y,self.origin.z) |         (invR.A14,invR.A24,invR.A34) = (self.origin.x,self.origin.y,self.origin.z) | ||||||
|  |  | ||||||
|         ( self.rG,self.fG ) = ( invR,invR.inverse() ) |         ( self.rG,self.fG ) = ( invR,invR.inverse() ) | ||||||
|  |          | ||||||
|  |     def computeTransform(self,tMatrix): | ||||||
|  |         """ | ||||||
|  |             Computes the 2-d projection of the supplied matrix | ||||||
|  |         """ | ||||||
|  | 		 | ||||||
|  |         rm = self.fG.multiply(tMatrix.wrapped).multiply(self.rG) | ||||||
|  |         return Matrix(rm) | ||||||
|  |  | ||||||
| class BoundBox(object): | class BoundBox(object): | ||||||
|     "A BoundingBox for an object or set of objects. Wraps the FreeCAD one" |     "A BoundingBox for an object or set of objects. Wraps the FreeCAD one" | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ | |||||||
|            object each one returns, so these are better grouped by the type of object they return.  |            object each one returns, so these are better grouped by the type of object they return.  | ||||||
|            (who would know that Part.makeCircle() returns an Edge, but Part.makePolygon() returns a Wire ? |            (who would know that Part.makeCircle() returns an Edge, but Part.makePolygon() returns a Wire ? | ||||||
| """ | """ | ||||||
| from cadquery import Vector | from cadquery import Vector,BoundBox | ||||||
| import FreeCAD | import FreeCAD | ||||||
| import FreeCAD.Part | import FreeCAD.Part | ||||||
|  |  | ||||||
| @ -65,7 +65,7 @@ class Shape(object): | |||||||
|     def cast(cls,obj,forConstruction = False): |     def cast(cls,obj,forConstruction = False): | ||||||
|         "Returns the right type of wrapper, given a FreeCAD object" |         "Returns the right type of wrapper, given a FreeCAD object" | ||||||
|         s = obj.ShapeType |         s = obj.ShapeType | ||||||
|         if type(obj) == Base.Vector: |         if type(obj) == FreeCAD.Base.Vector: | ||||||
|             return Vector(obj) |             return Vector(obj) | ||||||
|         tr = None |         tr = None | ||||||
|  |  | ||||||
| @ -99,7 +99,9 @@ class Shape(object): | |||||||
|  |  | ||||||
|         tr.forConstruction = forConstruction |         tr.forConstruction = forConstruction | ||||||
|         return tr |         return tr | ||||||
|  | 	#TODO: all these should move into the exporters folder. | ||||||
|  | 	#we dont need a bunch of exporting code stored in here! | ||||||
|  | 	# | ||||||
|     def exportStl(self,fileName): |     def exportStl(self,fileName): | ||||||
|         self.wrapped.exportStl(fileName) |         self.wrapped.exportStl(fileName) | ||||||
|  |  | ||||||
| @ -254,6 +256,7 @@ class Shape(object): | |||||||
|  |  | ||||||
|     def transformShape(self,tMatrix): |     def transformShape(self,tMatrix): | ||||||
|         """ |         """ | ||||||
|  | 			tMatrix is a matrix object. | ||||||
|             returns a copy of the ojbect, transformed by the provided matrix, |             returns a copy of the ojbect, transformed by the provided matrix, | ||||||
|             with all objects keeping their type |             with all objects keeping their type | ||||||
|         """ |         """ | ||||||
| @ -265,6 +268,8 @@ class Shape(object): | |||||||
|  |  | ||||||
|     def transformGeometry(self,tMatrix): |     def transformGeometry(self,tMatrix): | ||||||
|         """ |         """ | ||||||
|  | 			tMatrix is a matrix object. | ||||||
|  | 			 | ||||||
|             returns a copy of the object, but with geometry transformed insetad of just |             returns a copy of the object, but with geometry transformed insetad of just | ||||||
|             rotated. |             rotated. | ||||||
|  |  | ||||||
| @ -311,9 +316,9 @@ class Edge(Shape): | |||||||
|         #self.endPoint = None |         #self.endPoint = None | ||||||
|  |  | ||||||
|         self.edgetypes= { |         self.edgetypes= { | ||||||
|             Part.Line : 'LINE', |             FreeCAD.Part.Line : 'LINE', | ||||||
|             Part.ArcOfCircle : 'ARC', |             FreeCAD.Part.ArcOfCircle : 'ARC', | ||||||
|             Part.Circle : 'CIRCLE' |             FreeCAD.Part.Circle : 'CIRCLE' | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     def geomType(self): |     def geomType(self): | ||||||
| @ -363,7 +368,7 @@ class Edge(Shape): | |||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeCircle(cls,radius,pnt=(0,0,0),dir=(0,0,1),angle1=360.0,angle2=360): |     def makeCircle(cls,radius,pnt=(0,0,0),dir=(0,0,1),angle1=360.0,angle2=360): | ||||||
|         return Edge(Part.makeCircle(radius,toVector(pnt),toVector(dir),angle1,angle2)) |         return Edge(FreeCAD.Part.makeCircle(radius,toVector(pnt),toVector(dir),angle1,angle2)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeSpline(cls,listOfVector): |     def makeSpline(cls,listOfVector): | ||||||
| @ -375,7 +380,7 @@ class Edge(Shape): | |||||||
|         """ |         """ | ||||||
|         vecs = [v.wrapped for v in listOfVector] |         vecs = [v.wrapped for v in listOfVector] | ||||||
|  |  | ||||||
|         spline = Part.BSplineCurve() |         spline = FreeCAD.Part.BSplineCurve() | ||||||
|         spline.interpolate(vecs,False) |         spline.interpolate(vecs,False) | ||||||
|         return Edge(spline.toShape()) |         return Edge(spline.toShape()) | ||||||
|  |  | ||||||
| @ -389,7 +394,7 @@ class Edge(Shape): | |||||||
|         :param v3: end vector |         :param v3: end vector | ||||||
|         :return: an edge object through the three points |         :return: an edge object through the three points | ||||||
|         """ |         """ | ||||||
|         arc = Part.Arc(v1.wrapped,v2.wrapped,v3.wrapped) |         arc = FreeCAD.Part.Arc(v1.wrapped,v2.wrapped,v3.wrapped) | ||||||
|         e = Edge(arc.toShape()) |         e = Edge(arc.toShape()) | ||||||
|         return e #arcane and undocumented, this creates an Edge object |         return e #arcane and undocumented, this creates an Edge object | ||||||
|  |  | ||||||
| @ -401,7 +406,7 @@ class Edge(Shape): | |||||||
|             :param v2: Vector that represents the second point |             :param v2: Vector that represents the second point | ||||||
|             :return: A linear edge between the two provided points |             :return: A linear edge between the two provided points | ||||||
|         """ |         """ | ||||||
|         return Edge(Part.makeLine(v1.toTuple(),v2.toTuple() )) |         return Edge(FreeCAD.Part.makeLine(v1.toTuple(),v2.toTuple() )) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Wire(Shape): | class Wire(Shape): | ||||||
| @ -420,7 +425,7 @@ class Wire(Shape): | |||||||
|         :param listOfWires: |         :param listOfWires: | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.Wire([w.wrapped for w in listOfWires])) |         return Shape.cast(FreeCAD.Part.Wire([w.wrapped for w in listOfWires])) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def assembleEdges(cls,listOfEdges): |     def assembleEdges(cls,listOfEdges): | ||||||
| @ -432,7 +437,7 @@ class Wire(Shape): | |||||||
|         """ |         """ | ||||||
|         fCEdges = [a.wrapped for a in listOfEdges] |         fCEdges = [a.wrapped for a in listOfEdges] | ||||||
|  |  | ||||||
|         wa = Wire( Part.Wire(fCEdges) ) |         wa = Wire( FreeCAD.Part.Wire(fCEdges) ) | ||||||
|         return wa |         return wa | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
| @ -444,13 +449,13 @@ class Wire(Shape): | |||||||
|             :param normal: vector representing the direction of the plane the circle should lie in |             :param normal: vector representing the direction of the plane the circle should lie in | ||||||
|             :return: |             :return: | ||||||
|         """ |         """ | ||||||
|         w = Wire(Part.Wire([Part.makeCircle(radius,center.wrapped,normal.wrapped)])) |         w = Wire(FreeCAD.Part.Wire([FreeCAD.Part.makeCircle(radius,center.wrapped,normal.wrapped)])) | ||||||
|         return w |         return w | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makePolygon(cls,listOfVertices,forConstruction=False): |     def makePolygon(cls,listOfVertices,forConstruction=False): | ||||||
|         #convert list of tuples into Vectors. |         #convert list of tuples into Vectors. | ||||||
|         w = Wire(Part.makePolygon([i.wrapped for i in listOfVertices])) |         w = Wire(FreeCAD.Part.makePolygon([i.wrapped for i in listOfVertices])) | ||||||
|         w.forConstruction = forConstruction |         w.forConstruction = forConstruction | ||||||
|         return w |         return w | ||||||
|  |  | ||||||
| @ -461,7 +466,7 @@ class Wire(Shape): | |||||||
|         By default a cylindrical surface is used to create the helix. If |         By default a cylindrical surface is used to create the helix. If | ||||||
|         the fourth parameter is set (the apex given in degree) a conical surface is used instead' |         the fourth parameter is set (the apex given in degree) a conical surface is used instead' | ||||||
|         """ |         """ | ||||||
|         return Wire(Part.makeHelix(pitch,height,radius,angle)) |         return Wire(FreeCAD.Part.makeHelix(pitch,height,radius,angle)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Face(Shape): | class Face(Shape): | ||||||
| @ -473,9 +478,9 @@ class Face(Shape): | |||||||
|  |  | ||||||
|         self.facetypes = { |         self.facetypes = { | ||||||
|             #TODO: bezier,bspline etc |             #TODO: bezier,bspline etc | ||||||
|             Part.Plane : 'PLANE', |             FreeCAD.Part.Plane : 'PLANE', | ||||||
|             Part.Sphere : 'SPHERE', |             FreeCAD.Part.Sphere : 'SPHERE', | ||||||
|             Part.Cone : 'CONE' |             FreeCAD.Part.Cone : 'CONE' | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     def geomType(self): |     def geomType(self): | ||||||
| @ -501,7 +506,7 @@ class Face(Shape): | |||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makePlane(cls,length,width,basePnt=None,dir=None): |     def makePlane(cls,length,width,basePnt=None,dir=None): | ||||||
|         return Face(Part.makePlan(length,width,toVector(basePnt),toVector(dir))) |         return Face(FreeCAD.Part.makePlan(length,width,toVector(basePnt),toVector(dir))) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeRuledSurface(cls,edgeOrWire1,edgeOrWire2,dist=None): |     def makeRuledSurface(cls,edgeOrWire1,edgeOrWire2,dist=None): | ||||||
| @ -510,7 +515,7 @@ class Face(Shape): | |||||||
|         Create a ruled surface out of two edges or wires. If wires are used then |         Create a ruled surface out of two edges or wires. If wires are used then | ||||||
|         these must have the same |         these must have the same | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeRuledSurface(edgeOrWire1.obj,edgeOrWire2.obj,dist)) |         return Shape.cast(FreeCAD.Part.makeRuledSurface(edgeOrWire1.obj,edgeOrWire2.obj,dist)) | ||||||
|  |  | ||||||
|     def cut(self,faceToCut): |     def cut(self,faceToCut): | ||||||
|         "Remove a face from another one" |         "Remove a face from another one" | ||||||
| @ -536,7 +541,7 @@ class Shell(Shape): | |||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeShell(cls,listOfFaces): |     def makeShell(cls,listOfFaces): | ||||||
|         return Shell(Part.makeShell([i.obj for i in listOfFaces])) |         return Shell(FreeCAD.Part.makeShell([i.obj for i in listOfFaces])) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Solid(Shape): | class Solid(Shape): | ||||||
| @ -563,7 +568,7 @@ class Solid(Shape): | |||||||
|             makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d |             makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d | ||||||
|             imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)' |             imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)' | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeBox(length,width,height,pnt.wrapped,dir.wrapped)) |         return Shape.cast(FreeCAD.Part.makeBox(length,width,height,pnt.wrapped,dir.wrapped)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeCone(cls,radius1,radius2,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360): |     def makeCone(cls,radius1,radius2,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360): | ||||||
| @ -572,7 +577,7 @@ class Solid(Shape): | |||||||
|             Make a cone with given radii and height\nBy default pnt=Vector(0,0,0), |             Make a cone with given radii and height\nBy default pnt=Vector(0,0,0), | ||||||
|             dir=Vector(0,0,1) and angle=360' |             dir=Vector(0,0,1) and angle=360' | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeCone(radius1,radius2,height,pnt.wrapped,dir.wrapped,angleDegrees)) |         return Shape.cast(FreeCAD.Part.makeCone(radius1,radius2,height,pnt.wrapped,dir.wrapped,angleDegrees)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeCylinder(cls,radius,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360): |     def makeCylinder(cls,radius,height,pnt=Vector(0,0,0),dir=Vector(0,0,1),angleDegrees=360): | ||||||
| @ -581,7 +586,7 @@ class Solid(Shape): | |||||||
|             Make a cylinder with a given radius and height |             Make a cylinder with a given radius and height | ||||||
|             By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360' |             By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360' | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeCylinder(radius,height,pnt.wrapped,dir.wrapped,angleDegrees)) |         return Shape.cast(FreeCAD.Part.makeCylinder(radius,height,pnt.wrapped,dir.wrapped,angleDegrees)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeTorus(cls,radius1,radius2,pnt=None,dir=None,angleDegrees1=None,angleDegrees2=None): |     def makeTorus(cls,radius1,radius2,pnt=None,dir=None,angleDegrees1=None,angleDegrees2=None): | ||||||
| @ -591,7 +596,7 @@ class Solid(Shape): | |||||||
|             By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0 |             By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0 | ||||||
|             ,angle1=360 and angle=360' |             ,angle1=360 and angle=360' | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeTorus(radius1,radius2,pnt,dir,angleDegrees1,angleDegrees2)) |         return Shape.cast(FreeCAD.Part.makeTorus(radius1,radius2,pnt,dir,angleDegrees1,angleDegrees2)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def sweep(cls,profileWire,pathWire): |     def sweep(cls,profileWire,pathWire): | ||||||
| @ -610,11 +615,11 @@ class Solid(Shape): | |||||||
|         """ |         """ | ||||||
|             makes a loft from a list of wires |             makes a loft from a list of wires | ||||||
|             The wires will be converted into faces when possible-- it is presumed that nobody ever actually |             The wires will be converted into faces when possible-- it is presumed that nobody ever actually | ||||||
|             wants to make an infinitely thin shell for a real part. |             wants to make an infinitely thin shell for a real FreeCAD.Part. | ||||||
|         """ |         """ | ||||||
|         #the True flag requests building a solid instead of a shell. |         #the True flag requests building a solid instead of a shell. | ||||||
|  |  | ||||||
|         return Shape.cast(Part.makeLoft([i.wrapped for i in listOfWire],True)) |         return Shape.cast(FreeCAD.Part.makeLoft([i.wrapped for i in listOfWire],True)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeWedge(cls,xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt=None,dir=None): |     def makeWedge(cls,xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt=None,dir=None): | ||||||
| @ -624,7 +629,7 @@ class Solid(Shape): | |||||||
|          Make a wedge located in pnt\nBy default pnt=Vector(0,0,0) and dir=Vec |          Make a wedge located in pnt\nBy default pnt=Vector(0,0,0) and dir=Vec | ||||||
|         tor(0,0,1)' |         tor(0,0,1)' | ||||||
|         """ |         """ | ||||||
|         return Shape.cast(Part.makeWedge(xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt,dir)) |         return Shape.cast(FreeCAD.Part.makeWedge(xmin,ymin,zmin,z2min,x2min,xmax,ymax,zmax,z2max,x2max,pnt,dir)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def makeSphere(cls,radius,pnt=None,angleDegrees1=None,angleDegrees2=None,angleDegrees3=None): |     def makeSphere(cls,radius,pnt=None,angleDegrees1=None,angleDegrees2=None,angleDegrees3=None): | ||||||
| @ -633,7 +638,7 @@ class Solid(Shape): | |||||||
|             Make a sphere with a giv |             Make a sphere with a giv | ||||||
|             en radius\nBy default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360' |             en radius\nBy default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360' | ||||||
|         """ |         """ | ||||||
|         return Solid(Part.makeSphere(radius,pnt,angleDegrees1,angleDegrees2,angleDegrees3)) |         return Solid(FreeCAD.Part.makeSphere(radius,pnt,angleDegrees1,angleDegrees2,angleDegrees3)) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def extrudeLinearWithRotation(cls,outerWire,innerWires,vecCenter, vecNormal,angleDegrees): |     def extrudeLinearWithRotation(cls,outerWire,innerWires,vecCenter, vecNormal,angleDegrees): | ||||||
| @ -674,12 +679,12 @@ class Solid(Shape): | |||||||
|         #make a ruled surface for each set of wires |         #make a ruled surface for each set of wires | ||||||
|         sides = [] |         sides = [] | ||||||
|         for w1,w2 in zip(startWires,endWires): |         for w1,w2 in zip(startWires,endWires): | ||||||
|             rs = Part.makeRuledSurface(w1,w2) |             rs = FreeCAD.Part.makeRuledSurface(w1,w2) | ||||||
|             sides.append(rs) |             sides.append(rs) | ||||||
|  |  | ||||||
|         #make faces for the top and bottom |         #make faces for the top and bottom | ||||||
|         startFace = Part.Face(startWires) |         startFace = FreeCAD.Part.Face(startWires) | ||||||
|         endFace = Part.Face(endWires) |         endFace = FreeCAD.Part.Face(endWires) | ||||||
|  |  | ||||||
|         #collect all the faces from the sides |         #collect all the faces from the sides | ||||||
|         faceList = [ startFace] |         faceList = [ startFace] | ||||||
| @ -687,8 +692,8 @@ class Solid(Shape): | |||||||
|             faceList.extend(s.Faces) |             faceList.extend(s.Faces) | ||||||
|         faceList.append(endFace) |         faceList.append(endFace) | ||||||
|  |  | ||||||
|         shell = Part.makeShell(faceList) |         shell = FreeCAD.Part.makeShell(faceList) | ||||||
|         solid = Part.makeSolid(shell) |         solid = FreeCAD.Part.makeSolid(shell) | ||||||
|         return Shape.cast(solid) |         return Shape.cast(solid) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
| @ -725,7 +730,7 @@ class Solid(Shape): | |||||||
|         for w in innerWires: |         for w in innerWires: | ||||||
|             freeCADWires.append(w.wrapped) |             freeCADWires.append(w.wrapped) | ||||||
|  |  | ||||||
|         f = Part.Face(freeCADWires) |         f = FreeCAD.Part.Face(freeCADWires) | ||||||
|         result = f.extrude(vecNormal.wrapped) |         result = f.extrude(vecNormal.wrapped) | ||||||
|  |  | ||||||
|         return Shape.cast(result) |         return Shape.cast(result) | ||||||
| @ -789,7 +794,7 @@ class Compound(Shape): | |||||||
|         Create a compound out of a list of shapes |         Create a compound out of a list of shapes | ||||||
|         """ |         """ | ||||||
|         solids = [s.wrapped for s in listOfShapes] |         solids = [s.wrapped for s in listOfShapes] | ||||||
|         c = Part.Compound(solids) |         c = FreeCAD.Part.Compound(solids) | ||||||
|         return Shape.cast( c) |         return Shape.cast( c) | ||||||
|  |  | ||||||
|     def fuse(self,toJoin): |     def fuse(self,toJoin): | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ | |||||||
|  |  | ||||||
| import re | import re | ||||||
| import math | import math | ||||||
|  | from cadquery import Vector,Edge,Vertex,Face,Solid,Shell,Compound | ||||||
|  |  | ||||||
| class Selector(object): | class Selector(object): | ||||||
|     """ |     """ | ||||||
|  | |||||||
| @ -18,8 +18,8 @@ | |||||||
| """ | """ | ||||||
|  |  | ||||||
| import math | import math | ||||||
| from . import CQ |  | ||||||
| from cadquery import Vector | from cadquery import Vector,CQ,CQContext,Plane,Wire | ||||||
|  |  | ||||||
| class Workplane(CQ): | class Workplane(CQ): | ||||||
|     """ |     """ | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								runtests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								runtests.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import sys | ||||||
|  | from tests import * | ||||||
|  | import cadquery | ||||||
|  | import unittest | ||||||
|  |  | ||||||
|  | #if you are on python 2.7, you can use -m uniitest discover. | ||||||
|  | #but this is required for python 2.6.6 on windows. FreeCAD0.12 will not load | ||||||
|  | #on py 2.7.x on win | ||||||
|  | suite = unittest.TestSuite() | ||||||
|  |  | ||||||
|  | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadObjects.TestCadObjects)) | ||||||
|  | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWorkplanes.TestWorkplanes)) | ||||||
|  | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQSelectors.TestCQSelectors)) | ||||||
|  | suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery)) | ||||||
|  |  | ||||||
|  | unittest.TextTestRunner().run(suite) | ||||||
							
								
								
									
										1
									
								
								tests/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/README.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | It is OK for tests to import implementations like FreeCAD directly. | ||||||
| @ -13,8 +13,9 @@ import unittest,sys | |||||||
| import os.path | import os.path | ||||||
|  |  | ||||||
| #my modules | #my modules | ||||||
| from TestBase import * | from tests import BaseTest,makeUnitCube,makeUnitSquareWire | ||||||
| from cadquery import * | from cadquery import * | ||||||
|  | from cadquery import selectors | ||||||
|  |  | ||||||
| class TestCQSelectors(BaseTest): | class TestCQSelectors(BaseTest): | ||||||
|  |  | ||||||
| @ -122,8 +123,8 @@ class TestCQSelectors(BaseTest): | |||||||
|         #faces parallel to Z axis |         #faces parallel to Z axis | ||||||
|         self.assertEqual(2, c.faces("|Z").size()) |         self.assertEqual(2, c.faces("|Z").size()) | ||||||
|         #TODO: provide short names for ParallelDirSelector |         #TODO: provide short names for ParallelDirSelector | ||||||
|         self.assertEqual(2, c.faces(ParallelDirSelector(Vector((0,0,1)))).size()) #same thing as above |         self.assertEqual(2, c.faces(selectors.ParallelDirSelector(Vector((0,0,1)))).size()) #same thing as above | ||||||
|         self.assertEqual(2, c.faces(ParallelDirSelector(Vector((0,0,-1)))).size()) #same thing as above |         self.assertEqual(2, c.faces(selectors.ParallelDirSelector(Vector((0,0,-1)))).size()) #same thing as above | ||||||
|  |  | ||||||
|         #just for fun, vertices on faces parallel to z |         #just for fun, vertices on faces parallel to z | ||||||
|         self.assertEqual(8, c.faces("|Z").vertices().size()) |         self.assertEqual(8, c.faces("|Z").vertices().size()) | ||||||
| @ -164,17 +165,17 @@ class TestCQSelectors(BaseTest): | |||||||
|         #nearest vertex to origin is (0,0,0) |         #nearest vertex to origin is (0,0,0) | ||||||
|         t = Vector(0.1,0.1,0.1) |         t = Vector(0.1,0.1,0.1) | ||||||
|  |  | ||||||
|         v = c.vertices(NearestToPointSelector(t)).vals()[0] |         v = c.vertices(selectors.NearestToPointSelector(t)).vals()[0] | ||||||
|         self.assertTupleAlmostEquals((0.0,0.0,0.0),(v.X,v.Y,v.Z),3) |         self.assertTupleAlmostEquals((0.0,0.0,0.0),(v.X,v.Y,v.Z),3) | ||||||
|  |  | ||||||
|         t = Vector(0.1,0.1,0.2) |         t = Vector(0.1,0.1,0.2) | ||||||
|         #nearest edge is the vertical side edge, 0,0,0 -> 0,0,1 |         #nearest edge is the vertical side edge, 0,0,0 -> 0,0,1 | ||||||
|         e = c.edges(NearestToPointSelector(t)).vals()[0] |         e = c.edges(selectors.NearestToPointSelector(t)).vals()[0] | ||||||
|         v = c.edges(NearestToPointSelector(t)).vertices().vals() |         v = c.edges(selectors.NearestToPointSelector(t)).vertices().vals() | ||||||
|         self.assertEqual(2,len(v)) |         self.assertEqual(2,len(v)) | ||||||
|  |  | ||||||
|         #nearest solid is myself |         #nearest solid is myself | ||||||
|         s = c.solids(NearestToPointSelector(t)).vals() |         s = c.solids(selectors.NearestToPointSelector(t)).vals() | ||||||
|         self.assertEqual(1,len(s)) |         self.assertEqual(1,len(s)) | ||||||
|  |  | ||||||
|     def testFaceCount(self): |     def testFaceCount(self): | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| #system modules | #system modules | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| #my modules | import unittest | ||||||
|  | from tests import BaseTest | ||||||
| import from cadquery import * | import FreeCAD | ||||||
|  | from cadquery import * | ||||||
|  | 	 | ||||||
| class TestCadObjects(BaseTest): | class TestCadObjects(BaseTest): | ||||||
|  |  | ||||||
|     def testVectorConstructors(self): |     def testVectorConstructors(self): | ||||||
| @ -56,4 +56,7 @@ class TestCadObjects(BaseTest): | |||||||
|  |  | ||||||
|     def testVertices(self): |     def testVertices(self): | ||||||
|         e = Shape.cast(FreeCAD.Part.makeLine((0,0,0),(1,1,0))) |         e = Shape.cast(FreeCAD.Part.makeLine((0,0,0),(1,1,0))) | ||||||
|         self.assertEquals(2,len(e.Vertices())) |         self.assertEquals(2,len(e.Vertices())) | ||||||
|  | 		 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     unittest.main()		 | ||||||
| @ -7,6 +7,8 @@ import math,sys,os.path,time | |||||||
|  |  | ||||||
| #my modules | #my modules | ||||||
| from cadquery import * | from cadquery import * | ||||||
|  | from cadquery import exporters | ||||||
|  | from tests import BaseTest,writeStringToFile,makeUnitCube,readFileAsString,makeUnitSquareWire,makeCube | ||||||
|  |  | ||||||
| #where unit test output will be saved | #where unit test output will be saved | ||||||
| OUTDIR = "c:/temp" | OUTDIR = "c:/temp" | ||||||
| @ -739,16 +741,6 @@ class TestCadQuery(BaseTest): | |||||||
|         self.saveModel(s3) |         self.saveModel(s3) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def testTwistedGear3(self): |  | ||||||
|         pts = plugins.make_gear(14.5,10,2.5) #make involutes |  | ||||||
|         s = Workplane("XY").polyline(pts).twistExtrude(4.0,8.0) |  | ||||||
|         #s2 = s.faces(">Z").workplane().transformed(rotate=Vector(0,0,8)).polyline(pts).twistExtrude(4.0,-8.0,combine=False) |  | ||||||
|         #s3 = s.union(s2) |  | ||||||
|         #s.val().exportStl("c:\\temp\\pleasework3.stl") |  | ||||||
|         #s3.val().exportStl("c:\\temp\\pleasework5.stl") |  | ||||||
|         self.saveModel(s) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     def testEnclosure(self): |     def testEnclosure(self): | ||||||
|         """ |         """ | ||||||
|             Builds an electronics enclosure |             Builds an electronics enclosure | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ __author__ = 'dcowden' | |||||||
| from cadquery import * | from cadquery import * | ||||||
|  |  | ||||||
| import unittest,sys | import unittest,sys | ||||||
| import MakeTestObjects | from tests import MakeTestObjects | ||||||
| import SVGexporter | import SVGexporter | ||||||
|  |  | ||||||
| class TestCadQuery(unittest.TestCase): | class TestCadQuery(unittest.TestCase): | ||||||
|  | |||||||
| @ -5,9 +5,9 @@ | |||||||
|  |  | ||||||
| #my modules | #my modules | ||||||
| from cadquery import * | from cadquery import * | ||||||
|  | from tests import BaseTest,toTuple | ||||||
|  |  | ||||||
| class TestPlane(BaseTest): | class TestWorkplanes(BaseTest): | ||||||
|  |  | ||||||
|  |  | ||||||
|     def testYZPlaneOrigins(self): |     def testYZPlaneOrigins(self): | ||||||
|         #xy plane-- with origin at x=0.25 |         #xy plane-- with origin at x=0.25 | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ def makeCube(size): | |||||||
| def toTuple(v): | def toTuple(v): | ||||||
|     "convert a vector or a vertex to a 3-tuple: x,y,z" |     "convert a vector or a vertex to a 3-tuple: x,y,z" | ||||||
|     pnt = v |     pnt = v | ||||||
|     if type(v) == Base.Vector: |     if type(v) == FreeCAD.Base.Vector: | ||||||
|         return (v.Point.x,v.Point.y,v.Point.z) |         return (v.Point.x,v.Point.y,v.Point.z) | ||||||
|     elif type(v) == Vector: |     elif type(v) == Vector: | ||||||
|         return v.toTuple() |         return v.toTuple() | ||||||
| @ -45,3 +45,5 @@ class BaseTest(unittest.TestCase): | |||||||
|     def assertTupleAlmostEquals(self,expected,actual,places): |     def assertTupleAlmostEquals(self,expected,actual,places): | ||||||
|         for i,j in zip(actual,expected): |         for i,j in zip(actual,expected): | ||||||
|             self.assertAlmostEquals(i,j,places) |             self.assertAlmostEquals(i,j,places) | ||||||
|  |  | ||||||
|  | __all__ = [ 'TestCadObjects','TestCadQuery','TestCQSelectors','TestWorkplanes'] | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user