1 """
2 Svg reader.
3
4 """
5
6 from fabmetheus_utilities.geometry.solids import triangle_mesh
7 from fabmetheus_utilities.xml_simple_reader import XMLSimpleReader
8 from fabmetheus_utilities import archive
9 from fabmetheus_utilities import euclidean
10 from fabmetheus_utilities import intercircle
11 from fabmetheus_utilities import svg_writer
12 import math
13 import os
14 import sys
15 import traceback
16
17
18 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
19 __credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
20 __date__ = '$Date: 2008/21/04 $'
21 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
22
23
24 globalNumberOfCornerPoints = 11
25 globalNumberOfBezierPoints = globalNumberOfCornerPoints + globalNumberOfCornerPoints
26 globalNumberOfCirclePoints = 4 * globalNumberOfCornerPoints
27
28
30 "Add functions to dictionary."
31 for function in functions:
32 dictionary[ function.__name__[ len( prefix ) : ] ] = function
33
34 -def getArcComplexes(begin, end, largeArcFlag, radius, sweepFlag, xAxisRotation):
35 'Get the arc complexes, procedure at http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes'
36 if begin == end:
37 print('Warning, begin equals end in getArcComplexes in svgReader')
38 print(begin)
39 print(end)
40 return []
41 if radius.imag < 0.0:
42 print('Warning, radius.imag is less than zero in getArcComplexes in svgReader')
43 print(radius)
44 radius = complex(radius.real, abs(radius.imag))
45 if radius.real < 0.0:
46 print('Warning, radius.real is less than zero in getArcComplexes in svgReader')
47 print(radius)
48 radius = complex(abs(radius.real), radius.imag)
49 if radius.imag <= 0.0:
50 print('Warning, radius.imag is too small for getArcComplexes in svgReader')
51 print(radius)
52 return [end]
53 if radius.real <= 0.0:
54 print('Warning, radius.real is too small for getArcComplexes in svgReader')
55 print(radius)
56 return [end]
57 xAxisRotationComplex = euclidean.getWiddershinsUnitPolar(xAxisRotation)
58 reverseXAxisRotationComplex = complex(xAxisRotationComplex.real, -xAxisRotationComplex.imag)
59 beginRotated = begin * reverseXAxisRotationComplex
60 endRotated = end * reverseXAxisRotationComplex
61 beginTransformed = complex(beginRotated.real / radius.real, beginRotated.imag / radius.imag)
62 endTransformed = complex(endRotated.real / radius.real, endRotated.imag / radius.imag)
63 midpointTransformed = 0.5 * (beginTransformed + endTransformed)
64 midMinusBeginTransformed = midpointTransformed - beginTransformed
65 midMinusBeginTransformedLength = abs(midMinusBeginTransformed)
66 if midMinusBeginTransformedLength > 1.0:
67 print('Warning, midMinusBeginTransformedLength is too large for getArcComplexes in svgReader')
68 print(begin)
69 print(end)
70 print(beginTransformed)
71 print(endTransformed)
72 print(midpointTransformed)
73 print(midMinusBeginTransformed)
74 print('The ellipse will be scaled to fit.')
75 radius *= midMinusBeginTransformedLength
76 scale = 1.0 / midMinusBeginTransformedLength
77 beginTransformed *= scale
78 endTransformed *= scale
79 midpointTransformed *= scale
80 midMinusBeginTransformed *= scale
81 midMinusBeginTransformedLength = 1.0
82 midWiddershinsTransformed = complex(-midMinusBeginTransformed.imag, midMinusBeginTransformed.real)
83 midWiddershinsLengthSquared = 1.0 - midMinusBeginTransformedLength * midMinusBeginTransformedLength
84 if midWiddershinsLengthSquared < 0.0:
85 midWiddershinsLengthSquared = 0.0
86 midWiddershinsLength = math.sqrt(midWiddershinsLengthSquared)
87 midWiddershinsTransformed *= midWiddershinsLength / abs(midWiddershinsTransformed)
88 centerTransformed = midpointTransformed
89 if largeArcFlag == sweepFlag:
90 centerTransformed -= midWiddershinsTransformed
91 else:
92 centerTransformed += midWiddershinsTransformed
93 beginMinusCenterTransformed = beginTransformed - centerTransformed
94 beginMinusCenterTransformedLength = abs(beginMinusCenterTransformed)
95 if beginMinusCenterTransformedLength <= 0.0:
96 return end
97 beginAngle = math.atan2(beginMinusCenterTransformed.imag, beginMinusCenterTransformed.real)
98 endMinusCenterTransformed = endTransformed - centerTransformed
99 angleDifference = euclidean.getAngleDifferenceByComplex(endMinusCenterTransformed, beginMinusCenterTransformed)
100 if sweepFlag:
101 if angleDifference < 0.0:
102 angleDifference += 2.0 * math.pi
103 else:
104 if angleDifference > 0.0:
105 angleDifference -= 2.0 * math.pi
106 global globalSideAngle
107 sides = int(math.ceil(abs(angleDifference) / globalSideAngle))
108 sideAngle = angleDifference / float(sides)
109 arcComplexes = []
110 center = complex(centerTransformed.real * radius.real, centerTransformed.imag * radius.imag) * xAxisRotationComplex
111 for side in xrange(1, sides):
112 unitPolar = euclidean.getWiddershinsUnitPolar(beginAngle + float(side) * sideAngle)
113 circumferential = complex(unitPolar.real * radius.real, unitPolar.imag * radius.imag) * beginMinusCenterTransformedLength
114 point = center + circumferential * xAxisRotationComplex
115 arcComplexes.append(point)
116 arcComplexes.append(end)
117 return arcComplexes
118
120 "Get chain matrixSVG by svgElement."
121 matrixSVG = matrixSVG.getOtherTimesSelf(getMatrixSVG(xmlElement).tricomplex)
122 if xmlElement.parentNode != None:
123 matrixSVG = getChainMatrixSVG(matrixSVG, xmlElement.parentNode)
124 return matrixSVG
125
127 "Get chain matrixSVG by svgElement and yAxisPointingUpward."
128 matrixSVG = MatrixSVG()
129 if yAxisPointingUpward:
130 return matrixSVG
131 return getChainMatrixSVG(matrixSVG, xmlElement)
132
134 'Get the cubic point.'
135 segmentBegin = getQuadraticPoint( along, begin, controlPoints[0], controlPoints[1] )
136 segmentEnd = getQuadraticPoint( along, controlPoints[0], controlPoints[1], end )
137 return ( 1.0 - along ) * segmentBegin + along * segmentEnd
138
140 'Get the cubic points.'
141 bezierPortion = 1.0 / float(numberOfBezierPoints)
142 cubicPoints = []
143 for bezierIndex in xrange( 1, numberOfBezierPoints + 1 ):
144 cubicPoints.append(getCubicPoint(bezierPortion * bezierIndex, begin, controlPoints, end))
145 return cubicPoints
146
162
166
168 "Get the label string for the dictionary."
169 for key in dictionary:
170 labelIndex = key.find('label')
171 if labelIndex >= 0:
172 return dictionary[key]
173 return ''
174
176 "Get matrixSVG by svgElement."
177 matrixSVG = MatrixSVG()
178 if 'transform' not in xmlElement.attributeDictionary:
179 return matrixSVG
180 transformWords = []
181 for transformWord in xmlElement.attributeDictionary['transform'].replace(')', '(').split('('):
182 transformWordStrip = transformWord.strip()
183 if transformWordStrip != '':
184 transformWords.append(transformWordStrip)
185 global globalGetTricomplexDictionary
186 getTricomplexDictionaryKeys = globalGetTricomplexDictionary.keys()
187 for transformWordIndex, transformWord in enumerate(transformWords):
188 if transformWord in getTricomplexDictionaryKeys:
189 transformString = transformWords[transformWordIndex + 1].replace(',', ' ')
190 matrixSVG = matrixSVG.getSelfTimesOther(globalGetTricomplexDictionary[ transformWord ](transformString.split()))
191 return matrixSVG
192
194 'Get the quadratic point.'
195 oneMinusAlong = 1.0 - along
196 segmentBegin = oneMinusAlong * begin + along * controlPoint
197 segmentEnd = oneMinusAlong * controlPoint + along * end
198 return oneMinusAlong * segmentBegin + along * segmentEnd
199
201 'Get the quadratic points.'
202 bezierPortion = 1.0 / float(numberOfBezierPoints)
203 quadraticPoints = []
204 for bezierIndex in xrange(1, numberOfBezierPoints + 1):
205 quadraticPoints.append(getQuadraticPoint(bezierPortion * bezierIndex, begin, controlPoint, end))
206 return quadraticPoints
207
209 "Get word with alphabet characters and the percent sign stripped from the right."
210 word = word.strip()
211 for characterIndex in xrange(len(word) - 1, -1, -1):
212 character = word[characterIndex]
213 if not character.isalpha() and not character == '%':
214 return float(word[: characterIndex + 1])
215 return None
216
218 "Get string with spaces after the minus sign stripped."
219 oldLineStringLength = -1
220 while oldLineStringLength < len(lineString):
221 oldLineStringLength = len(lineString)
222 lineString = lineString.replace('- ', '-')
223 return lineString.split()
224
228
230 "Get the stroke value string."
231 if 'style' in xmlElement.attributeDictionary:
232 line = xmlElement.attributeDictionary['style']
233 strokeIndex = line.find(key)
234 if strokeIndex > -1:
235 words = line[strokeIndex :].replace(':', ' ').replace(';', ' ').split()
236 if len(words) > 1:
237 return words[1]
238 if key in xmlElement.attributeDictionary:
239 return xmlElement.attributeDictionary[key]
240 if xmlElement.parentNode == None:
241 return defaultValue
242 return getStyleValue(defaultValue, key, xmlElement.parentNode)
243
244 -def getTextComplexLoops(fontFamily, fontSize, text, yAxisPointingUpward=True):
245 "Get text as complex loops."
246 textComplexLoops = []
247 fontReader = getFontReader(fontFamily)
248 horizontalAdvanceX = 0.0
249 for character in text:
250 glyph = fontReader.getGlyph(character, yAxisPointingUpward)
251 textComplexLoops += glyph.getSizedAdvancedLoops(fontSize, horizontalAdvanceX, yAxisPointingUpward)
252 horizontalAdvanceX += glyph.horizontalAdvanceX
253 return textComplexLoops
254
263
268
273
280
282 "Get matrixSVG by transformWords."
283 rotate = euclidean.getWiddershinsUnitPolar(math.radians(float(transformWords[0])))
284 return [rotate, complex(-rotate.imag,rotate.real), complex()]
285
287 "Get matrixSVG by transformWords."
288 scale = euclidean.getComplexByWords(transformWords)
289 return [complex(scale.real,0.0), complex(0.0,scale.imag), complex()]
290
292 "Get matrixSVG by transformWords."
293 skewX = math.tan(math.radians(float(transformWords[0])))
294 return [complex(1.0, 0.0), complex(skewX, 1.0), complex()]
295
297 "Get matrixSVG by transformWords."
298 skewY = math.tan(math.radians(float(transformWords[0])))
299 return [complex(1.0, skewY), complex(0.0, 1.0), complex()]
300
302 "Get this matrix multiplied by the otherColumn."
303 dotProductX = firstTricomplex[0].real * otherColumn.real + firstTricomplex[1].real * otherColumn.imag
304 dotProductY = firstTricomplex[0].imag * otherColumn.real + firstTricomplex[1].imag * otherColumn.imag
305 return complex(dotProductX, dotProductY)
306
314
316 "Get matrixSVG by transformWords."
317 translate = euclidean.getComplexByWords(transformWords)
318 return [complex(1.0, 0.0), complex(0.0, 1.0), translate]
319
337
339 "Process xmlElement by svgReader."
340 attributeDictionary = xmlElement.attributeDictionary
341 center = euclidean.getComplexDefaultByDictionaryKeys( complex(), attributeDictionary, 'cx', 'cy')
342 radius = euclidean.getComplexDefaultByDictionaryKeys( complex(), attributeDictionary, 'rx', 'ry')
343 if radius.real == 0.0 or radius.imag == 0.0:
344 print('Warning, in processSVGElementellipse in svgReader radius is zero in:')
345 print(attributeDictionary)
346 return
347 global globalNumberOfCirclePoints
348 global globalSideAngle
349 loop = []
350 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
351 for side in xrange( globalNumberOfCirclePoints ):
352 unitPolar = euclidean.getWiddershinsUnitPolar( float(side) * globalSideAngle )
353 loop.append( center + complex( unitPolar.real * radius.real, unitPolar.imag * radius.imag ) )
354 rotatedLoopLayer.loops += getTransformedFillOutline(loop, xmlElement, svgReader.yAxisPointingUpward)
355
357 'Process xmlElement by svgReader.'
358 if 'id' not in xmlElement.attributeDictionary:
359 return
360 idString = xmlElement.attributeDictionary['id']
361 if 'beginningOfControlSection' in xmlElement.attributeDictionary:
362 if xmlElement.attributeDictionary['beginningOfControlSection'].lower()[: 1] == 't':
363 svgReader.stopProcessing = True
364 return
365 idStringLower = idString.lower()
366 zIndex = idStringLower.find('z:')
367 if zIndex < 0:
368 idStringLower = getLabelString(xmlElement.attributeDictionary)
369 zIndex = idStringLower.find('z:')
370 if zIndex < 0:
371 return
372 floatFromValue = euclidean.getFloatFromValue(idStringLower[zIndex + len('z:') :].strip())
373 if floatFromValue != None:
374 svgReader.z = floatFromValue
375 svgReader.bridgeRotation = euclidean.getComplexDefaultByDictionary( None, xmlElement.attributeDictionary, 'bridgeRotation')
376
383
385 "Process xmlElement by svgReader."
386 if 'd' not in xmlElement.attributeDictionary:
387 print('Warning, in processSVGElementpath in svgReader can not get a value for d in:')
388 print(xmlElement.attributeDictionary)
389 return
390 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
391 PathReader(rotatedLoopLayer.loops, xmlElement, svgReader.yAxisPointingUpward)
392
394 "Process xmlElement by svgReader."
395 if 'points' not in xmlElement.attributeDictionary:
396 print('Warning, in processSVGElementpolygon in svgReader can not get a value for d in:')
397 print(xmlElement.attributeDictionary)
398 return
399 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
400 words = getRightStripMinusSplit(xmlElement.attributeDictionary['points'].replace(',', ' '))
401 loop = []
402 for wordIndex in xrange( 0, len(words), 2 ):
403 loop.append(euclidean.getComplexByWords(words[wordIndex :]))
404 rotatedLoopLayer.loops += getTransformedFillOutline(loop, xmlElement, svgReader.yAxisPointingUpward)
405
407 "Process xmlElement by svgReader."
408 if 'points' not in xmlElement.attributeDictionary:
409 print('Warning, in processSVGElementpolyline in svgReader can not get a value for d in:')
410 print(xmlElement.attributeDictionary)
411 return
412 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
413 words = getRightStripMinusSplit(xmlElement.attributeDictionary['points'].replace(',', ' '))
414 path = []
415 for wordIndex in xrange(0, len(words), 2):
416 path.append(euclidean.getComplexByWords(words[wordIndex :]))
417 rotatedLoopLayer.loops += getTransformedOutlineByPath(path, xmlElement, svgReader.yAxisPointingUpward)
418
420 "Process xmlElement by svgReader."
421 attributeDictionary = xmlElement.attributeDictionary
422 height = euclidean.getFloatDefaultByDictionary( 0.0, attributeDictionary, 'height')
423 if height == 0.0:
424 print('Warning, in processSVGElementrect in svgReader height is zero in:')
425 print(attributeDictionary)
426 return
427 width = euclidean.getFloatDefaultByDictionary( 0.0, attributeDictionary, 'width')
428 if width == 0.0:
429 print('Warning, in processSVGElementrect in svgReader width is zero in:')
430 print(attributeDictionary)
431 return
432 center = euclidean.getComplexDefaultByDictionaryKeys(complex(), attributeDictionary, 'x', 'y')
433 inradius = 0.5 * complex( width, height )
434 cornerRadius = euclidean.getComplexDefaultByDictionaryKeys( complex(), attributeDictionary, 'rx', 'ry')
435 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
436 if cornerRadius.real == 0.0 and cornerRadius.imag == 0.0:
437 inradiusMinusX = complex( - inradius.real, inradius.imag )
438 loop = [center + inradius, center + inradiusMinusX, center - inradius, center - inradiusMinusX]
439 rotatedLoopLayer.loops += getTransformedFillOutline(loop, xmlElement, svgReader.yAxisPointingUpward)
440 return
441 if cornerRadius.real == 0.0:
442 cornerRadius = complex( cornerRadius.imag, cornerRadius.imag )
443 elif cornerRadius.imag == 0.0:
444 cornerRadius = complex( cornerRadius.real, cornerRadius.real )
445 cornerRadius = complex( min( cornerRadius.real, inradius.real ), min( cornerRadius.imag, inradius.imag ) )
446 ellipsePath = [ complex( cornerRadius.real, 0.0 ) ]
447 inradiusMinusCorner = inradius - cornerRadius
448 loop = []
449 global globalNumberOfCornerPoints
450 global globalSideAngle
451 for side in xrange( 1, globalNumberOfCornerPoints ):
452 unitPolar = euclidean.getWiddershinsUnitPolar( float(side) * globalSideAngle )
453 ellipsePath.append( complex( unitPolar.real * cornerRadius.real, unitPolar.imag * cornerRadius.imag ) )
454 ellipsePath.append( complex( 0.0, cornerRadius.imag ) )
455 cornerPoints = []
456 for point in ellipsePath:
457 cornerPoints.append( point + inradiusMinusCorner )
458 cornerPointsReversed = cornerPoints[: : -1]
459 for cornerPoint in cornerPoints:
460 loop.append( center + cornerPoint )
461 for cornerPoint in cornerPointsReversed:
462 loop.append( center + complex( - cornerPoint.real, cornerPoint.imag ) )
463 for cornerPoint in cornerPoints:
464 loop.append( center - cornerPoint )
465 for cornerPoint in cornerPointsReversed:
466 loop.append( center + complex( cornerPoint.real, - cornerPoint.imag ) )
467 loop = euclidean.getLoopWithoutCloseSequentialPoints( 0.0001 * abs(inradius), loop )
468 rotatedLoopLayer.loops += getTransformedFillOutline(loop, xmlElement, svgReader.yAxisPointingUpward)
469
470 -def processSVGElementtext(svgReader, xmlElement):
471 "Process xmlElement by svgReader."
472 if svgReader.yAxisPointingUpward:
473 return
474 fontFamily = getStyleValue('Gentium Basic Regular', 'font-family', xmlElement)
475 fontSize = getRightStripAlphabetPercent(getStyleValue('12.0', 'font-size', xmlElement))
476 matrixSVG = getChainMatrixSVGIfNecessary(xmlElement, svgReader.yAxisPointingUpward)
477 rotatedLoopLayer = svgReader.getRotatedLoopLayer()
478 translate = euclidean.getComplexDefaultByDictionaryKeys(complex(), xmlElement.attributeDictionary, 'x', 'y')
479 for textComplexLoop in getTextComplexLoops(fontFamily, fontSize, xmlElement.text, svgReader.yAxisPointingUpward):
480 translatedLoop = []
481 for textComplexPoint in textComplexLoop:
482 translatedLoop.append(textComplexPoint + translate )
483 rotatedLoopLayer.loops.append(matrixSVG.getTransformedPath(translatedLoop))
484
485
487 "Class to read a font in the fonts folder."
489 "Initialize."
490 self.fontFamily = fontFamily
491 self.glyphDictionary = {}
492 self.glyphXMLElementDictionary = {}
493 self.missingGlyph = None
494 fileName = os.path.join(getFontsDirectoryPath(), fontFamily + '.svg')
495 self.xmlParser = XMLSimpleReader(fileName, None, archive.getFileText(fileName))
496 self.fontXMLElement = self.xmlParser.getRoot().getFirstChildByLocalName('defs').getFirstChildByLocalName('font')
497 self.fontFaceXMLElement = self.fontXMLElement.getFirstChildByLocalName('font-face')
498 self.unitsPerEM = float(self.fontFaceXMLElement.attributeDictionary['units-per-em'])
499 glyphXMLElements = self.fontXMLElement.getChildNodesByLocalName('glyph')
500 for glyphXMLElement in glyphXMLElements:
501 self.glyphXMLElementDictionary[glyphXMLElement.attributeDictionary['unicode']] = glyphXMLElement
502
503 - def getGlyph(self, character, yAxisPointingUpward):
504 "Get the glyph for the character."
505 if character not in self.glyphXMLElementDictionary:
506 if self.missingGlyph == None:
507 missingGlyphXMLElement = self.fontXMLElement.getFirstChildByLocalName('missing-glyph')
508 self.missingGlyph = Glyph(self.unitsPerEM, missingGlyphXMLElement, yAxisPointingUpward)
509 return self.missingGlyph
510 if character not in self.glyphDictionary:
511 self.glyphDictionary[character] = Glyph(self.unitsPerEM, self.glyphXMLElementDictionary[character], yAxisPointingUpward)
512 return self.glyphDictionary[character]
513
514
516 "Class to handle a glyph."
517 - def __init__(self, unitsPerEM, xmlElement, yAxisPointingUpward):
518 "Initialize."
519 self.horizontalAdvanceX = float(xmlElement.attributeDictionary['horiz-adv-x'])
520 self.loops = []
521 self.unitsPerEM = unitsPerEM
522 xmlElement.attributeDictionary['fill'] = ''
523 if 'd' not in xmlElement.attributeDictionary:
524 return
525 PathReader(self.loops, xmlElement, yAxisPointingUpward)
526
528 "Get loops for font size, advanced horizontally."
529 multiplierX = fontSize / self.unitsPerEM
530 multiplierY = multiplierX
531 if not yAxisPointingUpward:
532 multiplierY = -multiplierY
533 sizedLoops = []
534 for loop in self.loops:
535 sizedLoop = []
536 sizedLoops.append(sizedLoop)
537 for point in loop:
538 sizedLoop.append( complex(multiplierX * (point.real + horizontalAdvanceX), multiplierY * point.imag))
539 return sizedLoops
540
541
543 "Two by three svg matrix."
545 "Initialize."
546 self.tricomplex = tricomplex
547
549 "Get the string representation of this two by three svg matrix."
550 return str(self.tricomplex)
551
553 "Get the other matrix multiplied by this matrix."
554 if otherTricomplex == None:
555 return MatrixSVG(self.tricomplex)
556 if self.tricomplex == None:
557 return MatrixSVG(otherTricomplex)
558 return MatrixSVG(getTricomplexTimesOther(otherTricomplex, self.tricomplex))
559
561 "Get this matrix multiplied by the other matrix."
562 if otherTricomplex == None:
563 return MatrixSVG(self.tricomplex)
564 if self.tricomplex == None:
565 return MatrixSVG(otherTricomplex)
566 return MatrixSVG(getTricomplexTimesOther(self.tricomplex, otherTricomplex))
567
581
590
591
593 "Class to read svg path."
594 - def __init__(self, loops, xmlElement, yAxisPointingUpward):
595 "Add to path string to loops."
596 self.controlPoints = None
597 self.loops = loops
598 self.oldPoint = None
599 self.outlinePaths = []
600 self.path = []
601 self.xmlElement = xmlElement
602 self.yAxisPointingUpward = yAxisPointingUpward
603 pathString = xmlElement.attributeDictionary['d'].replace(',', ' ')
604 global globalProcessPathWordDictionary
605 processPathWordDictionaryKeys = globalProcessPathWordDictionary.keys()
606 for processPathWordDictionaryKey in processPathWordDictionaryKeys:
607 pathString = pathString.replace( processPathWordDictionaryKey, ' %s ' % processPathWordDictionaryKey )
608 self.words = getRightStripMinusSplit(pathString)
609 for self.wordIndex in xrange( len( self.words ) ):
610 word = self.words[ self.wordIndex ]
611 if word in processPathWordDictionaryKeys:
612 globalProcessPathWordDictionary[word](self)
613 if len(self.path) > 0:
614 self.outlinePaths.append(self.path)
615 self.loops += getTransformedOutlineByPaths(self.outlinePaths, xmlElement, yAxisPointingUpward)
616
627
629 "Add a cubic curve to the path."
630 begin = self.getOldPoint()
631 self.controlPoints = controlPoints
632 self.path += getCubicPoints( begin, controlPoints, end )
633 self.wordIndex += 7
634
636 "Add a cubic curve to the path from a reflected control point."
637 begin = self.getOldPoint()
638 controlPointBegin = begin
639 if self.controlPoints != None:
640 if len(self.controlPoints) == 2:
641 controlPointBegin = begin + begin - self.controlPoints[-1]
642 self.controlPoints = [controlPointBegin, controlPoint]
643 self.path += getCubicPoints(begin, self.controlPoints, end)
644 self.wordIndex += 5
645
647 "Add a line to the path."
648 self.controlPoints = None
649 self.path.append(point)
650 self.wordIndex += 3
651 self.addPathLineByFunction(lineFunction)
652
654 "Add an axis line to the path."
655 self.controlPoints = None
656 self.path.append(point)
657 self.wordIndex += 2
658
660 "Add a line to the path by line function."
661 while 1:
662 if self.getFloatByExtraIndex() == None:
663 return
664 self.path.append(lineFunction())
665 self.wordIndex += 2
666
668 "Add an axis line to the path."
669 self.controlPoints = None
670 if len(self.path) > 0:
671 self.outlinePaths.append(self.path)
672 self.oldPoint = self.path[-1]
673 self.path = [point]
674 self.wordIndex += 3
675 self.addPathLineByFunction(lineFunction)
676
678 "Add a quadratic curve to the path."
679 begin = self.getOldPoint()
680 self.controlPoints = [controlPoint]
681 self.path += getQuadraticPoints(begin, controlPoint, end)
682 self.wordIndex += 5
683
685 "Add a quadratic curve to the path from a reflected control point."
686 begin = self.getOldPoint()
687 controlPoint = begin
688 if self.controlPoints != None:
689 if len( self.controlPoints ) == 1:
690 controlPoint = begin + begin - self.controlPoints[-1]
691 self.controlPoints = [ controlPoint ]
692 self.path += getQuadraticPoints(begin, controlPoint, end)
693 self.wordIndex += 3
694
698
702
704 'Get float from the extraIndex.'
705 totalIndex = self.wordIndex + extraIndex
706 if totalIndex >= len(self.words):
707 return None
708 word = self.words[totalIndex]
709 if word[: 1].isalpha():
710 return None
711 return euclidean.getFloatFromValue(word)
712
714 'Get the old point.'
715 if len(self.path) > 0:
716 return self.path[-1]
717 return self.oldPoint
718
722
726
731
737
739 "Process path word H."
740 beginY = self.getOldPoint().imag
741 self.addPathLineAxis(complex(float(self.words[self.wordIndex + 1]), beginY))
742 while 1:
743 floatByExtraIndex = self.getFloatByExtraIndex()
744 if floatByExtraIndex == None:
745 return
746 self.path.append(complex(floatByExtraIndex, beginY))
747 self.wordIndex += 1
748
750 "Process path word h."
751 begin = self.getOldPoint()
752 self.addPathLineAxis(complex(float(self.words[self.wordIndex + 1]) + begin.real, begin.imag))
753 while 1:
754 floatByExtraIndex = self.getFloatByExtraIndex()
755 if floatByExtraIndex == None:
756 return
757 self.path.append(complex(floatByExtraIndex + self.getOldPoint().real, begin.imag))
758 self.wordIndex += 1
759
763
767
771
775
779
784
788
793
797
801
803 "Process path word V."
804 beginX = self.getOldPoint().real
805 self.addPathLineAxis(complex(beginX, float(self.words[self.wordIndex + 1])))
806 while 1:
807 floatByExtraIndex = self.getFloatByExtraIndex()
808 if floatByExtraIndex == None:
809 return
810 self.path.append(complex(beginX, floatByExtraIndex))
811 self.wordIndex += 1
812
814 "Process path word v."
815 begin = self.getOldPoint()
816 self.addPathLineAxis(complex(begin.real, float(self.words[self.wordIndex + 1]) + begin.imag))
817 while 1:
818 floatByExtraIndex = self.getFloatByExtraIndex()
819 if floatByExtraIndex == None:
820 return
821 self.path.append(complex(begin.real, floatByExtraIndex + self.getOldPoint().imag))
822 self.wordIndex += 1
823
832
836
837
839 "An svg carving."
841 "Add empty lists."
842 self.bridgeRotation = None
843 self.rotatedLoopLayers = []
844 self.sliceDictionary = None
845 self.stopProcessing = False
846 self.z = 0.0
847
857
859 "Return the rotated loop layer."
860 if self.z != None:
861 rotatedLoopLayer = euclidean.RotatedLoopLayer( self.z )
862 self.rotatedLoopLayers.append( rotatedLoopLayer )
863 rotatedLoopLayer.rotation = self.bridgeRotation
864 self.z = None
865 return self.rotatedLoopLayers[-1]
866
868 "Parse SVG text and store the layers."
869 self.fileName = fileName
870 xmlParser = XMLSimpleReader(fileName, None, svgText)
871 self.root = xmlParser.getRoot()
872 if self.root == None:
873 print('Warning, root was None in parseSVG in SVGReader, so nothing will be done for:')
874 print(fileName)
875 return
876 self.parseSVGByXMLElement(self.root)
877
886
902
903
904 globalFontFileNames = None
905 globalFontReaderDictionary = {}
906 globalGetTricomplexDictionary = {}
907 globalGetTricomplexFunctions = [
908 getTricomplexmatrix,
909 getTricomplexrotate,
910 getTricomplexscale,
911 getTricomplexskewX,
912 getTricomplexskewY,
913 getTricomplextranslate ]
914 globalProcessPathWordFunctions = [
915 PathReader.processPathWordA,
916 PathReader.processPathWorda,
917 PathReader.processPathWordC,
918 PathReader.processPathWordc,
919 PathReader.processPathWordH,
920 PathReader.processPathWordh,
921 PathReader.processPathWordL,
922 PathReader.processPathWordl,
923 PathReader.processPathWordM,
924 PathReader.processPathWordm,
925 PathReader.processPathWordQ,
926 PathReader.processPathWordq,
927 PathReader.processPathWordS,
928 PathReader.processPathWords,
929 PathReader.processPathWordT,
930 PathReader.processPathWordt,
931 PathReader.processPathWordV,
932 PathReader.processPathWordv,
933 PathReader.processPathWordZ,
934 PathReader.processPathWordz ]
935 globalProcessPathWordDictionary = {}
936 globalProcessSVGElementDictionary = {}
937 globalProcessSVGElementFunctions = [
938 processSVGElementcircle,
939 processSVGElementellipse,
940 processSVGElementg,
941 processSVGElementline,
942 processSVGElementpath,
943 processSVGElementpolygon,
944 processSVGElementpolyline,
945 processSVGElementrect,
946 processSVGElementtext ]
947 globalSideAngle = 0.5 * math.pi / float( globalNumberOfCornerPoints )
948
949
950 addFunctionsToDictionary( globalGetTricomplexDictionary, globalGetTricomplexFunctions, 'getTricomplex')
951 addFunctionsToDictionary( globalProcessPathWordDictionary, globalProcessPathWordFunctions, 'processPathWord')
952 addFunctionsToDictionary( globalProcessSVGElementDictionary, globalProcessSVGElementFunctions, 'processSVGElement')
953