Kicad schematic rendering WIP

This commit is contained in:
jaseg 2023-07-21 01:46:11 +02:00
parent 60674ab5b3
commit b69e9fded4
3 changed files with 82 additions and 26 deletions

View file

@ -80,7 +80,8 @@ class Stroke:
attrs = {'stroke': color,
'stroke_linecap': 'round',
'stroke_widtj': self.width}
'stroke_linejoin': 'round',
'stroke_width': self.width or 0.254}
if self.type not in (Atom.default, Atom.solid):
attrs['stroke_dasharray'] = {
@ -313,6 +314,14 @@ class TextMixin:
d = ' '.join(self.svg_path_data())
yield Tag('path', d=d, fill='none', stroke=color, stroke_width=f'{self.line_width:.3f}', stroke_linecap='round')
@property
def _text_offset(self):
return (0, 0)
@property
def rotation(self):
return self.at.rotation
def render(self, variables={}):
if not self.effects or self.effects.hide or not self.effects.font:
return
@ -327,17 +336,30 @@ class TextMixin:
w = max_x - min_x
h = max_y - min_y
offx = -min_x + {
h_just = self.effects.justify.h if self.effects.justify else None
v_just = self.effects.justify.v if self.effects.justify else None
rot = self.rotation
# KiCad already flips h_just in these cases, making the rotation param redundant.
if rot == 180:
rot = 0
if rot == 270 and self.at.rotation != 270:
h_just = {Atom.right: Atom.left, Atom.left: Atom.right}.get(h_just, h_just)
offx, offy = self._text_offset
offx += -min_x + {
None: -w/2,
Atom.right: -w,
Atom.left: 0
}[self.effects.justify.h if self.effects.justify else None]
}[h_just]
offy = {
offy += {
None: self.size/2,
Atom.top: self.size,
Atom.bottom: 0
}[self.effects.justify.v if self.effects.justify else None]
}[v_just]
aperture = ap.CircleAperture(self.line_width or 0.2, unit=MM)
for stroke in strokes:
@ -345,7 +367,7 @@ class TextMixin:
for x, y in stroke:
x, y = x+offx, y+offy
x, y = rotate_point(x, y, math.radians(self.at.rotation or 0))
x, y = rotate_point(x, y, math.radians(-rot or 0))
x, y = x+self.at.x, y+self.at.y
out.append((x, y))
@ -429,6 +451,11 @@ class DrawnProperty(TextMixin):
hide: Flag() = False
tstamp: Timestamp = None
effects: TextEffect = field(default_factory=TextEffect)
_ : SEXP_END = None
parent: object = None
def __after_parse(self, parent=None):
self.parent = parent
# Alias value for text mixin
@property

View file

@ -187,6 +187,10 @@ class LocalLabel(TextMixin):
effects: TextEffect = field(default_factory=TextEffect)
uuid: UUID = field(default_factory=UUID)
@property
def _text_offset(self):
return (0, -2*self.line_width)
def to_svg(self, colorscheme=Colorscheme.KiCad):
yield from TextMixin.to_svg(self, colorscheme.text)
@ -283,6 +287,11 @@ class DrawnProperty(TextMixin):
at: AtPos = field(default_factory=AtPos)
hide: Flag() = False
effects: TextEffect = field(default_factory=TextEffect)
_: SEXP_END = None
parent: object = None
def __after_parse__(self, parent=None):
self.parent = parent
# Alias value for text mixin
@property
@ -293,6 +302,10 @@ class DrawnProperty(TextMixin):
def text(self, value):
self.value = value
@property
def rotation(self):
return self.parent.rotation + self.at.rotation
def to_svg(self, colorscheme=Colorscheme.KiCad):
if not self.hide:
yield from TextMixin.to_svg(self, colorscheme.text)
@ -323,26 +336,39 @@ class SymbolInstance:
def __after_parse__(self, parent):
self.schematic = parent
@property
def rotation(self):
return self.at.rotation
def to_svg(self, colorscheme=Colorscheme.KiCad):
children = []
rot = self.at.rotation
for prop in self.properties:
children += prop.to_svg()
sym = self.schematic.lookup_symbol(self.lib_name, self.lib_id)
sym = self.schematic.lookup_symbol(self.lib_name, self.lib_id).raw_units[self.unit - 1]
for elem in sym.graphical_elements:
children += elem.to_svg(colorscheme)
name = f'{sym.name}_0_1'
if name in sym.global_units.get(1, {}):
for elem in sym.global_units[1][name].graphical_elements:
children += elem.to_svg(colorscheme)
name = f'{sym.name}_{self.unit}_1'
if name in sym.styles.get(1, {}):
for elem in sym.styles[1][name].graphical_elements:
children += elem.to_svg(colorscheme)
xform = f'translate({self.at.x:.3f} {self.at.y:.3f})'
if self.at.rotation:
xform = f'rotate({self.at.rotation}) {xform}'
if rot:
xform += f'rotate({-rot})'
if self.mirror.x:
xform = f'scale(-1 1) {xform}'
if self.mirror.y:
xform = f'scale(1 -1) {xform}'
xform += f'scale(-1 1)'
if not self.mirror.y:
xform += f'scale(1 -1)'
yield Tag('g', children=children, transform=xform, fill=colorscheme.fill, stroke=colorscheme.lines)
for prop in self.properties:
yield from prop.to_svg()
@sexp_type('path')
class SubsheetCrosslinkSheet:
@ -399,6 +425,10 @@ class Subsheet:
def __before_sexp__(self):
self._properties = [self.sheet_name, self.file_name]
@property
def rotation(self):
return 0
def open(self, search_dir=None, safe=True):
if search_dir is None:
if not self.schematic.original_filename:
@ -496,18 +526,18 @@ class Schematic:
@property
def elements(self):
yield from self.images
yield from self.polylines
yield from self.symbols
yield from self.junctions
yield from self.no_connects
yield from self.bus_entries
yield from self.wires
yield from self.buses
yield from self.images
yield from self.polylines
yield from self.texts
yield from self.local_labels
yield from self.global_labels
yield from self.hierarchical_labels
yield from self.symbols
yield from self.subsheets
def to_svg(self, colorscheme=Colorscheme.KiCad):

View file

@ -96,12 +96,12 @@ class Pin:
return (x1, y1), (x2, y2)
def to_svg(self, colorscheme=Colorscheme.KiCad):
x1, y1 = self.at.x, self.at.y
x2, y2 = x1+self.length, y1
xform = {'transform': f'rotate({-self.at.rotation} {x1} {y1})'}
x1, y1 = 0, 0
x2, y2 = self.length, 0
xform = {'transform': f'translate({self.at.x:.3f} {self.at.y:.3f}) rotate({self.at.rotation})'}
style = {'stroke_width': 0.254, 'stroke': colorscheme.lines, 'stroke_linecap': 'round'}
yield Tag('path', **xform, **style, d=f'M {x1:.6f} {y1:.6f} L {x2:.6f} {y2:.6f}')
yield Tag('path', **xform, **style, d=f'M 0 0 L {self.length:.3f} 0')
eps = 1
for tag in {
@ -160,8 +160,6 @@ class Pin:
else:
raise ValueError(f'Invalid pin rotation {self.at.rotation}')
yield f'M {line.x1:.3f} {line.y1:.3f} L {line.x2:.3f} {line.y2:.3f}'
d = []
for stroke in strokes:
points = []
@ -171,7 +169,8 @@ class Pin:
x, y = x+self.at.x, y+self.at.y
points.append(f'{x:.3f} {y:.3f}')
d.append('M '+ ' L '.join(points) + ' ')
yield Tag('path', d=d, fill='none', stroke=colorscheme.text, stroke_width='0.254', stroke_linecap='round')
yield Tag('path', d=' '.join(d), fill='none', stroke=colorscheme.text, stroke_width='0.254', stroke_linecap='round', stroke_linejoin='round')
print('name', self.name.value)
@sexp_type('fill')