def test_add_points_to_empty_bounding_box(self): box = Bounds() p1 = Point(-5, 2, 0) p2 = Point(7, 0, -3) box.add_point(p1) box.add_point(p2) self.assertEqual(box.min, Point(-5, 0, -3)) self.assertEqual(box.max, Point(7, 2, 0))
def bounds_of(self) -> Bounds: box = Bounds() box.add_point(self.p1) box.add_point(self.p2) box.add_point(self.p3) return box
class SvgLoopTracer(object): def __init__(self): self.loops = [] self.bounds = Bounds() def get_point(self, command): x = command[1] y = -command[2] self.bounds.add_point(x, y) return x, y def onMove(self, command): x, y = self.get_point(command) self.current_path = [(x, y)] def onLine(self, command): x, y = self.get_point(command) self.current_path.append((x, y)) def onClose(self, command): if self.current_path[0] == self.current_path[-1]: self.current_path = self.current_path[:-1] if len(self.current_path) < 3: raise ParseError('loop needs 3 or more verts') self.loops.append(self.current_path) self.current_path = None def onBadCommand(self, action): msg = 'unsupported svg path command: %s' % (action,) raise ParseError(msg) def to_loops(self, commands): ''' commands : list of tuples, as output from to_tuples() method, eg: [('M', 1, 2), ('L', 3, 4), ('L', 5, 6), ('z')] Interprets the command characters at the start of each tuple to return a list of loops, where each loop is a closed list of verts, and each vert is a pair of ints or floats, eg: [[1, 2, 3, 4, 5, 6]] Note that the final point of each loop is eliminated if it is equal to the first. SVG defines commands: M x,y: move, start a new loop L x,y: line, draw boundary H x: move horizontal V y: move vertical Z: close current loop - join to start point Lower-case command letters (eg 'm') indicate a relative offset. See http://www.w3.org/TR/SVG11/paths.html ''' lookup = { 'M': self.onMove, 'L': self.onLine, 'Z': self.onClose, 'z': self.onClose, } self.loops = [] self.current_path = None self.bounds.reset() for command in commands: action = command[0] if action in lookup: lookup[action](command) else: self.onBadCommand(action) return self.loops