summaryrefslogtreecommitdiff
path: root/gerbonara/cad/kicad
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-10-26 23:53:23 +0200
committerjaseg <git@jaseg.de>2023-10-26 23:53:23 +0200
commit36da1fd68bcfb44957d370584231545cee0b2e20 (patch)
tree7bf1730a71392ab3de33010a56edf3ce0a2a09e6 /gerbonara/cad/kicad
parent9624e46147755d221c8e7cf519e9ecd416381857 (diff)
downloadgerbonara-36da1fd68bcfb44957d370584231545cee0b2e20.tar.gz
gerbonara-36da1fd68bcfb44957d370584231545cee0b2e20.tar.bz2
gerbonara-36da1fd68bcfb44957d370584231545cee0b2e20.zip
Fix failing test cases
Diffstat (limited to 'gerbonara/cad/kicad')
-rw-r--r--gerbonara/cad/kicad/base_types.py17
-rw-r--r--gerbonara/cad/kicad/footprints.py29
-rw-r--r--gerbonara/cad/kicad/graphical_primitives.py22
-rw-r--r--gerbonara/cad/kicad/primitives.py25
-rw-r--r--gerbonara/cad/kicad/symbols.py27
5 files changed, 78 insertions, 42 deletions
diff --git a/gerbonara/cad/kicad/base_types.py b/gerbonara/cad/kicad/base_types.py
index 32717fb..1161996 100644
--- a/gerbonara/cad/kicad/base_types.py
+++ b/gerbonara/cad/kicad/base_types.py
@@ -97,7 +97,8 @@ class Stroke:
class Dasher:
def __init__(self, obj):
if obj.stroke:
- w, t = obj.stroke.width or 0.254, obj.stroke.type
+ w = obj.stroke.width if obj.stroke.width is not None else 0.254
+ t = obj.stroke.type
else:
w = obj.width or 0
t = Atom.solid
@@ -210,6 +211,20 @@ class XYCoord:
else:
self.x, self.y = x, y
+ def __iter__(self):
+ return iter((self.x, self.y))
+
+ def __getitem__(self, index):
+ return (self.x, self.y)[index]
+
+ def __setitem__(self, index, value):
+ if index == 0:
+ self.x = value
+ elif index == 1:
+ self.y = value
+ else:
+ raise IndexError(f'Invalid 2D point coordinate index {index}')
+
def within_distance(self, x, y, dist):
return math.dist((x, y), (self.x, self.y)) < dist
diff --git a/gerbonara/cad/kicad/footprints.py b/gerbonara/cad/kicad/footprints.py
index b24e004..9debaa9 100644
--- a/gerbonara/cad/kicad/footprints.py
+++ b/gerbonara/cad/kicad/footprints.py
@@ -220,7 +220,7 @@ class Arc:
cy = ((x1 * x1 + y1 * y1) * (mx - x2) + (x2 * x2 + y2 * y2) * (x1 - mx) + (mx * mx + my * my) * (x2 - x1)) / d
# KiCad only has clockwise arcs.
- arc = go.Arc(x1, -y1, x2, -y2, cx-x1, -(cy-y1), clockwise=False, aperture=aperture, unit=MM)
+ arc = go.Arc(x1, -y1, x2, -y2, cx-x1, -(cy-y1), clockwise=True, aperture=aperture, unit=MM)
if dasher.solid:
yield arc
@@ -249,13 +249,14 @@ class Polygon:
dasher = Dasher(self)
start = self.pts.xy[0]
- dasher.move(start.x, -start.y)
+ dasher.move(start.x, start.y)
for point in self.pts.xy[1:]:
dasher.line(point.x, point.y)
- aperture = ap.CircleAperture(dasher.width, unit=MM)
- for x1, y1, x2, y2 in dasher:
- yield go.Line(x1, -y1, x2, -y2, aperture=aperture, unit=MM)
+ if dasher.width > 0:
+ aperture = ap.CircleAperture(dasher.width, unit=MM)
+ for x1, y1, x2, y2 in dasher:
+ yield go.Line(x1, -y1, x2, -y2, aperture=aperture, unit=MM)
if self.fill == Atom.solid:
yield go.Region([(pt.x, -pt.y) for pt in self.pts.xy], unit=MM)
@@ -466,10 +467,10 @@ class Pad:
0, 0, # no hole
rotation), unit=MM)
else:
- return ap.RectangleAperture(self.size.x+2*margin, self.size.y+2*margin, unit=MM).rotated(rotation)
+ return ap.RectangleAperture(self.size.x+2*margin, self.size.y+2*margin, unit=MM).rotated(-rotation)
elif self.shape == Atom.oval:
- return ap.ObroundAperture(self.size.x+2*margin, self.size.y+2*margin, unit=MM).rotated(rotation)
+ return ap.ObroundAperture(self.size.x+2*margin, self.size.y+2*margin, unit=MM).rotated(-rotation)
elif self.shape == Atom.trapezoid:
# KiCad's trapezoid aperture "rect_delta" param is just weird to the point that I think it's probably
@@ -495,14 +496,14 @@ class Pad:
(x+dy+2*margin*math.cos(alpha), y+2*margin,
2*dy,
0, 0, # no hole
- rotation), unit=MM)
+ -rotation + math.pi), unit=MM)
else:
return ap.ApertureMacroInstance(GenericMacros.rounded_isosceles_trapezoid,
(x+dy, y,
2*dy, margin,
0, 0, # no hole
- rotation), unit=MM)
+ -rotation + math.pi), unit=MM)
elif self.shape == Atom.roundrect:
x, y = self.size.x, self.size.y
@@ -514,7 +515,7 @@ class Pad:
0, 0, # no hole
rotation), unit=MM)
else:
- return ap.RectangleAperture(x+margin, y+margin, unit=MM).rotated(rotation)
+ return ap.RectangleAperture(x+margin, y+margin, unit=MM).rotated(-rotation)
elif self.shape == Atom.custom:
primitives = []
@@ -556,7 +557,7 @@ class Pad:
elif self.options.anchor == Atom.circle and self.size.x > 0:
primitives.append(amp.Circle(MM, 1, self.size.x+2*margin, 0, 0, 0))
- macro = ApertureMacro(primitives=tuple(primitives)).rotated(rotation)
+ macro = ApertureMacro(primitives=tuple(primitives)).rotated(-rotation)
return ap.ApertureMacroInstance(macro, unit=MM)
def render_drill(self):
@@ -881,7 +882,7 @@ class Footprint:
for text in self.texts:
text.at.rotation = (text.at.rotation + delta) % 360
- def objects(self, text=False, pads=True, groups=True):
+ def objects(self, text=False, pads=True, groups=True, zones=True):
return chain(
(self.texts if text else []),
(self.text_boxes if text else []),
@@ -893,7 +894,7 @@ class Footprint:
self.curves,
(self.dimensions if text else []),
(self.pads if pads else []),
- self.zones,
+ (self.zones if zones else []),
self.groups if groups else [])
def render(self, layer_stack, layer_map, x=0, y=0, rotation=0, text=False, flip=False, variables={}, cache=None):
@@ -901,7 +902,7 @@ class Footprint:
y += self.at.y
rotation += math.radians(self.at.rotation)
- for obj in self.objects(pads=False, text=text):
+ for obj in self.objects(pads=False, text=text, zones=False):
if not (layer := layer_map.get(obj.layer)):
continue
diff --git a/gerbonara/cad/kicad/graphical_primitives.py b/gerbonara/cad/kicad/graphical_primitives.py
index a2393d2..94a61a4 100644
--- a/gerbonara/cad/kicad/graphical_primitives.py
+++ b/gerbonara/cad/kicad/graphical_primitives.py
@@ -203,10 +203,10 @@ class Arc:
return
aperture = ap.CircleAperture(self.width, unit=MM)
- cx, cy = self.mid.x, self.mid.y
x1, y1 = self.start.x, self.start.y
x2, y2 = self.end.x, self.end.y
- yield go.Arc(x1, -y1, x2, -y2, cx-x1, -(cy-y1), aperture=aperture, clockwise=True, unit=MM)
+ (cx, cy), _r = kicad_mid_to_center_arc(self.mid, self.start, self.end)
+ yield go.Arc(x1, -y1, x2, -y2, cx-x1, -(cy-y1), aperture=aperture, clockwise=False, unit=MM)
def offset(self, x=0, y=0):
self.start = self.start.with_offset(x, y)
@@ -224,7 +224,23 @@ class Polygon:
tstamp: Timestamp = None
def render(self, variables=None):
- reg = go.Region([(pt.x, -pt.y) for pt in self.pts.xy], unit=MM)
+ points = []
+ centers = []
+ for point_or_arc in self.pts:
+ if points:
+ centers.append((None, (None, None)))
+
+ if isinstance(point_or_arc, XYCoord):
+ points.append((point_or_arc.x, -point_or_arc.y))
+
+ else: # base_types.Arc
+ points.append((point_or_arc.start.x, -point_or_arc.start.y))
+ points.append((point_or_arc.end.x, -point_or_arc.end.y))
+ (cx, cy), _r = kicad_mid_to_center_arc(point_or_arc.mid, point_or_arc.start, point_or_arc.end)
+ centers.append((False, (cx, -cy)))
+
+ reg = go.Region(points, centers, unit=MM)
+ reg.close()
# FIXME stroke support
if self.width and self.width >= 0.005 or self.stroke.width and self.stroke.width > 0.005:
diff --git a/gerbonara/cad/kicad/primitives.py b/gerbonara/cad/kicad/primitives.py
index 74ce4e4..fa55568 100644
--- a/gerbonara/cad/kicad/primitives.py
+++ b/gerbonara/cad/kicad/primitives.py
@@ -59,6 +59,31 @@ def center_arc_to_kicad_mid(center, start, end):
return XYCoord(mx, my)
+def kicad_mid_to_center_arc(mid, start, end):
+ """ Convert kicad's slightly insane midpoint notation to standrad center/p1/p2 notation.
+
+ Returns the center and radius of the circle passing the given 3 points.
+ In case the 3 points form a line, raises a ValueError.
+ """
+ # https://stackoverflow.com/questions/28910718/give-3-points-and-a-plot-circle
+ p1, p2, p3 = start, mid, end
+
+ temp = p2[0] * p2[0] + p2[1] * p2[1]
+ bc = (p1[0] * p1[0] + p1[1] * p1[1] - temp) / 2
+ cd = (temp - p3[0] * p3[0] - p3[1] * p3[1]) / 2
+ det = (p1[0] - p2[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p2[1])
+
+ if abs(det) < 1.0e-6:
+ raise ValueError()
+
+ # Center of circle
+ cx = (bc*(p2[1] - p3[1]) - cd*(p1[1] - p2[1])) / det
+ cy = ((p1[0] - p2[0]) * cd - (p2[0] - p3[0]) * bc) / det
+
+ radius = math.sqrt((cx - p1[0])**2 + (cy - p1[1])**2)
+ return ((cx, cy), radius)
+
+
@sexp_type('hatch')
class Hatch:
style: AtomChoice(Atom.none, Atom.edge, Atom.full) = Atom.edge
diff --git a/gerbonara/cad/kicad/symbols.py b/gerbonara/cad/kicad/symbols.py
index baa77bb..ed93f7b 100644
--- a/gerbonara/cad/kicad/symbols.py
+++ b/gerbonara/cad/kicad/symbols.py
@@ -20,6 +20,7 @@ from .base_types import *
from ...utils import rotate_point, Tag, arc_bounds
from ...newstroke import Newstroke
from .schematic_colors import *
+from .primitives import center_arc_to_kicad_mid
PIN_ETYPE = AtomChoice(Atom.input, Atom.output, Atom.bidirectional, Atom.tri_state, Atom.passive, Atom.free,
@@ -249,28 +250,6 @@ class Circle:
**self.stroke.svg_attrs(colorscheme.lines))
-# https://stackoverflow.com/questions/28910718/give-3-points-and-a-plot-circle
-def define_circle(p1, p2, p3):
- """
- Returns the center and radius of the circle passing the given 3 points.
- In case the 3 points form a line, raises a ValueError.
- """
- temp = p2[0] * p2[0] + p2[1] * p2[1]
- bc = (p1[0] * p1[0] + p1[1] * p1[1] - temp) / 2
- cd = (temp - p3[0] * p3[0] - p3[1] * p3[1]) / 2
- det = (p1[0] - p2[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p2[1])
-
- if abs(det) < 1.0e-6:
- raise ValueError()
-
- # Center of circle
- cx = (bc*(p2[1] - p3[1]) - cd*(p1[1] - p2[1])) / det
- cy = ((p1[0] - p2[0]) * cd - (p2[0] - p3[0]) * bc) / det
-
- radius = math.sqrt((cx - p1[0])**2 + (cy - p1[1])**2)
- return ((cx, cy), radius)
-
-
@sexp_type('arc')
class Arc:
start: Rename(XYCoord) = field(default_factory=XYCoord)
@@ -280,7 +259,7 @@ class Arc:
fill: Fill = field(default_factory=Fill)
def bounding_box(self, default=None):
- (cx, cy), r = define_circle((self.start.x, self.start.y), (self.mid.x, self.mid.y), (self.end.x, self.end.y))
+ (cx, cy), r = center_arc_to_kicad_mid(self.mid, self.start, self.end)
x1, y1 = self.start.x, self.start.y
x2, y2 = self.mid.x-x1, self.mid.y-x2
x3, y3 = (self.end.x - x1)/2, (self.end.y - y1)/2
@@ -289,7 +268,7 @@ class Arc:
def to_svg(self, colorscheme=Colorscheme.KiCad):
- (cx, cy), r = define_circle((self.start.x, self.start.y), (self.mid.x, self.mid.y), (self.end.x, self.end.y))
+ (cx, cy), r = center_arc_to_kicad_mid(self.mid, self.start, self.end)
x1r = self.start.x - cx
y1r = self.start.y - cy