Fix arcpoly conversion bugs
This commit is contained in:
parent
f3c95a42d4
commit
2ce55ebdca
3 changed files with 58 additions and 21 deletions
|
|
@ -337,8 +337,9 @@ class Region(GraphicObject):
|
|||
], unit=unit)
|
||||
|
||||
@classmethod
|
||||
def from_arc_poly(kls, arc_poly, polarity_dark=True, unit=MM):
|
||||
return kls(arc_poly.outline, arc_poly.arc_centers, polarity_dark=polarity_dark, unit=unit)
|
||||
def from_arc_poly(kls, arc_poly, polarity_dark=None, unit=MM):
|
||||
polarity = arc_poly.polarity_dark if polarity_dark is None else polarity_dark
|
||||
return kls(arc_poly.outline, arc_poly.arc_centers, polarity_dark=polarity, unit=unit)
|
||||
|
||||
def append(self, obj):
|
||||
if obj.unit != self.unit:
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class Circle(GraphicPrimitive):
|
|||
|
||||
def to_arc_poly(self):
|
||||
return ArcPoly([(self.x-self.r, self.y), (self.x+self.r, self.y)],
|
||||
[(True, (self.x, self.y)), (True, (self.x, self.y))])
|
||||
[(True, (self.x, self.y)), (True, (self.x, self.y))],
|
||||
polarity_dark=self.polarity_dark)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -218,24 +219,30 @@ class Line(GraphicPrimitive):
|
|||
color = fg if self.polarity_dark else bg
|
||||
width = f'{self.width:.6}' if not math.isclose(self.width, 0) else '0.01mm'
|
||||
return tag('path', d=f'M {float(self.x1):.6} {float(self.y1):.6} L {float(self.x2):.6} {float(self.y2):.6}',
|
||||
fill='none', stroke=color, stroke_width=str(width))
|
||||
fill='none', stroke=color, stroke_width=str(width), stroke_linecap='round')
|
||||
|
||||
def to_arc_poly(self):
|
||||
l = math.dist((self.x1, self.y1), (self.x2, self.y2))
|
||||
if math.isclose(l, 0):
|
||||
# degenerate case: a zero-length line becomes a circle.
|
||||
return ArcPoly([(self.x1-self.width/2, self.y1), (self.x1+self.width/2, self.y1)],
|
||||
[(True, (self.x1, self.y1)), (True, (self.x1, self.y1))],
|
||||
polarity_dark=self.polarity_dark)
|
||||
|
||||
dx, dy = self.x2-self.x1, self.y2-self.y1
|
||||
nx, ny = -dy/l, dx/l
|
||||
rx, ry = nx*self.width/2, ny*self.width/2
|
||||
return ArcPoly([
|
||||
(self.x1+rx, self.y1+ry),
|
||||
(self.x1-rx, self.y1-ry),
|
||||
(self.x2-rx, self.y2-ry),
|
||||
(self.x2+rx, self.y2+ry),
|
||||
(self.x2-rx, self.y2-ry),
|
||||
(self.x1-rx, self.y1-ry),
|
||||
(self.x1+rx, self.y1+ry),
|
||||
], [
|
||||
(True, (self.x1, self.y1)),
|
||||
None,
|
||||
(True, (self.x2, self.y2)),
|
||||
None,
|
||||
])
|
||||
(True, (self.x1, self.y1)),
|
||||
None,
|
||||
], polarity_dark=self.polarity_dark)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -276,25 +283,32 @@ class Arc(GraphicPrimitive):
|
|||
arc = svg_arc((self.x1, self.y1), (self.x2, self.y2), (self.cx, self.cy), self.clockwise)
|
||||
width = f'{self.width:.6}' if not math.isclose(self.width, 0) else '0.01mm'
|
||||
return tag('path', d=f'M {float(self.x1):.6} {float(self.y1):.6} {arc}',
|
||||
fill='none', stroke=color, stroke_width=width)
|
||||
fill='none', stroke=color, stroke_width=width, stroke_linecap='round')
|
||||
|
||||
def to_arc_poly(self):
|
||||
r = math.dist((self.x1, self.y1), (self.cx, self.cy))
|
||||
|
||||
if math.isclose(r, 0):
|
||||
# degenerate case: a zero-radius arc becomes a circle.
|
||||
return ArcPoly([(self.x1-self.width/2, self.y1), (self.x1+self.width/2, self.y1)],
|
||||
[(True, (self.x1, self.y1)), (True, (self.x1, self.y1))],
|
||||
polarity_dark=self.polarity_dark)
|
||||
|
||||
dx1, dy1 = self.x1-self.cx, self.y1-self.cy
|
||||
nx1, ny1 = dx1/r * self.width/2, dy1/r * self.width/2
|
||||
dx2, dy2 = self.x2-self.cx, self.y2-self.cy
|
||||
nx2, ny2 = dx2/r * self.width/2, dy2/r * self.width/2
|
||||
return ArcPoly([
|
||||
(self.x1+nx1, self.y1+nx1),
|
||||
(self.x1-nx1, self.y1-nx1),
|
||||
(self.x2-nx2, self.y2-nx2),
|
||||
(self.x2+nx2, self.y2+nx2),
|
||||
], [
|
||||
(self.clockwise, (self.x1, self.y1)),
|
||||
return ArcPoly([ # vertices
|
||||
(self.x1+nx1, self.y1+ny1),
|
||||
(self.x1-nx1, self.y1-ny1),
|
||||
(self.x2-nx2, self.y2-ny2),
|
||||
(self.x2+nx2, self.y2+ny2),
|
||||
], [ # arc segments (direction, center)
|
||||
(not self.clockwise, (self.x1, self.y1)),
|
||||
(self.clockwise, (self.cx, self.cy)),
|
||||
(self.clockwise, (self.x2, self.y2)),
|
||||
(self.clockwise, (self.cx, self.cy)),
|
||||
])
|
||||
(not self.clockwise, (self.cx, self.cy)),
|
||||
], polarity_dark=self.polarity_dark)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -323,7 +337,7 @@ class Rectangle(GraphicPrimitive):
|
|||
(x - (cw+sh), y + (ch+sw)),
|
||||
(x + (cw+sh), y + (ch+sw)),
|
||||
(x + (cw+sh), y - (ch+sw)),
|
||||
])
|
||||
], polarity_dark=self.polarity_dark)
|
||||
|
||||
def to_svg(self, fg='black', bg='white', tag=Tag):
|
||||
color = fg if self.polarity_dark else bg
|
||||
|
|
|
|||
|
|
@ -47,8 +47,25 @@ def object_test(tmpfile, img_support, epsilon=1e-4):
|
|||
|
||||
out_svg = tmpfile('SVG Output', '.svg')
|
||||
with open(out_svg, 'w') as f:
|
||||
# Use inch units here to make sure we and gerbv agree on the exact pixel size of the output since both calculate
|
||||
# it from the DPI setting.
|
||||
f.write(str(gbr.to_svg(force_bounds=bounds, arg_unit='inch', fg='black', bg='white')))
|
||||
|
||||
# test primitive to_arc_poly
|
||||
arc_poly_gbr = GerberFile()
|
||||
for obj in gbr.objects:
|
||||
for primitive in obj.to_primitives(MM):
|
||||
poly = primitive.to_arc_poly()
|
||||
arc_poly_gbr.objects.append(Region.from_arc_poly(poly))
|
||||
|
||||
arc_poly_svg = tmpfile('ArcPoly SVG Output', '.svg')
|
||||
with open(arc_poly_svg, 'w') as f:
|
||||
f.write(str(arc_poly_gbr.to_svg(force_bounds=bounds, arg_unit='inch', fg='black', bg='white')))
|
||||
|
||||
arc_poly_png = tmpfile('ArcPoly conversion render', '.png')
|
||||
img_support.svg_to_png(arc_poly_svg, arc_poly_png, dpi=300, bg='white')
|
||||
|
||||
# Reference export via gerber through GerbV
|
||||
out_gbr = tmpfile('GBR Output', '.gbr')
|
||||
gbr.save(out_gbr)
|
||||
|
||||
|
|
@ -70,6 +87,11 @@ def object_test(tmpfile, img_support, epsilon=1e-4):
|
|||
assert mean < epsilon
|
||||
assert hist[3:].sum() < epsilon*hist.size
|
||||
|
||||
mean, _max, hist = img_support.image_difference(out_png, arc_poly_png, diff_out=tmpfile('ArcPoly Difference', '.png'))
|
||||
assert hist[9] < 1
|
||||
assert mean < epsilon
|
||||
assert hist[3:].sum() < epsilon*hist.size
|
||||
|
||||
@pytest.mark.parametrize('angle_deg', [0, 5, -5, 10, -10, 15, -15, 30, -30, 45, -45, 60, -60, 75, -75, 90, -90, 120, -120, 180, 153, 155, 157])
|
||||
def test_line(angle_deg, tmpfile, img_support):
|
||||
with object_test(tmpfile, img_support) as gbr:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue