30 svg_ns = '{http://www.w3.org/2000/svg}' |
30 svg_ns = '{http://www.w3.org/2000/svg}' |
31 |
31 |
32 # Regex commonly used |
32 # Regex commonly used |
33 number_re = r'[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?' |
33 number_re = r'[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?' |
34 unit_re = r'em|ex|px|in|cm|mm|pt|pc|%' |
34 unit_re = r'em|ex|px|in|cm|mm|pt|pc|%' |
|
35 point_re = r'(?:\d+(?:\.\d*)?|\.\d+),(?:\d+(?:\.\d*)?|\.\d+)' |
35 |
36 |
36 # Unit converter |
37 # Unit converter |
37 unit_convert = { |
38 unit_convert = { |
38 None: 1, # Default unit (same as pixel) |
39 None: 1, # Default unit (same as pixel) |
39 'px': 1, # px: pixel. Default SVG unit |
40 'px': 1, # px: pixel. Default SVG unit |
496 for seg in self.segments(precision): |
497 for seg in self.segments(precision): |
497 ret.append(simplify_segment(seg, precision)) |
498 ret.append(simplify_segment(seg, precision)) |
498 |
499 |
499 return ret |
500 return ret |
500 |
501 |
|
502 |
|
503 class Polygon(Transformable): |
|
504 '''SVG <polygon>''' |
|
505 # class Path handles the <polygon> tag |
|
506 tag = 'polygon' |
|
507 |
|
508 def __init__(self, elt=None): |
|
509 Transformable.__init__(self, elt) |
|
510 if elt is not None: |
|
511 self.style = elt.get('style') |
|
512 self.parse(elt.get('points')) |
|
513 |
|
514 def parse(self, pathstr): |
|
515 """Parse path string and build elements list""" |
|
516 |
|
517 pathlst = re.findall(point_re, pathstr) |
|
518 |
|
519 #pathlst.reverse() |
|
520 |
|
521 current_pt = None |
|
522 start_pt = None |
|
523 while pathlst: |
|
524 coord = pathlst.pop().split(",") |
|
525 pt = Point(coord[0], coord[1]) |
|
526 |
|
527 if start_pt: |
|
528 current_pt = pt |
|
529 l = Segment(start_pt, current_pt) |
|
530 self.items.append(l) |
|
531 start_pt = current_pt |
|
532 else: |
|
533 start_pt = pt |
|
534 self.items.append(MoveTo(pt)) |
|
535 |
|
536 def __str__(self): |
|
537 return '\n'.join(str(x) for x in self.items) |
|
538 |
|
539 def __repr__(self): |
|
540 return '<Polygon ' + self.id + '>' |
|
541 |
|
542 def segments(self, precision=0): |
|
543 '''Return a list of segments, each segment is ended by a MoveTo. |
|
544 A segment is a list of Points''' |
|
545 ret = [] |
|
546 # group items separated by MoveTo |
|
547 for moveTo, group in itertools.groupby(self.items, |
|
548 lambda x: isinstance(x, MoveTo)): |
|
549 # Use only non MoveTo item |
|
550 if not moveTo: |
|
551 # Generate segments for each relevant item |
|
552 seg = [x.segments(precision) for x in group] |
|
553 # Merge all segments into one |
|
554 ret.append(list(itertools.chain.from_iterable(seg))) |
|
555 |
|
556 return ret |
|
557 |
|
558 def simplify(self, precision): |
|
559 '''Simplify segment with precision: |
|
560 Remove any point which are ~aligned''' |
|
561 ret = [] |
|
562 for seg in self.segments(precision): |
|
563 ret.append(simplify_segment(seg, precision)) |
|
564 |
|
565 return ret |
|
566 |
|
567 |
501 class Ellipse(Transformable): |
568 class Ellipse(Transformable): |
502 '''SVG <ellipse>''' |
569 '''SVG <ellipse>''' |
503 # class Ellipse handles the <ellipse> tag |
570 # class Ellipse handles the <ellipse> tag |
504 tag = 'ellipse' |
571 tag = 'ellipse' |
505 |
572 |