class SVGReader: "An svg carving." def __init__( self ): "Add empty lists." self.bridgeRotation = None self.rotatedLoopLayers = [] self.stopProcessing = False self.z = 0.0 def flipDirectLayer(self, rotatedLoopLayer): "Flip the y coordinate of the layer and direct the loops." for loop in rotatedLoopLayer.loops: for pointIndex, point in enumerate(loop): loop[pointIndex] = complex(point.real, -point.imag) rotatedLoopLayer.loops = trianglemesh.getLoopsInOrderOfArea(trianglemesh.compareAreaDescending, rotatedLoopLayer.loops) for loopIndex, loop in enumerate(rotatedLoopLayer.loops): isInsideLoops = euclidean.isPointInsideLoopsZone(rotatedLoopLayer.loops[: loopIndex], euclidean.getLeftPoint(loop)) booleansolid.directLoop((not isInsideLoops), loop) def getRotatedLoopLayer( self ): "Return the rotated loop layer." if self.z != None: rotatedLoopLayer = euclidean.RotatedLoopLayer( self.z ) self.rotatedLoopLayers.append( rotatedLoopLayer ) rotatedLoopLayer.rotation = self.bridgeRotation self.z = None return self.rotatedLoopLayers[ - 1 ] def parseSVG( self, fileName, svgText ): "Parse SVG text and store the layers." self.fileName = fileName self.xmlParser = XMLSimpleReader(fileName, None, svgText) self.sliceDictionary = svg_writer.getSliceDictionary( self.xmlParser.getRoot() ) self.yAxisPointingUpward = euclidean.getBooleanFromDictionaryDefault(False, self.sliceDictionary, 'yAxisPointingUpward') self.processXMLElement( self.xmlParser.getRoot() ) if not self.yAxisPointingUpward: for rotatedLoopLayer in self.rotatedLoopLayers: self.flipDirectLayer(rotatedLoopLayer) def processXMLElement( self, xmlElement ): "Process the xml element." if self.stopProcessing: return lowerClassName = xmlElement.className.lower() global globalProcessSVGElementDictionary if lowerClassName in globalProcessSVGElementDictionary: try: globalProcessSVGElementDictionary[ lowerClassName ]( self, xmlElement ) except: print('Warning, in processXMLElement in svg_reader, could not process:') print(xmlElement) traceback.print_exc( file = sys.stdout ) for child in xmlElement.children: self.processXMLElement( child )
class FontReader: "Class to read a font in the fonts folder." def __init__(self, fontFamily): "Initialize." self.fontFamily = fontFamily self.glyphDictionary = {} self.glyphXMLElementDictionary = {} self.missingGlyph = None fileName = os.path.join(getFontsDirectoryPath(), fontFamily + '.svg') self.xmlParser = XMLSimpleReader(fileName, None, archive.getFileText(fileName)) self.fontXMLElement = self.xmlParser.getRoot().getFirstChildWithClassName('defs').getFirstChildWithClassName('font') self.fontFaceXMLElement = self.fontXMLElement.getFirstChildWithClassName('font-face') self.unitsPerEM = float(self.fontFaceXMLElement.attributeDictionary['units-per-em']) glyphXMLElements = self.fontXMLElement.getChildrenWithClassName('glyph') for glyphXMLElement in glyphXMLElements: self.glyphXMLElementDictionary[glyphXMLElement.attributeDictionary['unicode']] = glyphXMLElement def getGlyph(self, character, yAxisPointingUpward): "Get the glyph for the character." if character not in self.glyphXMLElementDictionary: if self.missingGlyph == None: missingGlyphXMLElement = self.fontXMLElement.getFirstChildWithClassName('missing-glyph') self.missingGlyph = Glyph(self.unitsPerEM, missingGlyphXMLElement, yAxisPointingUpward) return self.missingGlyph if character not in self.glyphDictionary: self.glyphDictionary[character] = Glyph(self.unitsPerEM, self.glyphXMLElementDictionary[character], yAxisPointingUpward) return self.glyphDictionary[character]
class FontReader: "Class to read a font in the fonts folder." def __init__(self, fontFamily): "Initialize." self.fontFamily = fontFamily self.glyphDictionary = {} self.glyphXMLElementDictionary = {} self.missingGlyph = None fileName = os.path.join(getFontsDirectoryPath(), fontFamily + '.svg') self.xmlParser = XMLSimpleReader(fileName, None, gcodec.getFileText(fileName)) self.fontXMLElement = self.xmlParser.getRoot().getFirstChildWithClassName('defs').getFirstChildWithClassName('font') self.fontFaceXMLElement = self.fontXMLElement.getFirstChildWithClassName('font-face') self.unitsPerEM = float(self.fontFaceXMLElement.attributeDictionary['units-per-em']) glyphXMLElements = self.fontXMLElement.getChildrenWithClassName('glyph') for glyphXMLElement in glyphXMLElements: self.glyphXMLElementDictionary[glyphXMLElement.attributeDictionary['unicode']] = glyphXMLElement def getGlyph(self, character, yAxisPointingUpward): "Get the glyph for the character." if character not in self.glyphXMLElementDictionary: if self.missingGlyph == None: missingGlyphXMLElement = self.fontXMLElement.getFirstChildWithClassName('missing-glyph') self.missingGlyph = Glyph(self.unitsPerEM, missingGlyphXMLElement, yAxisPointingUpward) return self.missingGlyph if character not in self.glyphDictionary: self.glyphDictionary[character] = Glyph(self.unitsPerEM, self.glyphXMLElementDictionary[character], yAxisPointingUpward) return self.glyphDictionary[character]
def parseSVG(self, fileName, svgText): "Parse SVG text and store the layers." self.fileName = fileName xmlParser = XMLSimpleReader(fileName, None, svgText) self.root = xmlParser.getRoot() if self.root == None: print('Warning, root was None in parseSVG in SVGReader, so nothing will be done for:') print(fileName) return self.parseSVGByXMLElement(self.root)
def getCarving( fileName = ''): "Get the carving for the xml file." xmlText = gcodec.getFileText( fileName ) if xmlText == '': return None xmlParser = XMLSimpleReader( fileName, None, xmlText ) lowerClassName = xmlParser.getRoot().className.lower() pluginModule = gcodec.getModuleWithDirectoryPath( getPluginsDirectoryPath(), lowerClassName ) if pluginModule == None: return None return pluginModule.getCarvingFromParser( xmlParser )
def getCarving(fileName=''): "Get the carving for the xml file." xmlText = archive.getFileText(fileName) if xmlText == '': return None xmlParser = XMLSimpleReader( fileName, None, xmlText ) lowerClassName = xmlParser.getRoot().className.lower() pluginModule = archive.getModuleWithDirectoryPath( getPluginsDirectoryPath(), lowerClassName ) if pluginModule == None: return None return pluginModule.getCarvingFromParser( xmlParser )
def parseSVG(self, fileName, svgText): "Parse SVG text and store the layers." self.fileName = fileName xmlParser = XMLSimpleReader(fileName, None, svgText) self.root = xmlParser.getRoot() if self.root == None: print( 'Warning, root was None in parseSVG in SVGReader, so nothing will be done for:' ) print(fileName) return self.parseSVGByXMLElement(self.root)
def getCraftedGcode(self, fileName, repository, svgText): "Parse svgText and store the bottom svgText." xmlParser = XMLSimpleReader(fileName, None, svgText) root = xmlParser.getRoot() sliceElements = getSliceElements(root) sliceDictionary = svg_writer.getSliceDictionary(root) decimalPlacesCarried = int(sliceDictionary['decimalPlacesCarried']) layerThickness = float(sliceDictionary['layerThickness']) procedures = sliceDictionary['procedureDone'].split(',') procedures.append('bottom') sliceDictionary['procedureDone'] = ','.join(procedures) zMinimum = 987654321.0 for sliceElement in sliceElements: zMinimum = min(getSliceElementZ(sliceElement), zMinimum) deltaZ = repository.altitude.value + 0.5 * layerThickness - zMinimum for sliceElementIndex, sliceElement in enumerate(sliceElements): z = getSliceElementZ(sliceElement) + deltaZ setSliceElementZ(decimalPlacesCarried, sliceElement, sliceElementIndex, z) output = cStringIO.StringIO() root.addXML(0, output) return output.getvalue()
class SVGWriter: 'A base class to get an svg skein from a carving.' def __init__(self, addLayerTemplateToSVG, cornerMaximum, cornerMinimum, decimalPlacesCarried, layerThickness, perimeterWidth=None): 'Initialize.' self.addLayerTemplateToSVG = addLayerTemplateToSVG self.cornerMaximum = cornerMaximum self.cornerMinimum = cornerMinimum self.decimalPlacesCarried = decimalPlacesCarried self.layerThickness = layerThickness self.perimeterWidth = perimeterWidth self.textHeight = 22.5 self.unitScale = 3.7 def addLayerBegin(self, layerIndex, rotatedLoopLayer): 'Add the start lines for the layer.' zRounded = self.getRounded(rotatedLoopLayer.z) self.graphicsCopy = self.graphicsXMLElement.getCopy( zRounded, self.graphicsXMLElement.parentNode) if self.addLayerTemplateToSVG: translateXRounded = self.getRounded(self.controlBoxWidth + self.margin + self.margin) layerTranslateY = self.marginTop layerTranslateY += layerIndex * self.textHeight + ( layerIndex + 1) * (self.extent.y * self.unitScale + self.margin) translateYRounded = self.getRounded(layerTranslateY) self.graphicsCopy.attributeDictionary[ 'transform'] = 'translate(%s, %s)' % (translateXRounded, translateYRounded) layerString = 'Layer %s, z:%s' % (layerIndex, zRounded) self.graphicsCopy.getFirstChildByLocalName( 'text').text = layerString self.graphicsCopy.attributeDictionary[ 'inkscape:groupmode'] = 'layer' self.graphicsCopy.attributeDictionary[ 'inkscape:label'] = layerString self.pathXMLElement = self.graphicsCopy.getFirstChildByLocalName( 'path') self.pathDictionary = self.pathXMLElement.attributeDictionary def addOriginalAsComment(self, xmlElement): 'Add original xmlElement as a comment.' if xmlElement == None: return if xmlElement.localName == 'comment': xmlElement.setParentAddToChildNodes(self.svgElement) return commentElement = xml_simple_reader.XMLElement() commentElement.localName = 'comment' xmlElementOutput = cStringIO.StringIO() xmlElement.addXML(0, xmlElementOutput) textLines = archive.getTextLines(xmlElementOutput.getvalue()) commentElementOutput = cStringIO.StringIO() isComment = False for textLine in textLines: lineStripped = textLine.strip() if lineStripped[:len('<!--')] == '<!--': isComment = True if not isComment: if len(textLine) > 0: commentElementOutput.write(textLine + '\n') if '-->' in lineStripped: isComment = False commentElement.text = '%s%s-->\n' % (globalOriginalTextString, commentElementOutput.getvalue()) commentElement.setParentAddToChildNodes(self.svgElement) def addRotatedLoopLayerToOutput(self, layerIndex, rotatedLoopLayer): 'Add rotated boundary layer to the output.' self.addLayerBegin(layerIndex, rotatedLoopLayer) if rotatedLoopLayer.rotation != None: self.graphicsCopy.attributeDictionary['bridgeRotation'] = str( rotatedLoopLayer.rotation) if self.addLayerTemplateToSVG: self.pathDictionary['transform'] = self.getTransformString() else: del self.pathDictionary['transform'] self.pathDictionary['d'] = self.getSVGStringForLoops( rotatedLoopLayer.loops) def addRotatedLoopLayersToOutput(self, rotatedLoopLayers): 'Add rotated boundary layers to the output.' for rotatedLoopLayerIndex, rotatedLoopLayer in enumerate( rotatedLoopLayers): self.addRotatedLoopLayerToOutput(rotatedLoopLayerIndex, rotatedLoopLayer) def getReplacedSVGTemplate(self, fileName, procedureName, rotatedLoopLayers, xmlElement=None): 'Get the lines of text from the layer_template.svg file.' self.extent = self.cornerMaximum - self.cornerMinimum svgTemplateText = archive.getFileText( archive.getTemplatesPath('layer_template.svg')) self.xmlParser = XMLSimpleReader(fileName, None, svgTemplateText) self.svgElement = self.xmlParser.getRoot() svgElementDictionary = self.svgElement.attributeDictionary self.sliceDictionary = getSliceDictionary(self.svgElement) self.controlBoxHeight = float(self.sliceDictionary['controlBoxHeight']) self.controlBoxWidth = float(self.sliceDictionary['controlBoxWidth']) self.margin = float(self.sliceDictionary['margin']) self.marginTop = float(self.sliceDictionary['marginTop']) self.textHeight = float(self.sliceDictionary['textHeight']) self.unitScale = float(self.sliceDictionary['unitScale']) svgMinWidth = float(self.sliceDictionary['svgMinWidth']) self.controlBoxHeightMargin = self.controlBoxHeight + self.marginTop if not self.addLayerTemplateToSVG: self.svgElement.getXMLElementByID( 'layerTextTemplate').removeFromIDNameParent() del self.svgElement.getXMLElementByID( 'sliceElementTemplate').attributeDictionary['transform'] self.graphicsXMLElement = self.svgElement.getXMLElementByID( 'sliceElementTemplate') self.graphicsXMLElement.attributeDictionary['id'] = 'z:' self.addRotatedLoopLayersToOutput(rotatedLoopLayers) self.setMetadataNoscriptElement('layerThickness', 'Layer Thickness: ', self.layerThickness) self.setMetadataNoscriptElement('maxX', 'X: ', self.cornerMaximum.x) self.setMetadataNoscriptElement('minX', 'X: ', self.cornerMinimum.x) self.setMetadataNoscriptElement('maxY', 'Y: ', self.cornerMaximum.y) self.setMetadataNoscriptElement('minY', 'Y: ', self.cornerMinimum.y) self.setMetadataNoscriptElement('maxZ', 'Z: ', self.cornerMaximum.z) self.setMetadataNoscriptElement('minZ', 'Z: ', self.cornerMinimum.z) self.textHeight = float(self.sliceDictionary['textHeight']) controlTop = len(rotatedLoopLayers) * ( self.margin + self.extent.y * self.unitScale + self.textHeight) + self.marginTop + self.textHeight self.svgElement.getFirstChildByLocalName( 'title').text = os.path.basename(fileName) + ' - Slice Layers' svgElementDictionary['height'] = '%spx' % self.getRounded( max(controlTop, self.controlBoxHeightMargin)) width = max(self.extent.x * self.unitScale, svgMinWidth) svgElementDictionary['width'] = '%spx' % self.getRounded(width) self.sliceDictionary['decimalPlacesCarried'] = str( self.decimalPlacesCarried) if self.perimeterWidth != None: self.sliceDictionary['perimeterWidth'] = self.getRounded( self.perimeterWidth) self.sliceDictionary['yAxisPointingUpward'] = 'true' self.sliceDictionary['procedureName'] = procedureName self.setDimensionTexts('dimX', 'X: ' + self.getRounded(self.extent.x)) self.setDimensionTexts('dimY', 'Y: ' + self.getRounded(self.extent.y)) self.setDimensionTexts('dimZ', 'Z: ' + self.getRounded(self.extent.z)) self.setTexts('numberOfLayers', 'Number of Layers: %s' % len(rotatedLoopLayers)) volume = 0.0 for rotatedLoopLayer in rotatedLoopLayers: volume += euclidean.getAreaLoops(rotatedLoopLayer.loops) volume *= 0.001 self.setTexts('volume', 'Volume: %s cm3' % self.getRounded(volume)) if not self.addLayerTemplateToSVG: self.svgElement.getFirstChildByLocalName( 'script').removeFromIDNameParent() self.svgElement.getXMLElementByID( 'isoControlBox').removeFromIDNameParent() self.svgElement.getXMLElementByID( 'layerControlBox').removeFromIDNameParent() self.svgElement.getXMLElementByID( 'scrollControlBox').removeFromIDNameParent() self.graphicsXMLElement.removeFromIDNameParent() self.addOriginalAsComment(xmlElement) output = cStringIO.StringIO() output.write(self.xmlParser.beforeRoot) self.svgElement.addXML(0, output) return xml_simple_writer.getBeforeRootOutput(self.xmlParser) def getRounded(self, number): 'Get number rounded to the number of carried decimal places as a string.' return euclidean.getRoundedToPlacesString(self.decimalPlacesCarried, number) def getRoundedComplexString(self, point): 'Get the rounded complex string.' return self.getRounded(point.real) + ' ' + self.getRounded(point.imag) def getSVGStringForLoop(self, loop): 'Get the svg loop string.' if len(loop) < 1: return '' return self.getSVGStringForPath(loop) + ' z' def getSVGStringForLoops(self, loops): 'Get the svg loops string.' loopString = '' if len(loops) > 0: loopString += self.getSVGStringForLoop(loops[0]) for loop in loops[1:]: loopString += ' ' + self.getSVGStringForLoop(loop) return loopString def getSVGStringForPath(self, path): 'Get the svg path string.' svgLoopString = '' for point in path: stringBeginning = 'M ' if len(svgLoopString) > 0: stringBeginning = ' L ' svgLoopString += stringBeginning + self.getRoundedComplexString( point) return svgLoopString def setMetadataNoscriptElement(self, key, prefix, value): 'Set the metadata value and the text.' valueString = self.getRounded(value) self.sliceDictionary[key] = valueString self.setDimensionTexts(key, prefix + valueString) def setDimensionTexts(self, key, valueString): 'Set the texts to the valueString followed by mm.' self.setTexts(key, valueString + ' mm') def setTexts(self, key, valueString): 'Set the texts to the valueString.' self.svgElement.getXMLElementByID(key + 'Iso').text = valueString self.svgElement.getXMLElementByID(key + 'Layer').text = valueString self.svgElement.getXMLElementByID(key + 'Scroll').text = valueString def getTransformString(self): 'Get the svg transform string.' cornerMinimumXString = self.getRounded(-self.cornerMinimum.x) cornerMinimumYString = self.getRounded(-self.cornerMinimum.y) return 'scale(%s, %s) translate(%s, %s)' % ( self.unitScale, -self.unitScale, cornerMinimumXString, cornerMinimumYString)
class SVGWriter: 'A base class to get an svg skein from a carving.' def __init__(self, addLayerTemplateToSVG, cornerMaximum, cornerMinimum, decimalPlacesCarried, layerThickness, perimeterWidth=None): 'Initialize.' self.addLayerTemplateToSVG = addLayerTemplateToSVG self.cornerMaximum = cornerMaximum self.cornerMinimum = cornerMinimum self.decimalPlacesCarried = decimalPlacesCarried self.layerThickness = layerThickness self.perimeterWidth = perimeterWidth self.textHeight = 22.5 self.unitScale = 3.7 def addLayerBegin(self, layerIndex, rotatedLoopLayer): 'Add the start lines for the layer.' zRounded = self.getRounded(rotatedLoopLayer.z) self.graphicsCopy = self.graphicsXMLElement.getCopy(zRounded, self.graphicsXMLElement.parent) if self.addLayerTemplateToSVG: translateXRounded = self.getRounded(self.controlBoxWidth + self.margin + self.margin) layerTranslateY = self.marginTop layerTranslateY += layerIndex * self.textHeight + (layerIndex + 1) * (self.extent.y * self.unitScale + self.margin) translateYRounded = self.getRounded(layerTranslateY) self.graphicsCopy.attributeDictionary['transform'] = 'translate(%s, %s)' % (translateXRounded, translateYRounded) layerString = 'Layer %s, z:%s' % (layerIndex, zRounded) self.graphicsCopy.getFirstChildWithClassName('text').text = layerString self.graphicsCopy.attributeDictionary['inkscape:groupmode'] = 'layer' self.graphicsCopy.attributeDictionary['inkscape:label'] = layerString self.pathXMLElement = self.graphicsCopy.getFirstChildWithClassName('path') self.pathDictionary = self.pathXMLElement.attributeDictionary def addOriginalAsComment(self, xmlElement): 'Add original xmlElement as a comment.' if xmlElement == None: return if xmlElement.className == 'comment': xmlElement.setParentAddToChildren(self.svgElement) return commentElement = xml_simple_reader.XMLElement() commentElement.className = 'comment' xmlElementOutput = cStringIO.StringIO() xmlElement.addXML(0, xmlElementOutput) textLines = archive.getTextLines(xmlElementOutput.getvalue()) commentElementOutput = cStringIO.StringIO() isComment = False for textLine in textLines: lineStripped = textLine.strip() if lineStripped[: len('<!--')] == '<!--': isComment = True if not isComment: if len(textLine) > 0: commentElementOutput.write(textLine + '\n') if '-->' in lineStripped: isComment = False commentElement.text = '%s%s-->\n' % (globalOriginalTextString, commentElementOutput.getvalue()) commentElement.setParentAddToChildren(self.svgElement) def addRotatedLoopLayerToOutput(self, layerIndex, rotatedLoopLayer): 'Add rotated boundary layer to the output.' self.addLayerBegin(layerIndex, rotatedLoopLayer) if rotatedLoopLayer.rotation != None: self.graphicsCopy.attributeDictionary['bridgeRotation'] = str(rotatedLoopLayer.rotation) if self.addLayerTemplateToSVG: self.pathDictionary['transform'] = self.getTransformString() else: del self.pathDictionary['transform'] self.pathDictionary['d'] = self.getSVGStringForLoops(rotatedLoopLayer.loops) def addRotatedLoopLayersToOutput(self, rotatedLoopLayers): 'Add rotated boundary layers to the output.' for rotatedLoopLayerIndex, rotatedLoopLayer in enumerate(rotatedLoopLayers): self.addRotatedLoopLayerToOutput(rotatedLoopLayerIndex, rotatedLoopLayer) def getReplacedSVGTemplate(self, fileName, procedureName, rotatedLoopLayers, xmlElement=None): 'Get the lines of text from the layer_template.svg file.' self.extent = self.cornerMaximum - self.cornerMinimum svgTemplateText = archive.getFileText(archive.getTemplatesPath('layer_template.svg')) self.xmlParser = XMLSimpleReader( fileName, None, svgTemplateText ) self.svgElement = self.xmlParser.getRoot() svgElementDictionary = self.svgElement.attributeDictionary self.sliceDictionary = getSliceDictionary(self.svgElement) self.controlBoxHeight = float(self.sliceDictionary['controlBoxHeight']) self.controlBoxWidth = float(self.sliceDictionary['controlBoxWidth']) self.margin = float(self.sliceDictionary['margin']) self.marginTop = float(self.sliceDictionary['marginTop']) self.textHeight = float(self.sliceDictionary['textHeight']) self.unitScale = float(self.sliceDictionary['unitScale']) svgMinWidth = float(self.sliceDictionary['svgMinWidth']) self.controlBoxHeightMargin = self.controlBoxHeight + self.marginTop if not self.addLayerTemplateToSVG: self.svgElement.getXMLElementByID('layerTextTemplate').removeFromIDNameParent() del self.svgElement.getXMLElementByID('sliceElementTemplate').attributeDictionary['transform'] self.graphicsXMLElement = self.svgElement.getXMLElementByID('sliceElementTemplate') self.graphicsXMLElement.attributeDictionary['id'] = 'z:' self.addRotatedLoopLayersToOutput(rotatedLoopLayers) self.setMetadataNoscriptElement('layerThickness', 'Layer Thickness: ', self.layerThickness) self.setMetadataNoscriptElement('maxX', 'X: ', self.cornerMaximum.x) self.setMetadataNoscriptElement('minX', 'X: ', self.cornerMinimum.x) self.setMetadataNoscriptElement('maxY', 'Y: ', self.cornerMaximum.y) self.setMetadataNoscriptElement('minY', 'Y: ', self.cornerMinimum.y) self.setMetadataNoscriptElement('maxZ', 'Z: ', self.cornerMaximum.z) self.setMetadataNoscriptElement('minZ', 'Z: ', self.cornerMinimum.z) self.textHeight = float( self.sliceDictionary['textHeight'] ) controlTop = len(rotatedLoopLayers) * (self.margin + self.extent.y * self.unitScale + self.textHeight) + self.marginTop + self.textHeight self.svgElement.getFirstChildWithClassName('title').text = os.path.basename(fileName) + ' - Slice Layers' svgElementDictionary['height'] = '%spx' % self.getRounded(max(controlTop, self.controlBoxHeightMargin)) width = max(self.extent.x * self.unitScale, svgMinWidth) svgElementDictionary['width'] = '%spx' % self.getRounded( width ) self.sliceDictionary['decimalPlacesCarried'] = str( self.decimalPlacesCarried ) if self.perimeterWidth != None: self.sliceDictionary['perimeterWidth'] = self.getRounded( self.perimeterWidth ) self.sliceDictionary['yAxisPointingUpward'] = 'true' self.sliceDictionary['procedureName'] = procedureName self.setDimensionTexts('dimX', 'X: ' + self.getRounded(self.extent.x)) self.setDimensionTexts('dimY', 'Y: ' + self.getRounded(self.extent.y)) self.setDimensionTexts('dimZ', 'Z: ' + self.getRounded(self.extent.z)) self.setTexts('numberOfLayers', 'Number of Layers: %s' % len(rotatedLoopLayers)) volume = 0.0 for rotatedLoopLayer in rotatedLoopLayers: volume += euclidean.getAreaLoops(rotatedLoopLayer.loops) volume *= 0.001 self.setTexts('volume', 'Volume: %s cm3' % self.getRounded(volume)) if not self.addLayerTemplateToSVG: self.svgElement.getFirstChildWithClassName('script').removeFromIDNameParent() self.svgElement.getXMLElementByID('isoControlBox').removeFromIDNameParent() self.svgElement.getXMLElementByID('layerControlBox').removeFromIDNameParent() self.svgElement.getXMLElementByID('scrollControlBox').removeFromIDNameParent() self.graphicsXMLElement.removeFromIDNameParent() self.addOriginalAsComment(xmlElement) output = cStringIO.StringIO() output.write(self.xmlParser.beforeRoot) self.svgElement.addXML(0, output) return xml_simple_writer.getBeforeRootOutput(self.xmlParser) def getRounded(self, number): 'Get number rounded to the number of carried decimal places as a string.' return euclidean.getRoundedToPlacesString(self.decimalPlacesCarried, number) def getRoundedComplexString(self, point): 'Get the rounded complex string.' return self.getRounded( point.real ) + ' ' + self.getRounded( point.imag ) def getSVGStringForLoop( self, loop ): 'Get the svg loop string.' if len(loop) < 1: return '' return self.getSVGStringForPath(loop) + ' z' def getSVGStringForLoops( self, loops ): 'Get the svg loops string.' loopString = '' if len(loops) > 0: loopString += self.getSVGStringForLoop( loops[0] ) for loop in loops[1 :]: loopString += ' ' + self.getSVGStringForLoop(loop) return loopString def getSVGStringForPath( self, path ): 'Get the svg path string.' svgLoopString = '' for point in path: stringBeginning = 'M ' if len( svgLoopString ) > 0: stringBeginning = ' L ' svgLoopString += stringBeginning + self.getRoundedComplexString(point) return svgLoopString def setMetadataNoscriptElement(self, key, prefix, value): 'Set the metadata value and the text.' valueString = self.getRounded(value) self.sliceDictionary[key] = valueString self.setDimensionTexts(key, prefix + valueString) def setDimensionTexts(self, key, valueString): 'Set the texts to the valueString followed by mm.' self.setTexts(key, valueString + ' mm') def setTexts(self, key, valueString): 'Set the texts to the valueString.' self.svgElement.getXMLElementByID(key + 'Iso').text = valueString self.svgElement.getXMLElementByID(key + 'Layer').text = valueString self.svgElement.getXMLElementByID(key + 'Scroll').text = valueString def getTransformString(self): 'Get the svg transform string.' cornerMinimumXString = self.getRounded(-self.cornerMinimum.x) cornerMinimumYString = self.getRounded(-self.cornerMinimum.y) return 'scale(%s, %s) translate(%s, %s)' % (self.unitScale, - self.unitScale, cornerMinimumXString, cornerMinimumYString)
def parseSVG(self, fileName, svgText): "Parse SVG text and store the layers." self.fileName = fileName xmlParser = XMLSimpleReader(fileName, None, svgText) self.parseSVGByXMLElement(xmlParser.getRoot())
class SVGWriter: "A base class to get an svg skein from a carving." def __init__(self, addLayerTemplateToSVG, carving, decimalPlacesCarried, perimeterWidth = None): self.addLayerTemplateToSVG = addLayerTemplateToSVG self.carving = carving self.decimalPlacesCarried = decimalPlacesCarried self.margin = 20 self.perimeterWidth = perimeterWidth self.textHeight = 22.5 self.unitScale = 3.7 def addLayerBegin(self, layerIndex, rotatedBoundaryLayer): "Add the start lines for the layer." zRounded = self.getRounded( rotatedBoundaryLayer.z ) self.graphicsCopy = self.graphicsXMLElement.getCopy(zRounded, self.graphicsXMLElement.parent) if self.addLayerTemplateToSVG: marginRounded = self.getRounded(self.margin) layerTranslateY = layerIndex * self.textHeight + (layerIndex + 1) * (self.extent.y * self.unitScale + self.margin) translateYRounded = self.getRounded(layerTranslateY) self.graphicsCopy.attributeDictionary['transform'] = 'translate(%s, %s)' % (marginRounded, translateYRounded) self.graphicsCopy.getFirstChildWithClassName('text').text = 'Layer %s, z:%s' % (layerIndex, zRounded) self.pathXMLElement = self.graphicsCopy.getFirstChildWithClassName('path') self.pathDictionary = self.pathXMLElement.attributeDictionary def addRotatedLoopLayerToOutput( self, layerIndex, rotatedBoundaryLayer ): "Add rotated boundary layer to the output." self.addLayerBegin( layerIndex, rotatedBoundaryLayer ) if rotatedBoundaryLayer.rotation != None: self.graphicsCopy.attributeDictionary['bridgeRotation'] = str( rotatedBoundaryLayer.rotation ) if self.addLayerTemplateToSVG: self.pathDictionary['transform'] = self.getTransformString() else: del self.pathDictionary['transform'] self.pathDictionary['d'] = self.getSVGStringForLoops(rotatedBoundaryLayer.loops) def addRotatedLoopLayersToOutput( self, rotatedBoundaryLayers ): "Add rotated boundary layers to the output." for rotatedBoundaryLayerIndex, rotatedBoundaryLayer in enumerate( rotatedBoundaryLayers ): self.addRotatedLoopLayerToOutput( rotatedBoundaryLayerIndex, rotatedBoundaryLayer ) def getReplacedSVGTemplate(self, fileName, procedureName, rotatedBoundaryLayers, xmlElement): "Get the lines of text from the layer_template.svg file." # ( layers.length + 1 ) * (margin + sliceDimY * unitScale + txtHeight) + margin + txtHeight + margin + 110 cornerMaximum = self.carving.getCarveCornerMaximum() cornerMinimum = self.carving.getCarveCornerMinimum() self.extent = cornerMaximum - cornerMinimum svgTemplateText = gcodec.getFileTextInFileDirectory( __file__, os.path.join('templates', 'layer_template.svg') ) self.xmlParser = XMLSimpleReader( fileName, None, svgTemplateText ) self.svgElement = self.xmlParser.getRoot() if not self.addLayerTemplateToSVG: self.svgElement.getXMLElementByID('layerTextTemplate').removeFromIDNameParent() del self.svgElement.getXMLElementByID('sliceElementTemplate').attributeDictionary['transform'] svgElementDictionary = self.svgElement.attributeDictionary self.graphicsXMLElement = self.svgElement.getXMLElementByID('sliceElementTemplate') self.graphicsXMLElement.attributeDictionary['id'] = 'z:' self.addRotatedLoopLayersToOutput( rotatedBoundaryLayers ) self.sliceDictionary = getSliceDictionary( self.svgElement ) self.setMetadataNoscriptElement('layerThickness', self.carving.getCarveLayerThickness() ) self.setMetadataNoscriptElement('maxX', cornerMaximum.x ) self.setMetadataNoscriptElement('minX', cornerMinimum.x ) self.setMetadataNoscriptElement('maxY', cornerMaximum.y ) self.setMetadataNoscriptElement('minY', cornerMinimum.y ) self.setMetadataNoscriptElement('maxZ', cornerMaximum.z ) self.setMetadataNoscriptElement('minZ', cornerMinimum.z ) self.margin = float( self.sliceDictionary['margin'] ) self.textHeight = float( self.sliceDictionary['textHeight'] ) javascriptControlBoxWidth = float( self.sliceDictionary['javascriptControlBoxWidth'] ) noJavascriptControlBoxHeight = float( self.sliceDictionary['noJavascriptControlBoxHeight'] ) controlTop = len( rotatedBoundaryLayers ) * ( self.margin + self.extent.y * self.unitScale + self.textHeight ) + 2.0 * self.margin + self.textHeight self.svgElement.getFirstChildWithClassName('title').text = os.path.basename(fileName) + ' - Slice Layers' svgElementDictionary['height'] = '%spx' % self.getRounded( controlTop + noJavascriptControlBoxHeight + self.margin ) # width = margin + (sliceDimX * unitScale) + margin; width = 2.0 * self.margin + max( self.extent.x * self.unitScale, javascriptControlBoxWidth ) svgElementDictionary['width'] = '%spx' % self.getRounded( width ) self.sliceDictionary['decimalPlacesCarried'] = str( self.decimalPlacesCarried ) if self.perimeterWidth != None: self.sliceDictionary['perimeterWidth'] = self.getRounded( self.perimeterWidth ) self.sliceDictionary['yAxisPointingUpward'] = 'true' self.sliceDictionary['procedureDone'] = procedureName noJavascriptDictionary = self.svgElement.getXMLElementByID('noJavascriptControls').attributeDictionary noJavascriptDictionary['transform'] = 'translate(%s, %s)' % ( self.getRounded(self.margin), self.getRounded( controlTop ) ) self.svgElement.getXMLElementByID('dimXNoJavascript').text = self.getRounded( self.extent.x ) self.svgElement.getXMLElementByID('dimYNoJavascript').text = self.getRounded( self.extent.y ) self.svgElement.getXMLElementByID('dimZNoJavascript').text = self.getRounded( self.extent.z ) if not self.addLayerTemplateToSVG: self.svgElement.getFirstChildWithClassName('script').removeFromIDNameParent() self.svgElement.getXMLElementByID('beginningOfControlSection').removeFromIDNameParent() self.svgElement.getXMLElementByID('noJavascriptControls').removeFromIDNameParent() self.graphicsXMLElement.removeFromIDNameParent() if xmlElement != None: xmlElement.setParentAddToChildren(self.svgElement) output = cStringIO.StringIO() output.write( self.xmlParser.beforeRoot ) self.svgElement.addXML( 0, output ) return output.getvalue() def getRounded(self, number): "Get number rounded to the number of carried decimal places as a string." return euclidean.getRoundedToDecimalPlacesString(self.decimalPlacesCarried, number) def getRoundedComplexString(self, point): "Get the rounded complex string." return self.getRounded( point.real ) + ' ' + self.getRounded( point.imag ) def getSVGStringForLoop( self, loop ): "Get the svg loop string." if len(loop) < 1: return '' return self.getSVGStringForPath(loop) + ' z' def getSVGStringForLoops( self, loops ): "Get the svg loops string." loopString = '' if len(loops) > 0: loopString += self.getSVGStringForLoop( loops[0] ) for loop in loops[1 :]: loopString += ' ' + self.getSVGStringForLoop(loop) return loopString def getSVGStringForPath( self, path ): "Get the svg path string." svgLoopString = '' for point in path: stringBeginning = 'M ' if len( svgLoopString ) > 0: stringBeginning = ' L ' svgLoopString += stringBeginning + self.getRoundedComplexString(point) return svgLoopString def getTransformString(self): "Get the svg transform string." cornerMinimumXString = self.getRounded( - self.carving.getCarveCornerMinimum().x ) cornerMinimumYString = self.getRounded( - self.carving.getCarveCornerMinimum().y ) return 'scale(%s, %s) translate(%s, %s)' % ( self.unitScale, - self.unitScale, cornerMinimumXString, cornerMinimumYString ) def setMetadataNoscriptElement( self, prefix, value ): "Set the metadata value and the NoJavascript text." valueString = self.getRounded(value) self.sliceDictionary[ prefix ] = valueString self.svgElement.getXMLElementByID( prefix + 'NoJavascript').text = valueString
class SVGWriter: "A base class to get an svg skein from a carving." def __init__(self, addLayerTemplateToSVG, carving, decimalPlacesCarried, perimeterWidth=None): self.addLayerTemplateToSVG = addLayerTemplateToSVG self.carving = carving self.decimalPlacesCarried = decimalPlacesCarried self.margin = 20 self.perimeterWidth = perimeterWidth self.textHeight = 22.5 self.unitScale = 3.7 def addLayerBegin(self, layerIndex, rotatedBoundaryLayer): "Add the start lines for the layer." zRounded = self.getRounded(rotatedBoundaryLayer.z) self.graphicsCopy = self.graphicsXMLElement.getCopy( zRounded, self.graphicsXMLElement.parent) if self.addLayerTemplateToSVG: marginRounded = self.getRounded(self.margin) layerTranslateY = layerIndex * self.textHeight + ( layerIndex + 1) * (self.extent.y * self.unitScale + self.margin) translateYRounded = self.getRounded(layerTranslateY) self.graphicsCopy.attributeDictionary[ 'transform'] = 'translate(%s, %s)' % (marginRounded, translateYRounded) self.graphicsCopy.getFirstChildWithClassName( 'text').text = 'Layer %s, z:%s' % (layerIndex, zRounded) self.pathXMLElement = self.graphicsCopy.getFirstChildWithClassName( 'path') self.pathDictionary = self.pathXMLElement.attributeDictionary def addOriginalAsComment(self, xmlElement): "Add original xmlElement as a comment." if xmlElement == None: return commentElement = XMLElement() commentElement.className = 'comment' xmlElementOutput = cStringIO.StringIO() xmlElement.addXML(0, xmlElementOutput) textLines = archive.getTextLines(xmlElementOutput.getvalue()) commentElementOutput = cStringIO.StringIO() isComment = False for textLine in textLines: lineStripped = textLine.strip() if lineStripped[:len('<!--')] == '<!--': isComment = True if not isComment: if len(textLine) > 0: commentElementOutput.write(textLine + '\n') if '-->' in lineStripped: isComment = False commentElement.text = '<!-- Original XML Text:\n%s-->\n' % commentElementOutput.getvalue( ) commentElement.setParentAddToChildren(self.svgElement) def addRotatedLoopLayerToOutput(self, layerIndex, rotatedBoundaryLayer): "Add rotated boundary layer to the output." self.addLayerBegin(layerIndex, rotatedBoundaryLayer) if rotatedBoundaryLayer.rotation != None: self.graphicsCopy.attributeDictionary['bridgeRotation'] = str( rotatedBoundaryLayer.rotation) if self.addLayerTemplateToSVG: self.pathDictionary['transform'] = self.getTransformString() else: del self.pathDictionary['transform'] self.pathDictionary['d'] = self.getSVGStringForLoops( rotatedBoundaryLayer.loops) def addRotatedLoopLayersToOutput(self, rotatedBoundaryLayers): "Add rotated boundary layers to the output." for rotatedBoundaryLayerIndex, rotatedBoundaryLayer in enumerate( rotatedBoundaryLayers): self.addRotatedLoopLayerToOutput(rotatedBoundaryLayerIndex, rotatedBoundaryLayer) def getReplacedSVGTemplate(self, fileName, procedureName, rotatedBoundaryLayers, xmlElement=None): "Get the lines of text from the layer_template.svg file." # ( layers.length + 1 ) * (margin + sliceDimY * unitScale + txtHeight) + margin + txtHeight + margin + 110 cornerMaximum = self.carving.getCarveCornerMaximum() cornerMinimum = self.carving.getCarveCornerMinimum() self.extent = cornerMaximum - cornerMinimum svgTemplateText = archive.getFileTextInFileDirectory( __file__, os.path.join('templates', 'layer_template.svg')) self.xmlParser = XMLSimpleReader(fileName, None, svgTemplateText) self.svgElement = self.xmlParser.getRoot() if not self.addLayerTemplateToSVG: self.svgElement.getXMLElementByID( 'layerTextTemplate').removeFromIDNameParent() del self.svgElement.getXMLElementByID( 'sliceElementTemplate').attributeDictionary['transform'] svgElementDictionary = self.svgElement.attributeDictionary self.graphicsXMLElement = self.svgElement.getXMLElementByID( 'sliceElementTemplate') self.graphicsXMLElement.attributeDictionary['id'] = 'z:' self.addRotatedLoopLayersToOutput(rotatedBoundaryLayers) self.sliceDictionary = getSliceDictionary(self.svgElement) self.setMetadataNoscriptElement('layerThickness', self.carving.getCarveLayerThickness()) self.setMetadataNoscriptElement('maxX', cornerMaximum.x) self.setMetadataNoscriptElement('minX', cornerMinimum.x) self.setMetadataNoscriptElement('maxY', cornerMaximum.y) self.setMetadataNoscriptElement('minY', cornerMinimum.y) self.setMetadataNoscriptElement('maxZ', cornerMaximum.z) self.setMetadataNoscriptElement('minZ', cornerMinimum.z) self.margin = float(self.sliceDictionary['margin']) self.textHeight = float(self.sliceDictionary['textHeight']) javascriptControlBoxWidth = float( self.sliceDictionary['javascriptControlBoxWidth']) noJavascriptControlBoxHeight = float( self.sliceDictionary['noJavascriptControlBoxHeight']) controlTop = len(rotatedBoundaryLayers) * ( self.margin + self.extent.y * self.unitScale + self.textHeight) + 2.0 * self.margin + self.textHeight self.svgElement.getFirstChildWithClassName( 'title').text = os.path.basename(fileName) + ' - Slice Layers' svgElementDictionary['height'] = '%spx' % self.getRounded( controlTop + noJavascriptControlBoxHeight + self.margin) # width = margin + (sliceDimX * unitScale) + margin; width = 2.0 * self.margin + max(self.extent.x * self.unitScale, javascriptControlBoxWidth) svgElementDictionary['width'] = '%spx' % self.getRounded(width) self.sliceDictionary['decimalPlacesCarried'] = str( self.decimalPlacesCarried) if self.perimeterWidth != None: self.sliceDictionary['perimeterWidth'] = self.getRounded( self.perimeterWidth) self.sliceDictionary['yAxisPointingUpward'] = 'true' self.sliceDictionary['procedureDone'] = procedureName noJavascriptDictionary = self.svgElement.getXMLElementByID( 'noJavascriptControls').attributeDictionary noJavascriptDictionary['transform'] = 'translate(%s, %s)' % ( self.getRounded(self.margin), self.getRounded(controlTop)) self.svgElement.getXMLElementByID( 'dimXNoJavascript').text = self.getRounded(self.extent.x) self.svgElement.getXMLElementByID( 'dimYNoJavascript').text = self.getRounded(self.extent.y) self.svgElement.getXMLElementByID( 'dimZNoJavascript').text = self.getRounded(self.extent.z) if not self.addLayerTemplateToSVG: self.svgElement.getFirstChildWithClassName( 'script').removeFromIDNameParent() self.svgElement.getXMLElementByID( 'beginningOfControlSection').removeFromIDNameParent() self.svgElement.getXMLElementByID( 'noJavascriptControls').removeFromIDNameParent() self.graphicsXMLElement.removeFromIDNameParent() self.addOriginalAsComment(xmlElement) output = cStringIO.StringIO() output.write(self.xmlParser.beforeRoot) self.svgElement.addXML(0, output) return output.getvalue() def getRounded(self, number): "Get number rounded to the number of carried decimal places as a string." return euclidean.getRoundedToDecimalPlacesString( self.decimalPlacesCarried, number) def getRoundedComplexString(self, point): "Get the rounded complex string." return self.getRounded(point.real) + ' ' + self.getRounded(point.imag) def getSVGStringForLoop(self, loop): "Get the svg loop string." if len(loop) < 1: return '' return self.getSVGStringForPath(loop) + ' z' def getSVGStringForLoops(self, loops): "Get the svg loops string." loopString = '' if len(loops) > 0: loopString += self.getSVGStringForLoop(loops[0]) for loop in loops[1:]: loopString += ' ' + self.getSVGStringForLoop(loop) return loopString def getSVGStringForPath(self, path): "Get the svg path string." svgLoopString = '' for point in path: stringBeginning = 'M ' if len(svgLoopString) > 0: stringBeginning = ' L ' svgLoopString += stringBeginning + self.getRoundedComplexString( point) return svgLoopString def getTransformString(self): "Get the svg transform string." cornerMinimumXString = self.getRounded( -self.carving.getCarveCornerMinimum().x) cornerMinimumYString = self.getRounded( -self.carving.getCarveCornerMinimum().y) return 'scale(%s, %s) translate(%s, %s)' % ( self.unitScale, -self.unitScale, cornerMinimumXString, cornerMinimumYString) def setMetadataNoscriptElement(self, prefix, value): "Set the metadata value and the NoJavascript text." valueString = self.getRounded(value) self.sliceDictionary[prefix] = valueString self.svgElement.getXMLElementByID(prefix + 'NoJavascript').text = valueString