def __init__(self, drawingView, calculateBounds=False ): self.name = drawingView.Name #self.scale = drawingView.Scale #not always correct for center line objects. self.drawing_x = drawingView.X self.drawing_y = drawingView.Y self.viewResult_length = len(drawingView.ViewResult) self.viewResult_hash = hash(drawingView.ViewResult) if calculateBounds: XML_tree = SvgXMLTreeNode(drawingView.ViewResult, 0) scaling = XML_tree.scaling() self.scale = scaling for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* scaling self.updateBounds_ellipse( x, y, r, r ) if element.tag == 'ellipse': cx, cy = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) rx, ry = float( element.parms['rx'] )* scaling, float( element.parms['ry'] )* scaling self.updateBounds_ellipse( cx, cy, rx, ry ) if element.tag == 'path': path = SvgPath( element ) for p in path.points: self.updateBounds( p.x, p.y ) if element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) self.updateBounds( x1, y1 ) self.updateBounds( x1, y2 )
def getPoints(svg): "returns a series of (x,y) points from an SVG fragment" # adapted from selectionOverlay.py points = [] XML_tree = SvgXMLTreeNode(svg, 0) scaling = XML_tree.scaling() SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) points.append((x, y)) elif element.tag == 'ellipse': x, y = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) points.append((x, y)) elif element.tag == 'text' and element.parms.has_key('x'): x, y = element.applyTransforms(float(element.parms['x']), float(element.parms['y'])) points.append((x, y)) elif element.tag == 'path': path = SvgPath(element) for p in path.points: points.append((p.x, p.y)) elif element.tag == 'line': x1, y1 = element.applyTransforms(float(element.parms['x1']), float(element.parms['y1'])) x2, y2 = element.applyTransforms(float(element.parms['x2']), float(element.parms['y2'])) points.append((x1, y1)) points.append((x2, y2)) return points
def getPoints(svg): "returns a series of (x,y) points from an SVG fragment" # adapted from selectionOverlay.py points = [] XML_tree = SvgXMLTreeNode(svg,0) scaling = XML_tree.scaling() SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) points.append((x,y)) elif element.tag == 'ellipse': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) points.append((x,y)) elif element.tag == 'text' and element.parms.has_key('x'): x, y = element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) points.append((x,y)) elif element.tag == 'path': path = SvgPath( element ) for p in path.points: points.append((p.x, p.y)) elif element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) points.append((x1, y1)) points.append((x2, y2)) return points
def __init__(self, SvgXML, element_tag_of_interest, doFittedCircles=False): 'parses a SVG and returns a FreeCAD_Object.Shape styled data structure' self.points = [] self.lines = [] self.circles = [] self.ellipses = [] self.arcs = [] self.texts = [] XML_tree = SvgXMLTreeNode( SvgXML, 0 ) scaling = XML_tree.scaling() for element in XML_tree.getAllElements(): if element.tag != element_tag_of_interest: continue if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* scaling self.circles.append( [ x, y, r] ) self.ellipse_points( x, y, r, r ) if element.tag == 'ellipse': #no angle parm? cx, cy = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) rx, ry = float( element.parms['rx'] )* scaling, float( element.parms['ry'] )* scaling self.ellipses.append( [ cx, cy, rx, ry] ) self.ellipse_points( cx, cy, rx, ry ) if element.tag == 'text' and element.parms.has_key('x'): x, y = element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) self.texts.append( [x, y, element] ) if element.tag == 'path': path = SvgPath( element ) for p in path.points: self.points.append( [p.x, p.y] ) for line in path.lines: self.lines.append([ line.x1, line.y1, line.x2, line.y2 ]) self.points.append( line.midPoint() ) for arc in path.arcs: if arc.circular: self.circles.append( [arc.center[0], arc.center[1], arc.r*scaling] ) else: self.ellipses.append( [arc.center[0], arc.center[1], arc.rX*scaling, arc.rY*scaling ] ) self.points.append( [arc.center[0], arc.center[1]] ) if doFittedCircles: for bezierCurve in path.bezierCurves: x, y, r, r_error = bezierCurve.fitCircle() if r_error < 10**-4: self.circles.append( [ x, y, r] ) if element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) self.points.append( [x1, y1] ) self.points.append( [x2, y2] ) self.points.append( [(x1+x2)/2, (y1+y2)/2] ) self.lines.append( [x1, y1, x2, y2 ] )
def generateSelectionGraphicsItems( viewObjects, onClickFun, transform=None, sceneToAddTo=None, clearPreviousSelectionItems=True, doPoints=False, doTextItems=False, doLines=False, doCircles=False, doFittedCircles=False, pointWid=1.0 , maskPen=defaultMaskPen , maskBrush=defaultMaskBrush, maskHoverPen=defaultMaskHoverPen ): if clearPreviousSelectionItems: del graphicItems[:] #may cause problems, if conflict results with FreeCAD recompute function def postProcessGraphicsItem(gi, elementParms): gi.setBrush( maskBrush ) gi.setPen(maskPen) gi.selectionMaskPen = maskPen gi.selectionMaskHoverPen = maskHoverPen gi._onClickFun = onClickFun gi.elementParms = elementParms gi.elementXML = element #should be able to get from functions name space gi.elementViewObject = viewObject gi.setAcceptHoverEvents(True) gi.setCursor( QtCore.Qt.CrossCursor ) # http://qt-project.org/doc/qt-5/qt.html#CursorShape-enum if transform <> None: gi.setTransform( transform ) if sceneToAddTo <> None: sceneToAddTo.addItem(gi) graphicItems.append(gi) pointsAlreadyAdded = [] def addSelectionPoint( x, y ): #common code if [x,y] in pointsAlreadyAdded: return pointsAlreadyAdded.append( [x,y] ) graphicsItem = CircleSelectionGraphicsItem( x-pointWid, y-pointWid, 2*pointWid, 2*pointWid ) graphicsItem.setZValue( 1 ) #point on top! postProcessGraphicsItem(graphicsItem, {'x':x, 'y':y}) for viewObject in viewObjects: if viewObject.ViewResult.strip() == '': pass XML_tree = SvgXMLTreeNode(viewObject.ViewResult,0) scaling = XML_tree.scaling() for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* scaling if doCircles: graphicsItem = CircleSelectionGraphicsItem( x-r, y-r, 2*r, 2*r ) graphicsItem.setZValue( 1.01**-r ) #smaller circles on top postProcessGraphicsItem(graphicsItem, {'x':x,'y':y,'r':r}) if doPoints: addSelectionPoint ( x, y ) #Circle center point addSelectionPoint ( x + r, y ) #Circle right quadrant point addSelectionPoint ( x - r, y ) #Circle left quadrant point addSelectionPoint ( x , y + r ) #Circle top quadrant point addSelectionPoint ( x , y - r ) #Circle bottom quadrant point if element.tag == 'text' and doTextItems: addSelectionPoint( *element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) ) if element.tag == 'path': #print(element.XML) fitData = [] dParmsXML = element.parms['d'] #<spacing corrections> i = 0 while i < len(dParmsXML)-1: if dParmsXML[i] in 'MLACQ,' and dParmsXML[i+1] in '-.0123456789': dParmsXML = dParmsXML[:i+1] + ' ' + dParmsXML[i+1:] i = i + 1 #</spacing corrections> parms = dParmsXML.replace(',',' ').strip().split() j = 0 while j < len(parms): #print(parms[j:]) if parms[j] == 'M': pen_x, pen_y = element.applyTransforms( float(parms[j+1]), float(parms[j+2]) ) j = j + 3 elif parms[j] == 'L': end_x, end_y = element.applyTransforms( float(parms[j+1]), float(parms[j+2]) ) if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) if doLines: graphicsItem = LineSelectionGraphicsItem( pen_x, pen_y, end_x, end_y ) postProcessGraphicsItem(graphicsItem, {'x1':pen_x,'y1':pen_y,'x2':end_x,'y2':end_y}) pen_x, pen_y = end_x, end_y j = j + 3 elif 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 = map( float, parms[j+1:j+1 + 7] ) end_x, end_y = element.applyTransforms( _end_x, _end_y ) if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) if doFittedCircles : pass #not implement yet for arcs ... pen_x, pen_y = end_x, end_y j = j + 8 elif parms[j] == 'C' or parms[j] =='Q': #Bézier curve if 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. _x1, _y1, _x2, _y2, _end_x, _end_y = map( float, parms[j+1:j+1 + 6] ) P = [ [pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_x2, _y2), element.applyTransforms(_end_x, _end_y) ] 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 = map( float, parms[j+1:j+1 + 4] ) P = [ [pen_x, pen_y], element.applyTransforms(_x1, _y1), element.applyTransforms(_end_x, _end_y) ] end_x, end_y = P[-1] if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) if doFittedCircles : fitData.append( P ) pen_x, pen_y = end_x, end_y j = j + 7 else: raise RuntimeError, 'unable to parse path "%s" with d parms %s' % (element.XML[element.pStart: element.pEnd], parms) if len(fitData) > 0: x, y, r, r_error = bezier_curve_lib.fitCircle_to_path(fitData) #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) if r_error < 10**-4: graphicsItem = CircleSelectionGraphicsItem( x-r, y-r, 2*r, 2*r ) graphicsItem.setZValue( 1.01**-r ) #smaller circles on top postProcessGraphicsItem(graphicsItem, {'x':x,'y':y,'r':r, 'r_error':r_error}) #self.fitted_circles.append( FittedCircle( element, fitData, cx, cy, r) ) return graphicItems
def export_via_dxfwrite( dxf_fn, V): from XMLlib import SvgXMLTreeNode from svgLib_dd import SvgTextParser, SvgPath, SvgPolygon from numpy import arctan2 from circleLib import fitCircle_to_path, findCircularArcCentrePoint, pointsAlongCircularArc from dxfwrite import DXFEngine as dxf drawing = dxf.drawing( dxf_fn) pageSvg = open(V.page.PageResult).read() XML_tree = SvgXMLTreeNode( pageSvg,0) def yT(y): #y transform return 210-y warningsShown = [] SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): clr_text = None if element.parms.has_key('fill'): clr_text = element.parms['fill'] elif element.parms.has_key('style'): for part in element.parms['style'].split(';'): if part.startswith('stroke:rgb('): clr_text = part[ len('stroke:'):] if clr_text == None or clr_text =='none' or not clr_text.startswith('rgb(') : color_code = 0 else: #FreeCAD.Console.PrintMessage( "color text: %s\n" % clr_text ) r,g,b = [ int(v.strip()) for v in clr_text[ len('rgb('): clr_text.find(')')].split(',') ] color_code = colorLookup(r,g,b)[0] if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* element.scaling2() drawing.add( dxf.circle( r, (x,yT(y)), color=color_code) ) elif element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) drawing.add( dxf.line( (x1, yT(y1)), (x2, yT(y2)), color=color_code ) ) elif element.tag == 'text' and element.parms.has_key('x'): x,y = element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) try: t = SvgTextParser(element.XML[element.pStart: element.pEnd ] ) drawing.add(dxf.text( t.text, insert=(x, yT(y)), height=t.height()*0.8, rotation=t.rotation, layer='TEXTLAYER', color=color_code) ) except ValueError, msg: FreeCAD.Console.PrintWarning('dxf_export: unable to convert text element "%s": %s, ignoring...\n' % (element.XML[element.pStart: element.pEnd ], str(msg) ) ) elif element.tag == 'path': #FreeCAD.Console.PrintMessage(element.parms['d']+'\n') path = SvgPath( element ) for line in path.lines: drawing.add( dxf.line( (line.x1, yT(line.y1)), (line.x2,yT(line.y2)), color=color_code) ) for arc in path.arcs: if arc.circular: for r, center, angle1, angle2 in arc.dxfwrite_arc_parms( yT ): drawing.add( dxf.arc( r, center, angle1, angle2 , color=color_code) ) else: for x1,y1,x2,y2 in arc.approximate_via_lines( 12 ): drawing.add( dxf.line( (x1, yT(y1)), (x2, yT(y2)), color=color_code) ) for bezierCurve in path.bezierCurves: x, y, r, r_error = bezierCurve.fitCircle() if r_error < 10**-4: raise NotImplementedError drawing.add( dxf.arc( *bezierCurve.dxfwrite_arc_parms(x, y, r) ) ) else: X,Y = bezierCurve.points_along_curve() for i in range(len(X) -1): drawing.add( dxf.line( (X[i], yT(Y[i])), (X[i+1],yT(Y[i+1])), color=color_code ) )
def generateSelectionGraphicsItems( viewObjects, onClickFun, transform=None, sceneToAddTo=None, clearPreviousSelectionItems=True, doPoints=False, doTextItems=False, doLines=False, doCircles=False, doFittedCircles=False, doPathEndPoints=False, doMidPoints=False, doSelectViewObjectPoints=False, pointWid=1.0 , maskPen=defaultMaskPen , maskBrush=defaultMaskBrush, maskHoverPen=defaultMaskHoverPen ): if clearPreviousSelectionItems: if sceneToAddTo <> None: for gi in sceneToAddTo.items(): if isinstance(gi, CircleSelectionGraphicsItem): sceneToAddTo.removeItem(gi) del graphicItems[:] def postProcessGraphicsItem(gi, elementParms, zValue=0.99): gi.setBrush( maskBrush ) gi.setPen(maskPen) gi.selectionMaskPen = QtGui.QPen(maskPen) gi.selectionMaskHoverPen = QtGui.QPen(maskHoverPen) gi._onClickFun = onClickFun gi.elementParms = elementParms gi.elementXML = element #should be able to get from functions name space gi.elementViewObject = viewObject gi.setAcceptHoverEvents(True) gi.setCursor( QtCore.Qt.CrossCursor ) # http://qt-project.org/doc/qt-5/qt.html#CursorShape-enum ; may not work for lines ... gi.setZValue(zValue) if transform <> None: gi.setTransform( transform ) if sceneToAddTo <> None: sceneToAddTo.addItem(gi) graphicItems.append(gi) pointsAlreadyAdded = [] def addSelectionPoint( x, y, zValue=1.0 ): #common code if [x,y] in pointsAlreadyAdded: return pointsAlreadyAdded.append( [x,y] ) graphicsItem = PointSelectionGraphicsItem( x-pointWid, y-pointWid, 2*pointWid, 2*pointWid ) postProcessGraphicsItem(graphicsItem, {'x':x, 'y':y}, zValue) def addCircle( x, y, r, **extraKWs): graphicsItem = CircleSelectionGraphicsItem( x-r, y-r, 2*r, 2*r ) KWs = {'x':x,'y':y,'r':r} KWs.update(extraKWs) postProcessGraphicsItem(graphicsItem, KWs, zValue=1.01**-r ) #smaller circles on top def circlePoints( x, y, rx, ry ): addSelectionPoint ( x, y, 2 ) #Circle/ellipse center point addSelectionPoint ( x + rx, y, 2 ) #Circle/ellipse right quadrant point addSelectionPoint ( x - rx, y, 2 ) #Circle/ellipse left quadrant point addSelectionPoint ( x , y + ry, 2 ) #Circle/ellipse top quadrant point addSelectionPoint ( x , y - ry, 2 ) #Circle/ellipse bottom quadrant point for viewObject in viewObjects: if not hasattr(viewObject, 'ViewResult'): continue if viewObject.ViewResult.strip() == '': continue XML_tree = SvgXMLTreeNode(viewObject.ViewResult,0) scaling = XML_tree.scaling() SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* scaling if doCircles: addCircle( x, y, r) if doPoints: circlePoints( x, y, r, r) if element.tag == 'ellipse': cx, cy = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) rx, ry = float( element.parms['rx'] )* scaling, float( element.parms['ry'] )* scaling if doCircles: if rx == ry: addCircle( cx, cy, rx) if doPoints: circlePoints( cx, cy, rx, ry) if element.tag == 'text' and element.parms.has_key('x'): if doTextItems: addSelectionPoint( *element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) ) elif doSelectViewObjectPoints: addSelectionPoint( *element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) ) if element.tag == 'path': path = SvgPath( element ) if doPoints: for p in path.points: addSelectionPoint( p.x, p.y ) if doLines: for line in path.lines: x1, y1, x2, y2 = line.x1, line.y1, line.x2, line.y2 graphicsItem = LineSelectionGraphicsItem( x1, y1, x2, y2 ) postProcessGraphicsItem(graphicsItem, {'x1':x1,'y1':y1,'x2':x2,'y2':y2} ) if doMidPoints: for line in path.lines: addSelectionPoint( *line.midPoint() ) if doCircles: for arc in path.arcs: if arc.circular: gi = PathSelectionGraphicsItem() gi.setPath( arc.svgPath() ) postProcessGraphicsItem( gi, {'x': arc.c_x,'y': arc.c_y,'r': arc.r*scaling, 'largeArc': arc.largeArc, 'sweep': arc.sweep, } ) if doFittedCircles: for bezierCurve in path.bezierCurves: x, y, r, r_error = bezierCurve.fitCircle() if r_error < 10**-4: gi = PathSelectionGraphicsItem() gi.setPath( bezierCurve.svgPath() ) postProcessGraphicsItem( gi, {'x':x,'y':y,'r':r} ) if doPathEndPoints and len(path.points) > 0: addSelectionPoint ( path.points[-1].x, path.points[-1].y ) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None and len(path.points) > 0: SelectViewObjectPoint_loc = path.points[-1].x, path.points[-1].y if element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) if doPoints: addSelectionPoint ( x1, y1 ) addSelectionPoint ( x2, y2 ) if doLines: graphicsItem = LineSelectionGraphicsItem( x1, y1, x2, y2 ) postProcessGraphicsItem(graphicsItem, {'x1':x1,'y1':y1,'x2':x2,'y2':y2}) if doMidPoints: addSelectionPoint( (x1+x2)/2, (y1+y2)/2 ) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: #second check to textElementes preference SelectViewObjectPoint_loc = x2, y2 if doSelectViewObjectPoints and SelectViewObjectPoint_loc <> None: addSelectionPoint( *SelectViewObjectPoint_loc ) #if len(fitData) > 0: # x, y, r, r_error = fitCircle_to_path(fitData) # #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) # if r_error < 10**-4: # if doFittedCircles: # addCircle( x, y, r , r_error=r_error ) # if doPoints: # circlePoints( x, y, r, r) return graphicItems
def generateSelectionGraphicsItems( viewObjects, onClickFun, transform=None, sceneToAddTo=None, clearPreviousSelectionItems=True, doPoints=False, doTextItems=False, doLines=False, doCircles=False, doFittedCircles=False, doPathEndPoints=False, doMidPoints=False, doSelectViewObjectPoints=False, pointWid=1.0 , maskPen=defaultMaskPen , maskBrush=defaultMaskBrush, maskHoverPen=defaultMaskHoverPen ): if clearPreviousSelectionItems: if sceneToAddTo <> None: for gi in sceneToAddTo.items(): if isinstance(gi, CircleSelectionGraphicsItem): sceneToAddTo.removeItem(gi) del graphicItems[:] def postProcessGraphicsItem(gi, elementParms, zValue=0.99): gi.setBrush( maskBrush ) gi.setPen(maskPen) gi.selectionMaskPen = QtGui.QPen(maskPen) gi.selectionMaskHoverPen = QtGui.QPen(maskHoverPen) gi._onClickFun = onClickFun gi.elementParms = elementParms gi.elementXML = element #should be able to get from functions name space gi.elementViewObject = viewObject gi.setAcceptHoverEvents(True) gi.setCursor( QtCore.Qt.CrossCursor ) # http://qt-project.org/doc/qt-5/qt.html#CursorShape-enum ; may not work for lines ... gi.setZValue(zValue) if transform <> None: gi.setTransform( transform ) if sceneToAddTo <> None: sceneToAddTo.addItem(gi) graphicItems.append(gi) pointsAlreadyAdded = [] def addSelectionPoint( x, y, zValue=1.0 ): #common code if [x,y] in pointsAlreadyAdded: return pointsAlreadyAdded.append( [x,y] ) graphicsItem = PointSelectionGraphicsItem( x-pointWid, y-pointWid, 2*pointWid, 2*pointWid ) postProcessGraphicsItem(graphicsItem, {'x':x, 'y':y}, zValue) def addCircle( x, y, r, **extraKWs): graphicsItem = CircleSelectionGraphicsItem( x-r, y-r, 2*r, 2*r ) KWs = {'x':x,'y':y,'r':r} KWs.update(extraKWs) postProcessGraphicsItem(graphicsItem, KWs, zValue=1.01**-r ) #smaller circles on top def circlePoints( x, y, rx, ry ): addSelectionPoint ( x, y, 2 ) #Circle/ellipse center point addSelectionPoint ( x + rx, y, 2 ) #Circle/ellipse right quadrant point addSelectionPoint ( x - rx, y, 2 ) #Circle/ellipse left quadrant point addSelectionPoint ( x , y + ry, 2 ) #Circle/ellipse top quadrant point addSelectionPoint ( x , y - ry, 2 ) #Circle/ellipse bottom quadrant point for viewObject in viewObjects: if viewObject.ViewResult.strip() == '': continue XML_tree = SvgXMLTreeNode(viewObject.ViewResult,0) scaling = XML_tree.scaling() SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) r = float( element.parms['r'] )* scaling if doCircles: addCircle( x, y, r) if doPoints: circlePoints( x, y, r, r) if element.tag == 'ellipse': cx, cy = element.applyTransforms( float( element.parms['cx'] ), float( element.parms['cy'] ) ) rx, ry = float( element.parms['rx'] )* scaling, float( element.parms['ry'] )* scaling if doCircles: if rx == ry: addCircle( cx, cy, rx) if doPoints: circlePoints( cx, cy, rx, ry) if element.tag == 'text' and element.parms.has_key('x'): if doTextItems: addSelectionPoint( *element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) ) elif doSelectViewObjectPoints: addSelectionPoint( *element.applyTransforms( float( element.parms['x'] ), float( element.parms['y'] ) ) ) if element.tag == 'path': #https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d #print(element.XML) fitData = [] dParmsXML = element.parms['d'] #<spacing corrections> i = 0 while i < len(dParmsXML)-1: if dParmsXML[i] in 'MmLlACcQZz,' and dParmsXML[i+1] in '-.0123456789': dParmsXML = dParmsXML[:i+1] + ' ' + dParmsXML[i+1:] i = i + 1 #</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('MmLlACcQZz,'): 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: _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 j = j + 3 elif parms[j] in ['L','l','Z','z']: if parms[j] == 'L' or parms[j] == 'l': 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 ) j = j + 3 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 if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) if doLines: graphicsItem = LineSelectionGraphicsItem( pen_x, pen_y, end_x, end_y ) postProcessGraphicsItem(graphicsItem, {'x1':pen_x,'y1':pen_y,'x2':end_x,'y2':end_y}) if doMidPoints: addSelectionPoint( (pen_x+end_x)/2, (pen_y+end_y)/2 ) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y elif 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 = map( float, parms[j+1:j+1 + 7] ) end_x, end_y = element.applyTransforms( _end_x, _end_y ) if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) if rX==rY : _c_x, _c_y = findCircularArcCentrePoint( rX, _pen_x, _pen_y, _end_x, _end_y, largeArc==1, sweep==1 ) #do in untranformed co-ordinates as to preserve sweep flag if not numpy.isnan(_c_x): #if all went well findCircularArcCentrePoint c_x, c_y = element.applyTransforms( _c_x, _c_y ) r = rX * scaling if doCircles: #addCircle( c_x, c_y, r , largeArc=largeArc, sweep=sweep) gi = PathSelectionGraphicsItem() path = QtGui.QPainterPath(QtCore.QPointF(pen_x, pen_y)) #path.arcTo(c_x - r, c_y -r , 2*r, 2*r, angle_1, angle_CCW) #dont know what is up with this function so trying something else. for _p in pointsAlongCircularArc(rX, _pen_x, _pen_y, _end_x, _end_y, largeArc==1, sweep==1, noPoints=12): path.lineTo(* element.applyTransforms(*_p) ) gi.setPath(path) postProcessGraphicsItem( gi, {'x':c_x,'y':c_y,'r':r, 'largeArc':largeArc, 'sweep':sweep, } ) #if doPoints: # circlePoints( c_x, c_y, r, r) _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 = 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 = 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) ] if doFittedCircles: x, y, r, r_error = fitCircle_to_path([P]) #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) if r_error < 10**-4: gi = PathSelectionGraphicsItem() path = QtGui.QPainterPath(QtCore.QPointF(pen_x, pen_y)) if len(P) == 4: path.cubicTo( QtCore.QPointF(*P[1]), QtCore.QPointF(*P[2]), QtCore.QPointF(*P[3]) ) else: path.quadTo( QtCore.QPointF(*P[1]), QtCore.QPointF(*P[2]) ) gi.setPath(path) postProcessGraphicsItem( gi, {'x':x,'y':y,'r':r} ) end_x, end_y = P[-1] if doPoints: addSelectionPoint ( pen_x, pen_y ) addSelectionPoint ( end_x, end_y ) #fitData.append( P ) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y else: raise RuntimeError, 'unable to parse path "%s" with d parms %s' % (element.XML[element.pStart: element.pEnd], parms) if j > 0 and doPathEndPoints: addSelectionPoint ( pen_x, pen_y ) if j > 0 and doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: SelectViewObjectPoint_loc = pen_x, pen_y if element.tag == 'line': x1, y1 = element.applyTransforms( float( element.parms['x1'] ), float( element.parms['y1'] ) ) x2, y2 = element.applyTransforms( float( element.parms['x2'] ), float( element.parms['y2'] ) ) if doPoints: addSelectionPoint ( x1, y1 ) addSelectionPoint ( x2, y2 ) if doLines: graphicsItem = LineSelectionGraphicsItem( x1, y1, x2, y2 ) postProcessGraphicsItem(graphicsItem, {'x1':x1,'y1':y1,'x2':x2,'y2':y2}) if doMidPoints: addSelectionPoint( (x1+x2)/2, (y1+y2)/2 ) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: #second check to textElementes preference SelectViewObjectPoint_loc = x2,y2 if doSelectViewObjectPoints and SelectViewObjectPoint_loc <> None: addSelectionPoint( *SelectViewObjectPoint_loc ) #if len(fitData) > 0: # x, y, r, r_error = fitCircle_to_path(fitData) # #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) # if r_error < 10**-4: # if doFittedCircles: # addCircle( x, y, r , r_error=r_error ) # if doPoints: # circlePoints( x, y, r, r) return graphicItems
def export_via_dxfwrite(dxf_fn, V): from XMLlib import SvgXMLTreeNode from svgLib_dd import SvgTextParser, SvgPath, SvgPolygon from numpy import arctan2 from circleLib import fitCircle_to_path, findCircularArcCentrePoint, pointsAlongCircularArc from dxfwrite import DXFEngine as dxf drawing = dxf.drawing(dxf_fn) pageSvg = open(V.page.PageResult).read() XML_tree = SvgXMLTreeNode(pageSvg, 0) def yT(y): #y transform return 210 - y warningsShown = [] SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): clr_text = None if element.parms.has_key('fill'): clr_text = element.parms['fill'] elif element.parms.has_key('style'): for part in element.parms['style'].split(';'): if part.startswith('stroke:rgb('): clr_text = part[len('stroke:'):] if clr_text == None or clr_text == 'none' or not clr_text.startswith( 'rgb('): color_code = 0 else: #FreeCAD.Console.PrintMessage( "color text: %s\n" % clr_text ) r, g, b = [ int(v.strip()) for v in clr_text[len('rgb('):clr_text.find(')')].split(',') ] color_code = colorLookup(r, g, b)[0] if element.tag == 'circle': x, y = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) r = float(element.parms['r']) * element.scaling2() drawing.add(dxf.circle(r, (x, yT(y)), color=color_code)) elif element.tag == 'line': x1, y1 = element.applyTransforms(float(element.parms['x1']), float(element.parms['y1'])) x2, y2 = element.applyTransforms(float(element.parms['x2']), float(element.parms['y2'])) drawing.add(dxf.line((x1, yT(y1)), (x2, yT(y2)), color=color_code)) elif element.tag == 'text' and element.parms.has_key('x'): x, y = element.applyTransforms(float(element.parms['x']), float(element.parms['y'])) try: t = SvgTextParser(element.XML[element.pStart:element.pEnd]) drawing.add( dxf.text(t.text, insert=(x, yT(y)), height=t.height() * 0.8, rotation=t.rotation, layer='TEXTLAYER', color=color_code)) except ValueError, msg: FreeCAD.Console.PrintWarning( 'dxf_export: unable to convert text element "%s": %s, ignoring...\n' % (element.XML[element.pStart:element.pEnd], str(msg))) elif element.tag == 'path': #FreeCAD.Console.PrintMessage(element.parms['d']+'\n') path = SvgPath(element) for line in path.lines: drawing.add( dxf.line((line.x1, yT(line.y1)), (line.x2, yT(line.y2)), color=color_code)) for arc in path.arcs: if arc.circular: for r, center, angle1, angle2 in arc.dxfwrite_arc_parms( yT): drawing.add( dxf.arc(r, center, angle1, angle2, color=color_code)) else: for x1, y1, x2, y2 in arc.approximate_via_lines(12): drawing.add( dxf.line((x1, yT(y1)), (x2, yT(y2)), color=color_code)) for bezierCurve in path.bezierCurves: x, y, r, r_error = bezierCurve.fitCircle() if r_error < 10**-4: raise NotImplementedError drawing.add( dxf.arc(*bezierCurve.dxfwrite_arc_parms(x, y, r))) else: X, Y = bezierCurve.points_along_curve() for i in range(len(X) - 1): drawing.add( dxf.line((X[i], yT(Y[i])), (X[i + 1], yT(Y[i + 1])), color=color_code))
def generateSelectionGraphicsItems(viewObjects, onClickFun, transform=None, sceneToAddTo=None, clearPreviousSelectionItems=True, doPoints=False, doTextItems=False, doLines=False, doCircles=False, doFittedCircles=False, doPathEndPoints=False, doMidPoints=False, doSelectViewObjectPoints=True, pointWid=1.0, maskPen=defaultMaskPen, maskBrush=defaultMaskBrush, maskHoverPen=defaultMaskHoverPen): if clearPreviousSelectionItems: if sceneToAddTo <> None: for gi in sceneToAddTo.items(): if isinstance(gi, CircleSelectionGraphicsItem): sceneToAddTo.removeItem(gi) del graphicItems[:] def postProcessGraphicsItem(gi, elementParms, zValue=0.99): gi.setBrush(maskBrush) gi.setPen(maskPen) gi.selectionMaskPen = QtGui.QPen(maskPen) gi.selectionMaskHoverPen = QtGui.QPen(maskHoverPen) gi._onClickFun = onClickFun gi.elementParms = elementParms gi.elementXML = element #should be able to get from functions name space gi.elementViewObject = viewObject gi.setAcceptHoverEvents(True) gi.setCursor( QtCore.Qt.CrossCursor ) # http://qt-project.org/doc/qt-5/qt.html#CursorShape-enum ; may not work for lines ... gi.setZValue(zValue) if transform <> None: gi.setTransform(transform) if sceneToAddTo <> None: sceneToAddTo.addItem(gi) graphicItems.append(gi) pointsAlreadyAdded = [] def addSelectionPoint(x, y, zValue=1.0): #common code if [x, y] in pointsAlreadyAdded: return pointsAlreadyAdded.append([x, y]) graphicsItem = PointSelectionGraphicsItem(x - pointWid, y - pointWid, 2 * pointWid, 2 * pointWid) postProcessGraphicsItem(graphicsItem, {'x': x, 'y': y}, zValue) def addCircle(x, y, r, **extraKWs): graphicsItem = CircleSelectionGraphicsItem(x - r, y - r, 2 * r, 2 * r) KWs = {'x': x, 'y': y, 'r': r} KWs.update(extraKWs) postProcessGraphicsItem(graphicsItem, KWs, zValue=1.01**-r) #smaller circles on top def circlePoints(x, y, r): addSelectionPoint(x, y, 2) #Circle center point addSelectionPoint(x + r, y, 2) #Circle right quadrant point addSelectionPoint(x - r, y, 2) #Circle left quadrant point addSelectionPoint(x, y + r, 2) #Circle top quadrant point addSelectionPoint(x, y - r, 2) #Circle bottom quadrant point for viewObject in viewObjects: if viewObject.ViewResult.strip() == '': continue XML_tree = SvgXMLTreeNode(viewObject.ViewResult, 0) scaling = XML_tree.scaling() SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) r = float(element.parms['r']) * scaling if doCircles: addCircle(x, y, r) if doPoints: circlePoints(x, y, r) if element.tag == 'text' and element.parms.has_key('x'): if doTextItems: addSelectionPoint(*element.applyTransforms( float(element.parms['x']), float(element.parms['y']))) elif doSelectViewObjectPoints: addSelectionPoint(*element.applyTransforms( float(element.parms['x']), float(element.parms['y']))) if element.tag == 'path': #https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d #print(element.XML) fitData = [] dParmsXML = element.parms['d'] #<spacing corrections> i = 0 while i < len(dParmsXML) - 1: if dParmsXML[i] in 'MmLlACcQZz,' and dParmsXML[ i + 1] in '-.0123456789': dParmsXML = dParmsXML[:i + 1] + ' ' + dParmsXML[i + 1:] i = i + 1 #</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('MmLlACcQZz,'): 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: _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 j = j + 3 elif parms[j] in ['L', 'l', 'Z', 'z']: if parms[j] == 'L' or parms[j] == 'l': 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) j = j + 3 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 if doPoints: addSelectionPoint(pen_x, pen_y) addSelectionPoint(end_x, end_y) if doLines: graphicsItem = LineSelectionGraphicsItem( pen_x, pen_y, end_x, end_y) postProcessGraphicsItem(graphicsItem, { 'x1': pen_x, 'y1': pen_y, 'x2': end_x, 'y2': end_y }) if doMidPoints: addSelectionPoint((pen_x + end_x) / 2, (pen_y + end_y) / 2) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y elif 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 = map( float, parms[j + 1:j + 1 + 7]) end_x, end_y = element.applyTransforms(_end_x, _end_y) if doPoints: addSelectionPoint(pen_x, pen_y) addSelectionPoint(end_x, end_y) if rX == rY: _c_x, _c_y = findCircularArcCentrePoint( rX, _pen_x, _pen_y, _end_x, _end_y, largeArc == 1, sweep == 1 ) #do in untranformed co-ordinates as to preserve sweep flag if not numpy.isnan( _c_x ): #if all went well findCircularArcCentrePoint c_x, c_y = element.applyTransforms(_c_x, _c_y) r = rX * scaling if doCircles: #addCircle( c_x, c_y, r , largeArc=largeArc, sweep=sweep) gi = PathSelectionGraphicsItem() path = QtGui.QPainterPath( QtCore.QPointF(pen_x, pen_y)) #path.arcTo(c_x - r, c_y -r , 2*r, 2*r, angle_1, angle_CCW) #dont know what is up with this function so trying something else. for _p in pointsAlongCircularArc( rX, _pen_x, _pen_y, _end_x, _end_y, largeArc == 1, sweep == 1, noPoints=12): path.lineTo(*element.applyTransforms( *_p)) gi.setPath(path) postProcessGraphicsItem( gi, { 'x': c_x, 'y': c_y, 'r': r, 'largeArc': largeArc, 'sweep': sweep, }) #if doPoints: # circlePoints( c_x, c_y, r) _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 = 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 = 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)] if doFittedCircles or True: x, y, r, r_error = fitCircle_to_path([P]) #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) if r_error < 10**-4: gi = PathSelectionGraphicsItem() path = QtGui.QPainterPath( QtCore.QPointF(pen_x, pen_y)) if len(P) == 4: path.cubicTo(QtCore.QPointF(*P[1]), QtCore.QPointF(*P[2]), QtCore.QPointF(*P[3])) else: path.quadTo(QtCore.QPointF(*P[1]), QtCore.QPointF(*P[2])) gi.setPath(path) postProcessGraphicsItem( gi, { 'x': x, 'y': y, 'r': r }) end_x, end_y = P[-1] if doPoints: addSelectionPoint(pen_x, pen_y) addSelectionPoint(end_x, end_y) #fitData.append( P ) _pen_x, _pen_y = _end_x, _end_y pen_x, pen_y = end_x, end_y else: raise RuntimeError, 'unable to parse path "%s" with d parms %s' % ( element.XML[element.pStart:element.pEnd], parms) if j > 0 and doPathEndPoints: addSelectionPoint(pen_x, pen_y) if j > 0 and doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: SelectViewObjectPoint_loc = pen_x, pen_y if element.tag == 'line': x1, y1 = element.applyTransforms(float(element.parms['x1']), float(element.parms['y1'])) x2, y2 = element.applyTransforms(float(element.parms['x2']), float(element.parms['y2'])) if doPoints: addSelectionPoint(x1, y1) addSelectionPoint(x2, y2) if doLines: graphicsItem = LineSelectionGraphicsItem(x1, y1, x2, y2) postProcessGraphicsItem(graphicsItem, { 'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2 }) if doMidPoints: addSelectionPoint((x1 + x2) / 2, (y1 + y2) / 2) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: #second check to textElementes preference SelectViewObjectPoint_loc = x2, y2 if doSelectViewObjectPoints and SelectViewObjectPoint_loc <> None: addSelectionPoint(*SelectViewObjectPoint_loc) #if len(fitData) > 0: # x, y, r, r_error = fitCircle_to_path(fitData) # #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) # if r_error < 10**-4: # if doFittedCircles: # addCircle( x, y, r , r_error=r_error ) # if doPoints: # circlePoints( x, y, r) return graphicItems
def generateSelectionGraphicsItems(viewObjects, onClickFun, transform=None, sceneToAddTo=None, clearPreviousSelectionItems=True, doPoints=False, doTextItems=False, doLines=False, doCircles=False, doFittedCircles=False, doPathEndPoints=False, doMidPoints=False, doSelectViewObjectPoints=False, doEllipses=False, doArcCenters=True, pointWid=1.0, maskPen=defaultMaskPen, maskBrush=defaultMaskBrush, maskHoverPen=defaultMaskHoverPen): if clearPreviousSelectionItems: if sceneToAddTo <> None: for gi in sceneToAddTo.items(): if isinstance(gi, CircleSelectionGraphicsItem): sceneToAddTo.removeItem(gi) del graphicItems[:] def postProcessGraphicsItem(gi, elementParms, zValue=0.99): gi.setBrush(maskBrush) gi.setPen(maskPen) gi.selectionMaskPen = QtGui.QPen(maskPen) gi.selectionMaskHoverPen = QtGui.QPen(maskHoverPen) gi._onClickFun = onClickFun gi.elementParms = elementParms gi.elementXML = element #should be able to get from functions name space gi.elementViewObject = viewObject gi.setAcceptHoverEvents(True) gi.setCursor( QtCore.Qt.CrossCursor ) # http://qt-project.org/doc/qt-5/qt.html#CursorShape-enum ; may not work for lines ... gi.setZValue(zValue) if transform <> None: gi.setTransform(transform) if sceneToAddTo <> None: sceneToAddTo.addItem(gi) graphicItems.append(gi) pointsAlreadyAdded = [] def addSelectionPoint(x, y, zValue=1.0): #common code if [x, y] in pointsAlreadyAdded: return pointsAlreadyAdded.append([x, y]) graphicsItem = PointSelectionGraphicsItem(x - pointWid, y - pointWid, 2 * pointWid, 2 * pointWid) postProcessGraphicsItem(graphicsItem, {'x': x, 'y': y}, zValue) def addCircle(x, y, r, **extraKWs): graphicsItem = CircleSelectionGraphicsItem(x - r, y - r, 2 * r, 2 * r) KWs = {'x': x, 'y': y, 'r': r} KWs.update(extraKWs) postProcessGraphicsItem(graphicsItem, KWs, zValue=1.01**-r) #smaller circles on top def circlePoints(x, y, rx, ry): addSelectionPoint(x, y, 2) #Circle/ellipse center point addSelectionPoint(x + rx, y, 2) #Circle/ellipse right quadrant point addSelectionPoint(x - rx, y, 2) #Circle/ellipse left quadrant point addSelectionPoint(x, y + ry, 2) #Circle/ellipse top quadrant point addSelectionPoint(x, y - ry, 2) #Circle/ellipse bottom quadrant point for viewObject in viewObjects: if not hasattr(viewObject, 'ViewResult'): continue if viewObject.ViewResult.strip() == '': continue DrawingsViews_info[viewObject.Name] = DrawingViewInfo(viewObject) viewInfo = DrawingsViews_info[viewObject.Name] #shorthand XML_tree = SvgXMLTreeNode(viewObject.ViewResult, 0) scaling = XML_tree.scaling() viewInfo.scale = scaling SelectViewObjectPoint_loc = None for element in XML_tree.getAllElements(): if element.tag == 'circle': x, y = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) r = float(element.parms['r']) * scaling if doCircles: addCircle(x, y, r) if doPoints: circlePoints(x, y, r, r) viewInfo.updateBounds_ellipse(x, y, r, r) if element.tag == 'ellipse': cx, cy = element.applyTransforms(float(element.parms['cx']), float(element.parms['cy'])) rx, ry = float(element.parms['rx']) * scaling, float( element.parms['ry']) * scaling if doCircles: if rx == ry: addCircle(cx, cy, rx) if doEllipses: raise NotImplemented if doPoints: circlePoints(cx, cy, rx, ry) viewInfo.updateBounds_ellipse(cx, cy, rx, ry) if element.tag == 'text' and element.parms.has_key('x'): if doTextItems: addSelectionPoint(*element.applyTransforms( float(element.parms['x']), float(element.parms['y']))) elif doSelectViewObjectPoints: addSelectionPoint(*element.applyTransforms( float(element.parms['x']), float(element.parms['y']))) if element.tag == 'path': path = SvgPath(element) for p in path.points: if doPoints: addSelectionPoint(p.x, p.y) viewInfo.updateBounds(p.x, p.y) if doLines: for line in path.lines: x1, y1, x2, y2 = line.x1, line.y1, line.x2, line.y2 graphicsItem = LineSelectionGraphicsItem( x1, y1, x2, y2) postProcessGraphicsItem(graphicsItem, { 'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2 }) if doMidPoints: for line in path.lines: addSelectionPoint(*line.midPoint()) for arc in path.arcs: if doCircles or doEllipses: if arc.circular: gi = PathSelectionGraphicsItem() gi.setPath(arc.QPainterPath()) postProcessGraphicsItem( gi, { 'x': arc.center[0], 'y': arc.center[1], 'r': arc.r * scaling, 'arcPickle': pickle.dumps(arc) }) elif doEllipses: gi = PathSelectionGraphicsItem() gi.setPath(arc.QPainterPath()) postProcessGraphicsItem( gi, { 'x': arc.center[0], 'y': arc.center[1], 'arcPickle': pickle.dumps(arc) }) if doPoints and doArcCenters: addSelectionPoint(arc.center[0], arc.center[1], 2) if doFittedCircles: for bezierCurve in path.bezierCurves: x, y, r, r_error = bezierCurve.fitCircle() if r_error < 10**-4: gi = PathSelectionGraphicsItem() gi.setPath(bezierCurve.QPainterPath()) postProcessGraphicsItem(gi, { 'x': x, 'y': y, 'r': r }) if doPathEndPoints and len(path.points) > 0: addSelectionPoint(path.points[-1].x, path.points[-1].y) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None and len( path.points) > 0: SelectViewObjectPoint_loc = path.points[-1].x, path.points[ -1].y if element.tag == 'line': x1, y1 = element.applyTransforms(float(element.parms['x1']), float(element.parms['y1'])) x2, y2 = element.applyTransforms(float(element.parms['x2']), float(element.parms['y2'])) if doPoints: addSelectionPoint(x1, y1) addSelectionPoint(x2, y2) viewInfo.updateBounds(x1, y1) viewInfo.updateBounds(x1, y2) if doLines: graphicsItem = LineSelectionGraphicsItem(x1, y1, x2, y2) postProcessGraphicsItem(graphicsItem, { 'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2 }) if doMidPoints: addSelectionPoint((x1 + x2) / 2, (y1 + y2) / 2) if doSelectViewObjectPoints and SelectViewObjectPoint_loc == None: #second check to textElementes preference SelectViewObjectPoint_loc = x2, y2 if doSelectViewObjectPoints and SelectViewObjectPoint_loc <> None: addSelectionPoint(*SelectViewObjectPoint_loc) #if len(fitData) > 0: # x, y, r, r_error = fitCircle_to_path(fitData) # #print('fittedCircle: x, y, r, r_error', x, y, r, r_error) # if r_error < 10**-4: # if doFittedCircles: # addCircle( x, y, r , r_error=r_error ) # if doPoints: # circlePoints( x, y, r, r) return graphicItems