def applyTransforms(self, x, y): R = numpy.eye(2) r_o = numpy.zeros(2) tx, ty = 0, 0 sx, sy = 1.0, 1.0 if 'transform=' in self.header: if 'rotate(' in self.header: rotateParms = map(float, extractParms(self.header, 0, 'rotate(', ', ', ')')) if len(rotateParms) == 3: rotateDegrees, rx, ry = rotateParms else: assert len(rotateParms) == 1 rotateDegrees, rx, ry = rotateParms[0], 0.0, 0.0 rads = numpy.pi * rotateDegrees / 180 R = numpy.array([ [ cos(rads), -sin(rads)], [ sin(rads), cos(rads)] ]) r_o = numpy.array([ rx, ry]) if 'translate(' in self.header: tx, ty = map(float, extractParms(self.header, 0, 'translate(', ', ', ')')) if 'scale(' in self.header: scaleParms = map(float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] if 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" sx, shear_1, shear_2, sy, tx, ty = map(float, extractParms(self.header, 0, 'matrix(', ', ', ')')) if not shear_1 == 0 and shear_2 == 0: raise NotImplementedError(" not shear_1 == 0 and shear_2 == 0! header %s" % self.header) p = numpy.array( [sx*x + tx, sy*y + ty] ) point = dot(R, p-r_o) +r_o if self.parent != None: return self.parent.applyTransforms(*point) else: return point[0], point[1]
def Transforms(self, cumalative=True, T=None, c=None): 'y = dot(T,x) + c' if T is None: T = numpy.eye(2) c = numpy.zeros(2) R = numpy.eye(2) r_o = numpy.zeros(2) tx, ty = 0, 0 sx, sy = 1.0, 1.0 if 'transform=' in self.header: if 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" t_11, t_12, t_21, t22, c1, c2 = map( float, extractParms(self.header, 0, 'matrix(', ', ', ')')) T_e = numpy.array([[t_11, t_12], [t_21, t22]]) c_e = numpy.array([c1, c2]) T = dot(T_e, T) c = dot(T_e, c) + c_e if 'translate(' in self.header: tx, ty = map( float, extractParms(self.header, 0, 'translate(', ', ', ')')) if 'scale(' in self.header: scaleParms = map( float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] if 'rotate(' in self.header: rotateParms = map( float, extractParms(self.header, 0, 'rotate(', ', ', ')')) if len(rotateParms) == 3: rotateDegrees, rx, ry = rotateParms else: assert len(rotateParms) == 1 rotateDegrees, rx, ry = rotateParms[0], 0.0, 0.0 rads = numpy.pi * rotateDegrees / 180 R = numpy.array([[cos(rads), -sin(rads)], [sin(rads), cos(rads)]]) r_o = numpy.array([rx, ry]) T_e = numpy.array([[sx, 0.0], [0.0, sy]]) c_e = numpy.array([tx, ty]) T = dot(T_e, T) c = dot(T_e, c) + c_e # z = dot(R, y - r_o) + r_o # z = dot(R, dot(T,x) + c - r_o) + r_o T = dot(R, T) c = dot(R, c) - dot(R, r_o) + r_o if self.parent != None and cumalative: return self.parent.Transforms(T=T, c=c) else: return T, c
def Transforms( self, cumalative=True, T=None, c=None): 'y = dot(T,x) + c' if T is None: T = numpy.eye(2) c = numpy.zeros(2) R = numpy.eye(2) r_o = numpy.zeros(2) tx, ty = 0, 0 sx, sy = 1.0, 1.0 if 'transform=' in self.header: if 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" t_11, t_12, t_21, t22, c1, c2 = map(float, extractParms(self.header, 0, 'matrix(', ', ', ')')) T_e = numpy.array([[ t_11, t_12], [t_21, t22]]) c_e = numpy.array([c1,c2]) T = dot( T_e, T ) c = dot( T_e, c) + c_e if 'translate(' in self.header: tx, ty = map(float, extractParms(self.header, 0, 'translate(', ', ', ')')) if 'scale(' in self.header: scaleParms = map(float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] if 'rotate(' in self.header: rotateParms = map(float, extractParms(self.header, 0, 'rotate(', ', ', ')')) if len(rotateParms) == 3: rotateDegrees, rx, ry = rotateParms else: assert len(rotateParms) == 1 rotateDegrees, rx, ry = rotateParms[0], 0.0, 0.0 rads = numpy.pi * rotateDegrees / 180 R = numpy.array([ [ cos(rads), -sin(rads)], [ sin(rads), cos(rads)] ]) r_o = numpy.array([ rx, ry]) T_e = numpy.array([[ sx, 0.0], [0.0, sy]]) c_e = numpy.array([tx,ty]) T = dot( T_e, T ) c = dot( T_e, c) + c_e # z = dot(R, y - r_o) + r_o # z = dot(R, dot(T,x) + c - r_o) + r_o T = dot(R,T) c = dot(R,c) - dot(R,r_o) + r_o if self.parent != None and cumalative: return self.parent.Transforms(T=T, c=c) else: return T, c
def scaling2(self, s=1.0): 'other scaling works only for drawingObject.ViewResult groups...' if 'transform=' in self.header: if 'scale(' in self.header: scaleParms = map(float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] s = s * sx elif 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" sx, shear_1, shear_2, sy, tx, ty = map(float, extractParms(self.header, 0, 'matrix(', ', ', ')')) assert shear_1 == 0 and shear_2 == 0 s = s *sx if self.parent != None: return self.parent.scaling2(s) else: return s
def scaling(self): sx = 1.0 if 'scale(' in self.header: sx = map(float, extractParms(self.header, 0, 'scale(', ',', ')'))[0] if len(self.children) == 1: sx_child = self.children[0].scaling() else: sx_child = 1.0 return sx * sx_child
def applyTransforms(self, x, y): R = numpy.eye(2) r_o = numpy.zeros(2) tx, ty = 0, 0 sx, sy = 1.0, 1.0 if 'transform=' in self.header: if 'rotate(' in self.header: rotateParms = map( float, extractParms(self.header, 0, 'rotate(', ', ', ')')) if len(rotateParms) == 3: rotateDegrees, rx, ry = rotateParms else: assert len(rotateParms) == 1 rotateDegrees, rx, ry = rotateParms[0], 0.0, 0.0 rads = numpy.pi * rotateDegrees / 180 R = numpy.array([[cos(rads), -sin(rads)], [sin(rads), cos(rads)]]) r_o = numpy.array([rx, ry]) if 'translate(' in self.header: tx, ty = map( float, extractParms(self.header, 0, 'translate(', ', ', ')')) if 'scale(' in self.header: scaleParms = map( float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] if 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" sx, shear_1, shear_2, sy, tx, ty = map( float, extractParms(self.header, 0, 'matrix(', ', ', ')')) if not shear_1 == 0 and shear_2 == 0: raise NotImplementedError( " not shear_1 == 0 and shear_2 == 0! header %s" % self.header) p = numpy.array([sx * x + tx, sy * y + ty]) point = dot(R, p - r_o) + r_o if self.parent != None: return self.parent.applyTransforms(*point) else: return point[0], point[1]
def scaling2(self, s=1.0): 'other scaling works only for drawingObject.ViewResult groups...' if 'transform=' in self.header: if 'scale(' in self.header: scaleParms = map( float, extractParms(self.header, 0, 'scale(', ', ', ')')) if len(scaleParms) == 2: sx, sy = scaleParms else: sx, sy = scaleParms[0], scaleParms[0] s = s * sx elif 'matrix(' in self.header: #"matrix(1.25,0,0,-1.25,-348.3393,383.537)" sx, shear_1, shear_2, sy, tx, ty = map( float, extractParms(self.header, 0, 'matrix(', ', ', ')')) assert shear_1 == 0 and shear_2 == 0 s = s * sx if self.parent != None: return self.parent.scaling2(s) else: return s
def __init__(self, element): assert isinstance(element, SvgXMLTreeNode) self.points = [] self.lines = [] points_raw = list(map( float, element.parms['points'].replace(',',' ').split() )) X = [] Y = [] for i in range(len(points_raw)/2): _x = points_raw[i*2] _y = points_raw[i*2 + 1] x, y = element.applyTransforms( _x, _y ) X.append(x) Y.append(y) self.points.append( SvgPathPoint( _x, _y, x, y ) ) X.append(X[0]) Y.append(Y[0]) for i in range(len(X)-1): self.lines.append( SvgPathLine( X[i], Y[i], X[i+1], Y[i+1] ) )
def __init__(self, element): assert isinstance(element, SvgXMLTreeNode) self.points = [] self.lines = [] points_raw = list( map(float, element.parms['points'].replace(',', ' ').split())) X = [] Y = [] for i in range(len(points_raw) / 2): _x = points_raw[i * 2] _y = points_raw[i * 2 + 1] x, y = element.applyTransforms(_x, _y) X.append(x) Y.append(y) self.points.append(SvgPathPoint(_x, _y, x, y)) X.append(X[0]) Y.append(Y[0]) for i in range(len(X) - 1): self.lines.append(SvgPathLine(X[i], Y[i], X[i + 1], Y[i + 1]))
def __init__( self, element): assert isinstance(element, SvgXMLTreeNode) self.points = [] self.lines = [] self.arcs = [] self.bezierCurves = [] self.elements = [] # for preserving order of path elements, pen movements are not considered elements since they do not result in a direct visual effect dParmsXML_org = element.parms['d'].replace(',',' ') #<spacing corrections> dParmsXML = '' for a,b in zip(dParmsXML_org[:-1], dParmsXML_org[1:]): if a in 'MmLlAaCcQZzHhVv': if len(dParmsXML) > 0 and dParmsXML[-1] != ' ': dParmsXML = dParmsXML + ' ' dParmsXML = dParmsXML + a if b != ' ': dParmsXML = dParmsXML + ' ' elif a != ' ' and a != 'e' and b == '-': dParmsXML = dParmsXML + a + ' ' else: dParmsXML = dParmsXML + a if b in 'MmLlAaCcQZzHhVv' and dParmsXML[-1] != ' ': dParmsXML = dParmsXML + ' ' dParmsXML = dParmsXML + b #<spacing corrections> parms = dParmsXML.replace(',',' ').strip().split() _pen_x = 0 _pen_y = 0 j = 0 pathDescriptor = None while j < len(parms): #print(parms[j:]) if parms[j] in list('MmLlAaCcQZzHhVv,'): pathDescriptor = parms[j] else: #using previous pathDescriptor if pathDescriptor == None: raise RuntimeError('pathDescriptor == None! unable to parse path "%s" with d parms %s' % (element.XML[element.pStart: element.pEnd], parms)) parms.insert(j, pathDescriptor.replace('m','l').replace('M','L')) if parms[j] == 'M' or parms[j] == 'm': if parms[j] == 'M': _pen_x, _pen_y = float(parms[j+1]), float(parms[j+2]) else: #m _pen_x = _pen_x + float(parms[j+1]) _pen_y = _pen_y + float(parms[j+2]) pen_x, pen_y = element.applyTransforms( _pen_x, _pen_y ) _path_start_x , _path_start_y = _pen_x, _pen_y path_start_x , path_start_y = pen_x, pen_y self.points.append( SvgPathPoint( _pen_x, _pen_y, pen_x, pen_y ) ) j = j + 3 elif parms[j] in 'LlZzVvHh': if parms[j] in 'Ll': if parms[j] == 'L': _end_x, _end_y = float(parms[j+1]), float(parms[j+2]) else: _end_x = _pen_x + float(parms[j+1]) _end_y = _pen_y + float(parms[j+2]) end_x, end_y = element.applyTransforms( _end_x, _end_y ) self.points.append( SvgPathPoint( _end_x, _end_y, end_x, end_y ) ) j = j + 3 elif parms[j] in 'VvHh': if parms[j] == 'V': _end_x, _end_y = _pen_x, float(parms[j+1]) elif parms[j] == 'v': _end_x = _pen_x _end_y = _pen_y + float(parms[j+1]) elif parms[j] == 'H': _end_x, _end_y = float(parms[j+1]), _pen_y elif parms[j] == 'h': _end_x = _pen_x + float(parms[j+1]) _end_y = _pen_y end_x, end_y = element.applyTransforms( _end_x, _end_y ) self.points.append( SvgPathPoint( _end_x, _end_y, end_x, end_y ) ) j = j + 2 else: #parms[j] == 'Z': _end_x, _end_y = _path_start_x , _path_start_y end_x, end_y = path_start_x , path_start_y j = j + 1 self.lines.append( SvgPathLine( pen_x, pen_y, end_x, end_y ) ) self.elements.append( self.lines[-1] ) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y elif parms[j] == 'A' or parms[j] == 'a': # The arc command begins with the x and y radius and ends with the ending point of the arc. # Between these are three other values: x axis rotation, large arc flag and sweep flag. rX, rY, xRotation, largeArc, sweep, _end_x, _end_y = list(map( float, parms[j+1:j+1 + 7] )) #print(_end_x, _end_y) if parms[j] == 'a': _end_x = _pen_x + _end_x _end_y = _pen_y + _end_y #print(_end_x, _end_y) end_x, end_y = element.applyTransforms( _end_x, _end_y ) if not ( _pen_x == _end_x and _pen_y == _end_y ) and rX != 0 and rY != 0: self.points.append( SvgPathPoint(_end_x, _end_y, end_x, end_y) ) try: self.arcs.append( SvgPathArc( element, _pen_x, _pen_y, rX, rY, xRotation, largeArc, sweep, _end_x, _end_y ) ) self.elements.append(self.arcs[-1]) except SvgParseError as e: printWarning( 2, 'failed to parse arc: msg %s' % str(e) ) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y j = j + 8 elif parms[j] == 'C' or parms[j] == 'c' or parms[j] =='Q': #Bézier curve if parms[j] == 'C' or parms[j] == 'c': #cubic Bézier curve from the current point to (x,y) using # (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve. if parms[j] == 'C': _x1, _y1, _x2, _y2, _end_x, _end_y = list(map( float, parms[j+1:j+1 + 6] )) else: #parms[j] == 'c': _x1, _y1, _x2, _y2, _end_x, _end_y = numpy.array(map( float, parms[j+1:j+1 + 6] )) + numpy.array([_pen_x,_pen_y]*3) P = [ [pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_x2, _y2), element.applyTransforms(_end_x, _end_y) ] j = j + 7 elif parms[j] == 'Q': # quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point. # Q (uppercase) indicates that absolute coordinates will follow; # q (lowercase) indicates that relative coordinates will follow. # Multiple sets of coordinates may be specified to draw a polybézier. # At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier. _x1, _y1, _end_x, _end_y = list(map( float, parms[j+1:j+1 + 4] )) j = j + 5 P = [ [pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_end_x, _end_y) ] self.bezierCurves.append( SvgPathBezierCurve(P) ) self.elements.append(self.bezierCurves[-1]) end_x, end_y = P[-1] self.points.append( SvgPathPoint(_end_x, _end_y, end_x, end_y) ) else: raise RuntimeError('unable to parse path "%s" with d parms %s' % (element.XML[element.pStart: element.pEnd], parms))
FF 0 3F 240 255 0 63 FF AA BF 241 255 170 191 BD 0 2E 242 189 0 46 BD 7E 8D 243 189 126 141 81 0 1F 244 129 0 31 81 56 60 245 129 86 96 68 0 19 246 104 0 25 68 45 4E 247 104 69 78 4F 0 13 248 79 0 19 4F 35 3B 249 79 53 59 33 33 33 250 51 51 51 50 50 50 251 80 80 80 69 69 69 252 105 105 105 82 82 82 253 130 130 130 BE BE BE 254 190 190 190 FF FF FF 255 255 255 255''' dxf_colours = numpy.zeros([ 256, 3 ]) for line in color_table_text.split('\n'): parts = line.split() ind = int(parts[3]) r,g,b = map(int, parts[4:]) dxf_colours[ind] = r,g,b def colorLookup(r,g,b): clr = numpy.array([r,g,b]) errors = [ numpy.linalg.norm( clr - row) for row in dxf_colours ] min_ind = errors.index( min(errors) ) return min_ind, dxf_colours[min_ind]
def __init__(self, element): assert isinstance(element, SvgXMLTreeNode) self.points = [] self.lines = [] self.arcs = [] self.bezierCurves = [] self.elements = [ ] # for preserving order of path elements, pen movements are not considered elements since they do not result in a direct visual effect dParmsXML_org = element.parms['d'].replace(',', ' ') #<spacing corrections> dParmsXML = '' for a, b in zip(dParmsXML_org[:-1], dParmsXML_org[1:]): if a in 'MmLlAaCcQZzHhVv': if len(dParmsXML) > 0 and dParmsXML[-1] != ' ': dParmsXML = dParmsXML + ' ' dParmsXML = dParmsXML + a if b != ' ': dParmsXML = dParmsXML + ' ' elif a != ' ' and a != 'e' and b == '-': dParmsXML = dParmsXML + a + ' ' else: dParmsXML = dParmsXML + a if b in 'MmLlAaCcQZzHhVv' and dParmsXML[-1] != ' ': dParmsXML = dParmsXML + ' ' dParmsXML = dParmsXML + b #<spacing corrections> parms = dParmsXML.replace(',', ' ').strip().split() _pen_x = 0 _pen_y = 0 j = 0 pathDescriptor = None while j < len(parms): #print(parms[j:]) if parms[j] in list('MmLlAaCcQZzHhVv,'): pathDescriptor = parms[j] else: #using previous pathDescriptor if pathDescriptor == None: raise RuntimeError( 'pathDescriptor == None! unable to parse path "%s" with d parms %s' % (element.XML[element.pStart:element.pEnd], parms)) parms.insert( j, pathDescriptor.replace('m', 'l').replace('M', 'L')) if parms[j] == 'M' or parms[j] == 'm': if parms[j] == 'M': _pen_x, _pen_y = float(parms[j + 1]), float(parms[j + 2]) else: #m _pen_x = _pen_x + float(parms[j + 1]) _pen_y = _pen_y + float(parms[j + 2]) pen_x, pen_y = element.applyTransforms(_pen_x, _pen_y) _path_start_x, _path_start_y = _pen_x, _pen_y path_start_x, path_start_y = pen_x, pen_y self.points.append(SvgPathPoint(_pen_x, _pen_y, pen_x, pen_y)) j = j + 3 elif parms[j] in 'LlZzVvHh': if parms[j] in 'Ll': if parms[j] == 'L': _end_x, _end_y = float(parms[j + 1]), float(parms[j + 2]) else: _end_x = _pen_x + float(parms[j + 1]) _end_y = _pen_y + float(parms[j + 2]) end_x, end_y = element.applyTransforms(_end_x, _end_y) self.points.append( SvgPathPoint(_end_x, _end_y, end_x, end_y)) j = j + 3 elif parms[j] in 'VvHh': if parms[j] == 'V': _end_x, _end_y = _pen_x, float(parms[j + 1]) elif parms[j] == 'v': _end_x = _pen_x _end_y = _pen_y + float(parms[j + 1]) elif parms[j] == 'H': _end_x, _end_y = float(parms[j + 1]), _pen_y elif parms[j] == 'h': _end_x = _pen_x + float(parms[j + 1]) _end_y = _pen_y end_x, end_y = element.applyTransforms(_end_x, _end_y) self.points.append( SvgPathPoint(_end_x, _end_y, end_x, end_y)) j = j + 2 else: #parms[j] == 'Z': _end_x, _end_y = _path_start_x, _path_start_y end_x, end_y = path_start_x, path_start_y j = j + 1 self.lines.append(SvgPathLine(pen_x, pen_y, end_x, end_y)) self.elements.append(self.lines[-1]) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y elif parms[j] == 'A' or parms[j] == 'a': # The arc command begins with the x and y radius and ends with the ending point of the arc. # Between these are three other values: x axis rotation, large arc flag and sweep flag. rX, rY, xRotation, largeArc, sweep, _end_x, _end_y = list( map(float, parms[j + 1:j + 1 + 7])) #print(_end_x, _end_y) if parms[j] == 'a': _end_x = _pen_x + _end_x _end_y = _pen_y + _end_y #print(_end_x, _end_y) end_x, end_y = element.applyTransforms(_end_x, _end_y) if not (_pen_x == _end_x and _pen_y == _end_y) and rX != 0 and rY != 0: self.points.append( SvgPathPoint(_end_x, _end_y, end_x, end_y)) try: self.arcs.append( SvgPathArc(element, _pen_x, _pen_y, rX, rY, xRotation, largeArc, sweep, _end_x, _end_y)) self.elements.append(self.arcs[-1]) except SvgParseError as e: printWarning(2, 'failed to parse arc: msg %s' % str(e)) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y j = j + 8 elif parms[j] == 'C' or parms[j] == 'c' or parms[ j] == 'Q': #Bézier curve if parms[j] == 'C' or parms[j] == 'c': #cubic Bézier curve from the current point to (x,y) using # (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve. if parms[j] == 'C': _x1, _y1, _x2, _y2, _end_x, _end_y = list( map(float, parms[j + 1:j + 1 + 6])) else: #parms[j] == 'c': _x1, _y1, _x2, _y2, _end_x, _end_y = numpy.array( map(float, parms[j + 1:j + 1 + 6])) + numpy.array( [_pen_x, _pen_y] * 3) P = [[pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_x2, _y2), element.applyTransforms(_end_x, _end_y)] j = j + 7 elif parms[ j] == 'Q': # quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point. # Q (uppercase) indicates that absolute coordinates will follow; # q (lowercase) indicates that relative coordinates will follow. # Multiple sets of coordinates may be specified to draw a polybézier. # At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier. _x1, _y1, _end_x, _end_y = list( map(float, parms[j + 1:j + 1 + 4])) j = j + 5 P = [[pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_end_x, _end_y)] self.bezierCurves.append(SvgPathBezierCurve(P)) self.elements.append(self.bezierCurves[-1]) end_x, end_y = P[-1] self.points.append(SvgPathPoint(_end_x, _end_y, end_x, end_y)) else: raise RuntimeError( 'unable to parse path "%s" with d parms %s' % (element.XML[element.pStart:element.pEnd], parms))
def textChanged( self, arg1=None): try: self.dimensioningProcess.dimensionConstructorKWs[ self.name ] = map(float, [v for v in self.textbox.toPlainText().split('\n') if len(v.strip())>0]) #debugPrint(1, str(self.dimensioningProcess.dimensionConstructorKWs[ self.name ])) except: FreeCAD.Console.PrintError(traceback.format_exc())
def FreeCAD_parm_to_val( self, FreeCAD_parm ): return map(float, FreeCAD_parm.split('\n'))
def val_to_FreeCAD_parm( self, val ): return '\n'.join(map(str, val))