def parse_t(self, data, is_relative): """ Parse a T or t (quadratic shorthand bezier) segment. """ points, data = self.parse_points(data) while points: start = self.cur_point end, points = points[0], points[1:] self.cur_point = end = self.get_path_point(end, is_relative) if self.prev_cmd not in 'qt' or not self.prev_ctl: ctl = start else: ctl = (start[0] - (self.prev_ctl[0] - start[0]), start[1] - (self.prev_ctl[1] - start[1])) self.prev_ctl = ctl ctl1 = (start[0] + (2.0 / 3.0 * (ctl[0] - start[0])), start[1] + (2.0 / 3.0 * (ctl[1] - start[1]))) ctl2 = (end[0] + (2.0 / 3.0 * (ctl[0] - end[0])), end[1] + (2.0 / 3.0 * (ctl[1] - end[1]))) self.shapes.append( BezierCurve(make_point(ctl1, self.svg_mult), make_point(ctl2, self.svg_mult), make_point(start, self.svg_mult), make_point(end, self.svg_mult))) return data
def parse_s(self, data, is_relative): """ Parse an S or s (cubic shorthand bezier) segment. """ points, data = self.parse_points(data) while points: start = self.cur_point (ctl2, end), points = points[:2], points[2:] self.cur_point = ctl2 = self.get_path_point(ctl2, is_relative) self.cur_point = end = self.get_path_point(end, is_relative) if self.prev_cmd not in 'cs' or not self.prev_ctl: ctl1 = start else: ctl1 = (start[0] - (self.prev_ctl[0] - start[0]), start[1] - (self.prev_ctl[1] - start[1])) self.prev_ctl = ctl2 self.shapes.append( BezierCurve(make_point(ctl1, self.svg_mult), make_point(ctl2, self.svg_mult), make_point(start, self.svg_mult), make_point(end, self.svg_mult))) return data
def parse_q(self, data, is_relative): """ Parse a Q or q (quadratic bezier) segment. """ points, data = self.parse_points(data) while points: start = self.cur_point (ctl, end), points = points[:2], points[2:] self.cur_point = ctl = self.get_path_point(ctl, is_relative) self.cur_point = end = self.get_path_point(end, is_relative) self.prev_ctl = ctl ctl1 = (start[0] + (2.0 / 3.0 * (ctl[0] - start[0])), start[1] + (2.0 / 3.0 * (ctl[1] - start[1]))) ctl2 = (end[0] + (2.0 / 3.0 * (ctl[0] - end[0])), end[1] + (2.0 / 3.0 * (ctl[1] - end[1]))) self.shapes.append( BezierCurve(make_point(ctl1, self.svg_mult), make_point(ctl2, self.svg_mult), make_point(start, self.svg_mult), make_point(end, self.svg_mult))) return data
def test_bezier_curve(self): """ Convert bezier to lines shape """ bezier = BezierCurve((0, 0), (1, 1), (2, 2), (3, 3)) writer = Specctra() writer.resolution = specctraobj.Resolution() writer.resolution.unit = 'mil' writer.resolution.resolution = 10 obj = writer._convert_shape(bezier) self.assertEqual( to_string(writer, obj), '( (path signal 10.416667 20.833333 20.833333 20.833333 20.833333)' + ' (path signal 10.416667 20.833333 20.833333 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 10.416667 10.416667)' + ' (path signal 10.416667 10.416667 10.416667 20.833333 20.833333)' + ' (path signal 10.416667 20.833333 20.833333 20.833333 20.833333)' + ' (path signal 10.416667 20.833333 20.833333 20.833333 20.833333)' + ' (path signal 10.416667 20.833333 20.833333 31.250000 31.250000) )' )
def test_bezier_curve(self): """ BezierCurves are output correctly. """ writer = KiCAD() bezier = BezierCurve((0, 0), (1, 1), (2, 2), (3, 3)) line = writer.get_shape_line(bezier) self.assertEqual(line, 'P 2 %(unit)d %(convert)d 0 22 22 33 33 N\n')
def parse_shape(self, shape): """ Extract a shape. """ # pylint: disable=R0914 # pylint: disable=R0911 typ = shape.get('type') if 'rectangle' == typ: x = int(shape.get('x')) y = int(shape.get('y')) height = int(shape.get('height')) width = int(shape.get('width')) parsed_shape = Rectangle(x, y, width, height) elif 'rounded_rectangle' == typ: x = int(shape.get('x')) y = int(shape.get('y')) height = int(shape.get('height')) width = int(shape.get('width')) radius = int(shape.get('radius')) parsed_shape = RoundedRectangle(x, y, width, height, radius) elif 'arc' == typ: x = int(shape.get('x')) y = int(shape.get('y')) start_angle = float(shape.get('start_angle')) end_angle = float(shape.get('end_angle')) radius = int(shape.get('radius')) parsed_shape = Arc(x, y, start_angle, end_angle, radius) elif 'circle' == typ: x = int(shape.get('x')) y = int(shape.get('y')) radius = int(shape.get('radius')) parsed_shape = Circle(x, y, radius) elif 'label' == typ: x = int(shape.get('x')) y = int(shape.get('y')) rotation = float(shape.get('rotation')) text = shape.get('text') align = shape.get('align') parsed_shape = Label(x, y, text, align, rotation) elif 'line' == typ: p1 = self.parse_point(shape.get('p1')) p2 = self.parse_point(shape.get('p2')) parsed_shape = Line(p1, p2) elif 'polygon' == typ: parsed_shape = Polygon() for point in shape.get('points'): parsed_shape.add_point(self.parse_point(point)) elif 'bezier' == typ: control1 = self.parse_point(shape.get('control1')) control2 = self.parse_point(shape.get('control2')) p1 = self.parse_point(shape.get('p1')) p2 = self.parse_point(shape.get('p2')) parsed_shape = BezierCurve(control1, control2, p1, p2) parsed_shape.styles = shape.get('styles') or {} parsed_shape.attributes = shape.get('attributes') or {} return parsed_shape
def parse_c(self, data, is_relative): """ Parse a C or c (cubic bezier) segment. """ points, data = self.parse_points(data) while points: start = self.cur_point (ctl1, ctl2, end), points = points[:3], points[3:] self.cur_point = ctl1 = self.get_path_point(ctl1, is_relative) self.cur_point = ctl2 = self.get_path_point(ctl2, is_relative) self.cur_point = end = self.get_path_point(end, is_relative) self.prev_ctl = ctl2 self.shapes.append( BezierCurve(make_point(ctl1, self.svg_mult), make_point(ctl2, self.svg_mult), make_point(start, self.svg_mult), make_point(end, self.svg_mult))) return data
def parse_shape(self, shape): """ Extract a shape. """ # pylint: disable=R0914 # pylint: disable=R0911 rotation = shape.get('rotation', 0.0) flip_horizontal = shape.get('flip_horizontal', False) shape_type = shape.get('type') if 'rectangle' == shape_type: x = int(shape.get('x')) y = int(shape.get('y')) height = int(shape.get('height')) width = int(shape.get('width')) parsed_shape = Rectangle(x, y, width, height) elif 'rounded_rectangle' == shape_type: x = int(shape.get('x')) y = int(shape.get('y')) height = int(shape.get('height')) width = int(shape.get('width')) radius = int(shape.get('radius')) parsed_shape = RoundedRectangle(x, y, width, height, radius) elif 'arc' == shape_type: x = int(shape.get('x')) y = int(shape.get('y')) start_angle = float(shape.get('start_angle')) end_angle = float(shape.get('end_angle')) radius = int(shape.get('radius')) parsed_shape = Arc(x, y, start_angle, end_angle, radius) elif 'circle' == shape_type: x = int(shape.get('x')) y = int(shape.get('y')) radius = int(shape.get('radius')) parsed_shape = Circle(x, y, radius) elif 'label' == shape_type: parsed_shape = self.parse_label(shape) elif 'line' == shape_type: p1 = self.parse_point(shape.get('p1')) p2 = self.parse_point(shape.get('p2')) parsed_shape = Line(p1, p2) elif 'polygon' == shape_type: parsed_shape = Polygon() for point in shape.get('points'): parsed_shape.add_point(self.parse_point(point)) elif 'bezier' == shape_type: control1 = self.parse_point(shape.get('control1')) control2 = self.parse_point(shape.get('control2')) p1 = self.parse_point(shape.get('p1')) p2 = self.parse_point(shape.get('p2')) parsed_shape = BezierCurve(control1, control2, p1, p2) elif 'rounded_segment' == shape_type: p1 = self.parse_point(shape.get('p1')) p2 = self.parse_point(shape.get('p2')) width = int(shape.get('width')) parsed_shape = RoundedSegment(p1, p2, width) parsed_shape.rotation = rotation parsed_shape.flip_horizontal = flip_horizontal parsed_shape.styles = shape.get('styles') or {} parsed_shape.attributes = shape.get('attributes') or {} return parsed_shape
def setUp(self): """ Setup the test case. """ self.curve = BezierCurve((2, 9), (9, 8), (1, 1), (7, 2))
class BezierCurveTests(unittest.TestCase): """ The tests of the core module bezier shape """ def setUp(self): """ Setup the test case. """ self.curve = BezierCurve((2, 9), (9, 8), (1, 1), (7, 2)) def tearDown(self): """ Teardown the test case. """ del self.curve def test_create_new_bezier_curve(self): """ Test the creation of a new empty bezier. """ control1 = Point(2, 9) control2 = Point(9, 8) p1 = Point(1, 1) p2 = Point(7, 2) assert self.curve.control1.x == control1.x assert self.curve.control1.y == control1.y assert self.curve.control2.x == control2.x assert self.curve.control2.y == control2.y assert self.curve.p1.x == p1.x assert self.curve.p1.y == p1.y assert self.curve.p2.x == p2.x assert self.curve.p2.y == p2.y def interp_bezier(self, points, typ): return tuple([int(round(((1 - typ) ** 3) * pts[0] + 3 * ((1 - typ) ** 2) * typ * pts[1] + 3 * (1 - typ) * (typ ** 2) * pts[2] + (typ ** 3) * pts[3])) for pts in ([pt.x for pt in points], [pt.y for pt in points])]) def bez_recurse(self, pts, lo, hi): """Helper method to draw a bezier curve""" # kind of important that we don't just copy how it's done in the method # to be tested, so do it by recusively bisecting the curve until we hit # the necessary resolution [plo, phi] = [self.interp_bezier(pts, typ) for typ in (lo, hi)] if abs(plo[0] - phi[0]) <= 1 and abs(plo[1] - phi[1]) <= 1: return [plo, phi] mid = (lo + hi) / 2. bot_half = self.bez_recurse(pts, lo, mid) top_half = self.bez_recurse(pts, mid, hi) if bot_half[-1] == top_half[0]: bot_half = bot_half[:-1] return bot_half + top_half def test_bezier_min_point(self): points = self.bez_recurse([self.curve.p1, self.curve.control1, self.curve.control2, self.curve.p2], 0., 1.) x = min([pt[0] for pt in points]) y = min([pt[1] for pt in points]) min_pt = self.curve.min_point() self.assertEqual(min_pt.x, x) self.assertEqual(min_pt.y, y) def test_bezier_max_point(self): points = self.bez_recurse([self.curve.p1, self.curve.control1, self.curve.control2, self.curve.p2], 0., 1.) x = max([pt[0] for pt in points]) y = max([pt[1] for pt in points]) max_pt = self.curve.max_point() self.assertEqual(max_pt.x, x) self.assertEqual(max_pt.y, y)