def parse_a_line(self, parts): """ Parse an A (Arc) line """ x, y, radius, start, end = [int(i) for i in parts[1:6]] # convert tenths of degrees to pi radians start = start / 1800.0 end = end / 1800.0 return Arc(x, y, end, start, radius)
def test_create_new_arc(self): """ Test the creation of a new empty arc. """ arc = Arc(0, 1, 2, 3, 4) assert arc.x == 0 assert arc.y == 1 assert arc.start_angle == 2 assert arc.end_angle == 3 assert arc.radius == 4
def test_arc(self): """ Arcs are output correctly. """ writer = KiCAD() arc = Arc(0, 0, -0.5, 0.5, 1) line = writer.get_shape_line(arc) self.assertEqual(line, 'A 0 0 11 900 -900 %(unit)d %(convert)d 0 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_arc(self, args): """ Returns a parsed arc. """ # ViewDraw saves arcs as three points along a circle. Start, mid, end # [not entirely sure that mid is a midpoint, but irrelevant here]. We # need to find the centre of that circle, and the angles of the start # and end points. Tracing from start to end, the arcs are always CCW. # To find the centre: construct two chords using the three points. Lines # drawn perpendicular to and bisecting these chords will intersect at # the circle's centre. x0, y0, x1, y1, x2, y2 = [float(pt) for pt in args.split()] # can't allow for infinite slopes (m_a and m_b), and can't allow m_a # to be a zero slope. while abs(x0 - x1) < 0.1 or abs(x1 - x2) < 0.1 or abs(y0 - y1) < 0.1: x0, y0, x1, y1, x2, y2 = x1, y1, x2, y2, x0, y0 # slopes of the chords m_a, m_b = (y1 - y0) / (x1 - x0), (y2 - y1) / (x2 - x1) # find the centre xcenter = ((m_a * m_b * (y0 - y2) + m_b * (x0 + x1) - m_a * (x1 + x2)) / (2 * (m_b - m_a))) ycenter = (-1 / m_a) * (xcenter - (x0 + x1) / 2) + (y0 + y1) / 2 # radius is the distance from the centre to any of the three points rad = sqrt((xcenter - x0)**2 + (ycenter - y0)**2) # re-init xs,ys so that start and end points don't get confused. x0, y0, x1, y1, x2, y2 = [float(pt) for pt in args.split()] def angle(x, y): """ Calculate the angle from the center of the arc to (x, y). """ # as parsed, the angle increases CCW. Here, we return an angle # increasing CW opp = y - ycenter adj = x - xcenter if abs(adj) < 0.01: # vertical line to x,y if opp > 0: return 3 * pi / 2 else: return pi / 2 ang = atan(opp / adj) # correct for ambiguity due to atan if adj < 0: ang += pi # restrict angle to (0, 2pi) range ang = ang % (2 * pi) # upverter uses CW angles, so... return 2 * pi - ang return ('shape', Arc(int(round(xcenter)), int(round(ycenter)), angle(x2, y2) / pi, angle(x0, y0) / pi, int(round(rad))))
def _draw_arc(self, end_pts, center_offset): """ Convert arc path into shape. """ start, end = end_pts offset = {'i': center_offset[0], 'j': center_offset[1]} for k in offset: if offset[k] is None: offset[k] = 0 center, radius = self._get_ctr_and_radius(end_pts, offset) start_angle = self._get_angle(center, start) end_angle = self._get_angle(center, end) clockwise = 'ANTI' not in self.status['interpolation'] self._check_mq(start_angle, end_angle, clockwise) return Arc(center.x, center.y, start_angle if clockwise else end_angle, end_angle if clockwise else start_angle, radius)
def make_shape_for_wire(self, wire): """ Generate an openjson shape for an eaglexml wire. """ if wire.curve is None: return Line((self.make_length(wire.x1), self.make_length(wire.y1)), (self.make_length(wire.x2), self.make_length(wire.y2))) curve, x1, y1, x2, y2 = map( float, (wire.curve, wire.x1, wire.y1, wire.x2, wire.y2)) if curve < 0: curve = -curve negative = True mult = -1.0 else: negative = False mult = 1.0 if curve > 180.0: major_arc = True curve = 360.0 - curve mult *= -1.0 else: major_arc = False chordlen = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)) radius = chordlen / (2.0 * sin(radians(curve) / 2)) mx, my = (x1 + x2) / 2, (y1 + y2) / 2 # midpoint between arc points h = sqrt(pow(radius, 2) - pow(chordlen / 2, 2)) # height of isoceles # calculate center point cx = mx + mult * h * (y1 - y2) / chordlen cy = my + mult * h * (x2 - x1) / chordlen if negative: start_angle = atan2(y2 - cy, x2 - cx) end_angle = start_angle + radians(curve) - (pi if major_arc else 0.0) else: start_angle = atan2(y1 - cy, x1 - cx) end_angle = start_angle + radians(curve) + (pi if major_arc else 0.0) return Arc(self.make_length(cx), self.make_length(cy), round(start_angle / pi, 3) % 2.0, round(end_angle / pi, 3) % 2.0, self.make_length(radius))
def test_arc(self): """ Convert arc to lines shape """ arc = Arc(0, 0, -0.5, 0.5, 1) writer = Specctra() obj = writer._convert_shape(arc) self.assertEqual( to_string(writer, obj), '( (path signal 10.416667 -0.000000 -10.416667 -6.122763 -8.427260)' + ' (path signal 10.416667 -6.122763 -8.427260 -9.906839 -3.218927)' + ' (path signal 10.416667 -9.906839 -3.218927 -9.906839 3.218927)' + ' (path signal 10.416667 -9.906839 3.218927 -6.122763 8.427260)' + ' (path signal 10.416667 -6.122763 8.427260 -0.000000 10.416667) )' )
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 make_arc(p1, p2, p0): start_angle = math.atan2(p1.y - p0.y, p1.x - p0.x) / math.pi end_angle = math.atan2(p2.y - p0.y, p2.x - p0.x) / math.pi return Arc(p0.x, p0.y, start_angle, end_angle, aperture)
def test_max_point_arc_wraparound(self): """max_point() of an arc that traces through 0 degrees""" arc = Arc(2, 3, 1.75, 0.25, 5) self.assertEqual(arc.max_point().x, 5 + 2) self.assertEqual(arc.max_point().y, int(round(sin(0.25 * pi) * 5 + 3)))
def test_max_point_arc(self): """max_point() of an arc tracing bottom-right quarter""" arc = Arc(2, 3, 0, 0.5, 5) self.assertEqual(arc.max_point().x, 7) self.assertEqual(arc.max_point().y, 8)
def test_min_point_arc(self): """min_point() of an arc tracing top-left quarter""" arc = Arc(2, 3, 1, 1.5, 5) self.assertEqual(arc.min_point().x, -3) self.assertEqual(arc.min_point().y, -2)
def test_max_point_arc_is_circle(self): '''max_point() when an arc actually traces out a full circle''' arc = Arc(2, 3, 0, 2, 5) self.assertEqual(arc.max_point().x, 7) self.assertEqual(arc.max_point().y, 8)
def test_min_point_arc_is_circle(self): """min_point() when an arc actually traces out a full circle""" arc = Arc(2, 3, 0, 2, 5) self.assertEqual(arc.min_point().x, -3) self.assertEqual(arc.min_point().y, -2)