summaryrefslogtreecommitdiff
path: root/gerbonara/cad/kicad/graphical_primitives.py
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2023-04-18 12:26:03 +0200
committerjaseg <git@jaseg.de>2023-04-19 00:51:27 +0200
commit2c6c9a5cbc6d389a17c0cc15173c6e626fd5d5c6 (patch)
treedd588a4beff48425d5723f767a25e51d28e4500f /gerbonara/cad/kicad/graphical_primitives.py
parent263033c9bdecf8c82027f6475c863d818f499914 (diff)
downloadgerbonara-2c6c9a5cbc6d389a17c0cc15173c6e626fd5d5c6.tar.gz
gerbonara-2c6c9a5cbc6d389a17c0cc15173c6e626fd5d5c6.tar.bz2
gerbonara-2c6c9a5cbc6d389a17c0cc15173c6e626fd5d5c6.zip
Basic KiCad footprint rendering works
Diffstat (limited to 'gerbonara/cad/kicad/graphical_primitives.py')
-rw-r--r--gerbonara/cad/kicad/graphical_primitives.py116
1 files changed, 114 insertions, 2 deletions
diff --git a/gerbonara/cad/kicad/graphical_primitives.py b/gerbonara/cad/kicad/graphical_primitives.py
index 391b38b..ed40c96 100644
--- a/gerbonara/cad/kicad/graphical_primitives.py
+++ b/gerbonara/cad/kicad/graphical_primitives.py
@@ -1,8 +1,15 @@
+import math
+
from .sexp import *
from .base_types import *
from .primitives import *
+from ... import graphic_objects as go
+from ... import apertures as ap
+from ...newstroke import Newstroke
+from ...utils import rotate_point
+
@sexp_type('layer')
class TextLayer:
layer: str = ''
@@ -17,6 +24,40 @@ class Text:
tstamp: Timestamp = None
effects: TextEffect = field(default_factory=TextEffect)
+ def render(self):
+ if not self.effects or self.effects.hide or not self.effects.font:
+ return
+
+ font = Newstroke.load()
+ strokes = list(font.render(self.text, size=self.effects.font.size.y))
+ min_x = min(x for st in strokes for x, y in st)
+ min_y = min(y for st in strokes for x, y in st)
+ max_x = max(x for st in strokes for x, y in st)
+ max_y = max(y for st in strokes for x, y in st)
+ w = max_x - min_x
+ h = max_y - min_y
+
+ offx = -min_x + {
+ None: -w/2,
+ Atom.right: -w,
+ Atom.left: 0
+ }[self.effects.justify.h if self.effects.justify else None]
+ offy = {
+ None: -h/2,
+ Atom.top: -h,
+ Atom.bottom: 0
+ }[self.effects.justify.v if self.effects.justify else None]
+
+ aperture = ap.CircleAperture(self.effects.font.width or 0.2, unit=MM)
+ for stroke in strokes:
+ out = []
+ for point in stroke:
+ x, y = rotate_point(x, y, math.radians(self.at.rotation or 0))
+ x, y = x+offx, y+offy
+ out.append((x, y))
+ for p1, p2 in zip(out[:-1], out[1:]):
+ yield go.Line(*p1, *p2, aperture=ap, unit=MM)
+
@sexp_type('gr_text_box')
class TextBox:
@@ -32,16 +73,38 @@ class TextBox:
stroke: Stroke = field(default_factory=Stroke)
render_cache: RenderCache = None
+ def render(self):
+ if not render_cache or not render_cache.polygons:
+ raise ValueError('Text box with empty render cache')
+
+ for poly in render_cache.polygons:
+ reg = go.Region([(p.x, p.y) for p in poly.pts.xy], unit=MM)
+
+ if self.stroke:
+ if self.stroke.type not in (None, Atom.default, Atom.solid):
+ raise ValueError('Dashed strokes are not supported on vector text')
+
+ yield from reg.outline_objects(aperture=CircleAperture(self.stroke.width, unit=MM))
+
+ yield reg
+
@sexp_type('gr_line')
class Line:
start: Rename(XYCoord) = None
end: Rename(XYCoord) = None
- angle: Named(float) = None
+ angle: Named(float) = None # wat
layer: Named(str) = None
width: Named(float) = None
tstamp: Timestamp = None
+ def render(self):
+ if self.angle:
+ raise NotImplementedError('Angles on lines are not implemented. Please raise an issue and provide an example file.')
+
+ ap = ap.CircleAperture(self.width, unit=MM)
+ return go.Line(self.start.x, self.start.y, self.end.x, self.end.y, aperture=ap, unit=MM)
+
@sexp_type('fill')
class FillMode:
@@ -65,6 +128,17 @@ class Rectangle:
fill: FillMode = False
tstamp: Timestamp = None
+ def render(self):
+ rect = go.Region.from_rectangle(self.start.x, self.start.y,
+ self.end.x-self.start.x, self.end.y-self.start.y,
+ unit=MM)
+
+ if self.fill:
+ yield rect
+
+ if self.width:
+ yield from rect.outline_objects(aperture=CircleAperture(self.width, unit=MM))
+
@sexp_type('gr_circle')
class Circle:
@@ -75,6 +149,17 @@ class Circle:
fill: FillMode = False
tstamp: Timestamp = None
+ def render(self):
+ r = math.dist((self.center.x, self.center.y), (self.end.x, self.end.y))
+ arc = go.Arc.from_circle(self.center.x, self.center.y, r, unit=MM)
+
+ if self.width:
+ arc.aperture = ap.CircleAperture(self.width, unit=MM)
+ yield arc
+
+ if self.fill:
+ yield arc.to_region()
+
@sexp_type('gr_arc')
class Arc:
@@ -85,6 +170,19 @@ class Arc:
width: Named(float) = None
tstamp: Timestamp = None
+ def render(self):
+ cx, cy = self.mid.x, self.mid.y
+ x1, y1 = self.start.x, self.start.y
+ x2, y2 = self.end.x, self.end.y
+ arc = go.Arc(x1, y1, x2, y2, cx-x1, cy-y1, unit=MM)
+
+ if self.width:
+ arc.aperture = CircleAperture(self.width, unit=MM)
+ yield arc
+
+ if self.fill:
+ yield arc.to_region()
+
@sexp_type('gr_poly')
class Polygon:
@@ -94,6 +192,15 @@ class Polygon:
fill: FillMode= False
tstamp: Timestamp = None
+ def render(self):
+ reg = go.Region([(pt.x, pt.y) for pt in self.pts.xy], unit=MM)
+
+ if width:
+ yield from reg.outline_objects(aperture=CircleAperture(self.width, unit=MM))
+
+ if self.fill:
+ yield reg
+
@sexp_type('gr_curve')
class Curve:
@@ -102,10 +209,15 @@ class Curve:
width: Named(float) = None
tstamp: Timestamp = None
+ def render(self):
+ raise NotImplementedError('Bezier rendering is not yet supported. Please raise an issue and provide an example file.')
+
@sexp_type('gr_bbox')
class AnnotationBBox:
start: Rename(XYCoord) = None
end: Rename(XYCoord) = None
-
+ def render(self):
+ return []
+