## dxf2nc is free software; you can redistribute it and/or modify## it under the terms of the GNU General Public License as published by the## Free Software Foundation; either version 2 of the License, or (at your## option) any later version. stl-to-dxf is distributed in the hope that it## will be useful, but WITHOUT ANY WARRANTY; without even the implied## warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See## the GNU General Public License for more details. You should have## received a copy of the GNU General Public License along with stl-to-dxf; if## not, write to the Free Software Foundation, Inc., 59 Temple Place,## Suite 330, Boston, MA 02111-1307 USA## ## dxf2nc is Copyright (C) 2006 Jarl Stefansson## jarl@dallur.comfrom math import sqrt################################################################## Make it so that all Operators are compatible with all numeric types# Make it so that all Operators are compatible with all objects# Make generic functions in Primitive which will work with other objects# Make it so that you can create all objects by passing things in lists# Filter which objects types are allowed to be passed to operators# Use lambda to enable creation of groups passing multiple#################################################################class CartesianZero(object): """ A singleton representing 0,0,0 in a cartesian coordinate system""" class __impl: """ The singleton interface """ pass __instance = None def __init__(self): """ Create singleton instance """ self.x = 0.0 self.y = 0.0 self.z = 0.0 # Check whether we already have an instance if CartesianZero.__instance is None: # Create and remember instance CartesianZero.__instance = CartesianZero.__impl() # Store instance reference as the only member in the handle self.__dict__['_CartesianZero__instance'] = CartesianZero.__instance # Any point of cartesian zero is equal to cartesian zero def getPoint(self, which = None, other = None): return selfclass Primitive(object): """Generic Geometric Object Class""" def __init__(self): self.closed = None self.color = None # A generic distance method to get the distance between any two points def distance(self, other = CartesianZero()): return self.calculate_distance(other) # An error thrown when a getPoint method is passed an object it is unable to handle def getPointTypeError(self): raise TypeError , ' getPoint() arguments must be "first"/"start"/"0"/(0)/[0] or "last"/"end"/"-1"/(-1)/[-1] or "center"/"middle" or "closest"/"nearest"/"near" and point object, defaults are "first" and "0,0,0"' sys.exit(1) def inputParser(self, returnObjectType ,*other ): for parameter in other: newinstance = parameter while not isinstance(newinstance, returnObjectType): break #newinstance = newinstance[1] return# other = tuple# other = list# other = dict# other = float# other = long# other = int# other = Primitive# other = Point# other = # else:# raise TypeError , str(type(self)) + ' arguments must be numerical, list, dict, tuple or geometric Object'# if isinstance(other, Point):# return sqrt((self.x - other.x)**2 + (self.y - other.y)**2 + (self.z - other.z)**2)# elif isinstance(other, Line):# return sqrt((self.x - other.points[0].x)**2 + (self.y - other.points[0].y)**2 + (self.z - other.points[0].z)**2)# elif isinstance(other, Curve):# return sqrt((self.x - other.lines[0].points[0].x)**2 + (self.y - other.lines[0].points[0].y)**2 + (self.z - other.lines[0].points[0].z)**2)# elif isinstance(other, Polyform):# return sqrt((self.x - other.points[0].x)**2 + (self.y - other.points[0].y)**2 + (self.z - other.points[0].z)**2)# elif isinstance(other, Group):# return other[0]# elif isinstance(other, int) and other == 0:# return sqrt(self.x**2 + self.y**2 + self.z**2)# elif isinstance (other, list):# return sqrt((self.x - other[0])**2 + (self.y - other[1])**2 + (self.z - other[2])**2)# else:# raise TypeError , ' calculate_distance() argument must be a Point, Line, Curve, Polyform, Group or a list with three numbers (flot/long/int)'# sys.exit(1)class Point(Primitive, list): """A vertex/knot/vector/point object for a point in 3D space""" def __init__(self, value1=0.0,value2=0.0,value3=0.0): self.x = 0.0 self.y = 0.0 self.z = 0.0 if isinstance(value1, Point): self.x = other.x self.y = other.y self.z = other.z elif isinstance (value1, list) and len(value1) == 3: self.x = value1[0] self.y = value1[1] self.z = value1[2] elif isinstance(value1, int) or isinstance(value2, long) or isinstance(value2, float): self.x = float(value1) if isinstance(value2, int) or isinstance(value2, long) or isinstance(value2, float): self.y = float(value2) if isinstance(value3, int) or isinstance(value3, long) or isinstance(value3, float): self.z = float(value3) else: raise TypeError , ' Point can only be created from another Point or one-three numerical values (int/long/float), these can passed as a list' sys.exit(1) # Return properly formatted string def __str__(self): return '(' + str(self.x) + ', ' + str(self.y) + ', ' + str(self.z) + ')' # Add two Points def __add__(self, other): return Point(self.x + other.getPoint().x, self.y + other.getPoint().y, self.z + other.getPoint().z) # Subtract two Points def __sub__(self, other): return Point(self.x - other.getPoint().x, self.y - other.getPoint().y, self.z - other.getPoint().z) # Dot product def __mul__(self, other): return Point(self.x * other.getPoint().x, self.y * other.getPoint().y, self.z * other.getPoint().z) # Scalar multiplication def __rmul__(self, other): return Point(other.getPoint().y * self.x + other.getPoint().y * self.y + other.getPoint().y * self.z) # Division def __div__(self, other): return Point(self.x / other.getPoint().x , self.y / other.getPoint().y , self.z / other.getPoint().z) # Modulo def __mod__(self, other): return Point(self.x % other.getPoint().x, self.y % other.getPoint().y, self.z % other.getPoint().z) # Exponentiation def __pow__(self, other): return Point(self.x ** other.getPoint().x, self.y ** other.getPoint().y, self.z ** other.getPoint().z) # Negative def __neg__(self): return Point(neg(self.x), neg(self.y), neg(self.z)) # Positive def __pos__(self): return Point(pos(self.x), pos(self.y), pos(self.z)) # Absolute def __abs__(self): return Point(abs(self.x), abs(self.y), abs(self.z)) # Compare two Points, 0 for same, 1 for self larger, -1 for other larger def __cmp__(self, other): if (self.x - other.x) == 0 and (self.y - other.y) == 0 and (self.z - other.z) == 0: return 0 elif self.x > other.x and self.y > other.y and self.z > other.z: return 1 else: return -1 # When you get a point from a point it always returns itself def getPoint(self, which = None, other = None): return self # Length of the "Vector" between 0,0,0 and the Point def length(self): return calculate_distance(self) # Returns a point which is mid way between the two points def average(self, other): return Point(self.x - (self.x - other.x) / 2 ,self.y - (self.y - other.y) / 2 ,self.z - (self.z - other.z) / 2) # Calculate the distances correctly to any object from a point, int(0) is assumed to be Point(0,0,0) def calculate_distance(self, other = CartesianZero()): return sqrt((self.x - other.getPoint("start").x)**2 + (self.x - other.getPoint("start").y)**2 + (self.z - other.getPoint("start").z)**2)class Line(Primitive, list): """A line/ray/vector which is defined by two Points""" def __init__(self, point0, point1): self.point0 = point0 self.point1 = point1 self.points = [point0, point1] # Return properly formatted string def __str__(self): return self.point0.__str__() + self.point1.__str__() # Length of a line or the distance from an ray start to the vector defining point def length(self): return calculate_distance(self.point0,self.point1) # Return a specific point from a line, first/last/middle or closest to a point, if closest is invoked without a point it returns the closest to 0,0,0 def getPoint(self, which = 0, other = CartesianZero()): if which in ["first", "start", "0", (0), [0]]: return self.point0 elif which in ["last", "end", "-1", (-1), [-1]]: return self.point1 elif which in ["center", "middle"]: return self.point0.average(self.point1) elif which in ["closest", "nearest", "near"] and isinstance(other, Point) or isinstance(other, CartesianZero): # faulty logic, should return the point on the line that is closest but not the closest defining point if self.point0.distance(other) > self.point1.distance(other): return self.point0 else: return self.point1 else: getPointTypeError()class Curve(Primitive, list): """A non-straight line defined as a NURBS curve""" # All curves should be defined as NURBS curve knot and knot-vectors, aka Series of non-connected Rays/Lines def __init__(self, lines): self.lines = lines # Return properly formatted string def __str__(self): return_string = list() for id in range(len(self.lines)): return_string.append(self.lines[id].__str__()) return str(return_string) def append(self, lines): for line in lines: self.lines.append(line) # Return a specific point from a curve, first/last/middle or closest to a point def getPoint(self, which = 0, other = CartesianZero()): if which in ["first", "start", "0", (0), [0]]: return self[0] elif which in ["last", "end", "-1", (-1), [-1]]: return self[-1] elif which in ["center", "middle"]: # Missing implementation return self[0] elif which in ["closest", "nearest", "near"] and isinstance(other, Point) or isinstance(other, CartesianZero): # Missing implementation return self[0] else: getPointTypeError()class Polyform(Primitive, list): """A Geometric object consisting of any number of points listed in sequence""" # A polyform is essentially a non-interpolated polyline which can be a solid def __init__(self, points): self.points = points # Return properly formatted string def __str__(self): return_string = list() for id in range(len(self.points)): return_string.append(self.points[id].__str__()) return str(return_string) def append(self, point): self.polyform.append(point) # Return a specific point from a curve, first/last/middle or closest to a point def getPoint(self, which = 0, other = CartesianZero()): if which in ["first", "start", "0", (0), [0]]: return self[0] elif which in ["last", "end", "-1", (-1), [-1]]: return self[-1] elif which in ["center", "middle"]: # Missing implementation return self[0] elif which in ["closest", "nearest", "near"] and isinstance(other, Point) or isinstance(other, CartesianZero): # Missing implementation return self[0] else: getPointTypeError()class Group(Primitive, list): """A collection of Polyforms, Curves and Lines""" # A group contains objects with a permanently fixed position relative to each other # All objects including itself(group) can be nested within a group # Groups where all objects form closed paths are considered to be solid objects or surfaces def __init__(self, geoObjects): self.objects = geoObjects def __str__(self): return_string = list() for id in range(len(self.objects)): return_string.append(self.objects[id].__str__()) return str(return_string) def append(self, geoObject): self.objects.append(geoObject) # Return a specific point from a curve, first/last/middle or closest to a point def getPoint(self, which, other = CartesianZero()): if which in ["first", "start", "0", (0), [0]]: newinstance = self while isinstance(newinstance, Group): newinstance = newinstance[0] return newinstance.GetPoint[0] elif which in ["last", "end", "-1", (-1), [-1]]: newinstance = self while isinstance(newinstance, Group): newinstance = newinstance[-1] return newinstance.GetPoint[-1] elif which in ["center", "middle"]: # Missing implementation return self[0] elif which in ["closest", "nearest", "near"] and isinstance(other, Point) or isinstance(other, CartesianZero): # Missing implementation return self[0] else: getPointTypeError()################# TEST #####################print ""print "###################### TEST ###########################"print "Create Objects"print " Create 10 points"mypoint0 = Point(0,0,0)mypoint1 = Point(10,10,10)mypoint2 = Point(20,20,20)mypoint3 = Point(30,20,30)mypoint4 = Point(40,20,30)mypoint5 = Point(50,20,30)mypoint6 = Point(60,20,30)mypoint7 = Point(70,20,30)mypoint8 = Point(80,20,30)mypoint9 = Point(90,20,30)print " Create 5 lines"myline0 = Line(mypoint0,mypoint1)myline1 = Line(mypoint2,mypoint3)myline2 = Line(mypoint4,mypoint5)myline3 = Line(mypoint6,mypoint7)myline4 = Line(mypoint8,mypoint9)print " Create 2 curves, one with 2 lines and the other with 3 lines"mycurve0 = Curve([myline0,myline1])mycurve1 = Curve([myline2,myline3,myline4])print " Create 2 polyforms, one with 3 points and the other with 7 points"mypolyform0 = Polyform([mypoint0,mypoint1,mypoint2])mypolyform1 = Polyform([mypoint3,mypoint4,mypoint5,mypoint6,mypoint7,mypoint8,mypoint9])print " Create 2 groups, one with 3 points, 2 lines, one curve and one polyline, the other everything including the other group"mygroup0 = Group([mypoint0,mypoint1,mypoint2,myline0,myline1,mycurve0,mypolyform0])mygroup1 = Group([mypoint0,mypoint1,mypoint2,mypoint3,mypoint4,mypoint5,mypoint6,mypoint7,mypoint8,mypoint9,myline0,myline1,myline2,myline3,myline4,mycurve0,mycurve1,mypolyform0,mypolyform1,mygroup0])print "Cast types to string"print " mypoint0 is: " + str(mypoint0)print " myline0 is: " + str(myline0)print " mycurve0 is: " + str(mycurve0)print " mypolyform0 is: " + str(mypolyform0)print " mygroup0 is: " + str(mygroup0)print "Return point objects from other objects"print " first point in myline2 is: " + str(myline2.points[0])print " first line in mycurve0 is: " + str(mycurve0.lines[0])print " first point in mypolyform1 is: " + str(mypolyform1.points[0])print " first object in mygroup1 is: " + str(mygroup1.objects[0])print "Silly, mypoint1 multiplied by the first point in myline1 divided by mypoint9 to the power of mypoint1"print " " + str(mypoint1 * myline1 / mypoint9 ** mypoint1)print "Distance Calculations"print " distance from mypoint0 to myline3: " + str(mypoint0.distance(myline3))print " distance from mypoint0 to start of myline3 (should be same as before): " + str(mypoint0.distance(myline3.points[0]))print " distance from mypoint1 to the middle of myline4: " + str(mypoint1.distance(myline4.getPoint("center")))print " distance from mypoint9 to the closest point of myline1: " + str(mypoint9.distance(myline1.getPoint("closest")))#drasl = Primitive()#drasl.inputParser(Point,myline1.points[0])