Fixing more tests

This commit is contained in:
jaseg 2023-04-24 00:56:32 +02:00
parent bda404c18b
commit 5a41d96fe3
5 changed files with 49 additions and 22 deletions

View file

@ -13,6 +13,7 @@ from . import primitive as ap
from .expression import *
from ..utils import MM
# we make our own here instead of using math.degrees to make sure this works with expressions, too.
def rad_to_deg(x):
return (x / math.pi) * 180
@ -190,6 +191,7 @@ class GenericMacros:
*_generic_hole(4)])
# w must be larger than h
# params: width, height, *hole, rotation
obround = ApertureMacro('GNO', [
ap.CenterLine('mm', [1, var(1), var(2), 0, 0, var(5) * -deg_per_rad]),
ap.Circle('mm', [1, var(2), +var(1)/2, 0, var(5) * -deg_per_rad]),

View file

@ -12,6 +12,7 @@ from .expression import Expression, UnitExpression, ConstantExpression, expr
from .. import graphic_primitives as gp
from .. import graphic_objects as go
from ..utils import rotate_point
def point_distance(a, b):
@ -20,9 +21,11 @@ def point_distance(a, b):
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
# we make our own here instead of using math.degrees to make sure this works with expressions, too.
def deg_to_rad(a):
return a * (math.pi / 180)
def rad_to_deg(a):
return a * (180 / math.pi)
@ -92,7 +95,7 @@ class Circle(Primitive):
def to_graphic_primitives(self, offset, rotation, variable_binding={}, unit=None, polarity_dark=True):
with self.Calculator(self, variable_binding, unit) as calc:
x, y = gp.rotate_point(calc.x, calc.y, deg_to_rad(calc.rotation) + rotation, 0, 0)
x, y = rotate_point(calc.x, calc.y, deg_to_rad(calc.rotation) + rotation, 0, 0)
x, y = x+offset[0], y+offset[1]
return [ gp.Circle(x, y, calc.diameter/2, polarity_dark=(bool(calc.exposure) == polarity_dark)) ]
@ -123,6 +126,7 @@ class VectorLine(Primitive):
delta_y = calc.end_y - calc.start_y
length = point_distance((calc.start_x, calc.start_y), (calc.end_x, calc.end_y))
center_x, center_y = rotate_point(center_x, center_y, deg_to_rad(calc.rotation) + rotation, 0, 0)
center_x, center_y = center_x+offset[0], center_y+offset[1]
rotation += deg_to_rad(calc.rotation) + math.atan2(delta_y, delta_x)
@ -181,7 +185,7 @@ class Polygon(Primitive):
def to_graphic_primitives(self, offset, rotation, variable_binding={}, unit=None, polarity_dark=True):
with self.Calculator(self, variable_binding, unit) as calc:
rotation += deg_to_rad(calc.rotation)
x, y = gp.rotate_point(calc.x, calc.y, rotation, 0, 0)
x, y = rotate_point(calc.x, calc.y, rotation, 0, 0)
x, y = x+offset[0], y+offset[1]
return [ gp.ArcPoly.from_regular_polygon(calc.x, calc.y, calc.diameter/2, calc.n_vertices, rotation,
polarity_dark=(bool(calc.exposure) == polarity_dark)) ]
@ -209,7 +213,7 @@ class Thermal(Primitive):
def to_graphic_primitives(self, offset, rotation, variable_binding={}, unit=None, polarity_dark=True):
with self.Calculator(self, variable_binding, unit) as calc:
rotation += deg_to_rad(calc.rotation)
x, y = gp.rotate_point(calc.x, calc.y, rotation, 0, 0)
x, y = rotate_point(calc.x, calc.y, rotation, 0, 0)
x, y = x+offset[0], y+offset[1]
dark = (bool(calc.exposure) == polarity_dark)
@ -271,7 +275,7 @@ class Outline(Primitive):
def to_graphic_primitives(self, offset, rotation, variable_binding={}, unit=None, polarity_dark=True):
with self.Calculator(self, variable_binding, unit) as calc:
rotation += deg_to_rad(calc.rotation)
bound_coords = [ gp.rotate_point(calc(x), calc(y), rotation, 0, 0) for x, y in self.coords ]
bound_coords = [ rotate_point(calc(x), calc(y), rotation, 0, 0) for x, y in self.coords ]
bound_coords = [ (x+offset[0], y+offset[1]) for x, y in bound_coords ]
bound_radii = [None] * len(bound_coords)
return [gp.ArcPoly(bound_coords, bound_radii, polarity_dark=(bool(calc.exposure) == polarity_dark))]

View file

@ -392,8 +392,8 @@ class ObroundAperture(Aperture):
return ApertureMacroInstance(GenericMacros.obround,
[MM(inst.w, self.unit),
MM(inst.h, self.unit),
MM(inst.hole_dia, self.unit),
MM(inst.hole_rect_h, self.unit),
MM(inst.hole_dia, self.unit) or 0,
MM(inst.hole_rect_h, self.unit) or 0,
inst.rotation])
def _params(self, unit=None):

View file

@ -24,8 +24,9 @@ from ... import graphic_primitives as gp
from ... import graphic_objects as go
from ... import apertures as ap
from ...newstroke import Newstroke
from ...utils import MM
from ...utils import MM, rotate_point
from ...aperture_macros.parse import GenericMacros, ApertureMacro
from ...aperture_macros import primitive as amp
@sexp_type('property')
@ -113,10 +114,10 @@ class Rectangle:
x2, y2 = self.end.x, self.end.y
x1, x2 = min(x1, x2), max(x1, x2)
y1, y2 = min(y1, y2), max(y1, y2)
w, h = x2-x1, y1-y2
w, h = x2-x1, y2-y1
if self.fill == Atom.solid:
yield go.Region.from_rectangle(x1, y1, w, y, unit=MM)
yield go.Region.from_rectangle(x1, y1, w, h, unit=MM)
dasher = Dasher(self)
dasher.move(x1, y1)
@ -364,21 +365,27 @@ class Pad:
options: OmitDefault(CustomPadOptions) = None
primitives: OmitDefault(CustomPadPrimitives) = None
def render(self, variables=None):
def render(self, variables=None, margin=None):
#if self.type in (Atom.connect, Atom.np_thru_hole):
# return
if self.drill and self.drill.offset:
ox, oy = rotate_point(self.drill.offset.x, self.drill.offset.y, math.radians(self.at.rotation))
else:
ox, oy = 0, 0
yield go.Flash(self.at.x, self.at.y, self.aperture(), unit=MM)
yield go.Flash(self.at.x+ox, self.at.y+oy, self.aperture(margin), unit=MM)
def aperture(self, margin=None):
rotation = -math.radians(self.at.rotation)
def aperture(self):
if self.shape == Atom.circle:
return ap.CircleAperture(self.size.x, unit=MM)
elif self.shape == Atom.rect:
return ap.RectangleAperture(self.size.x, self.size.y, unit=MM).rotated(self.at.rotation)
return ap.RectangleAperture(self.size.x, self.size.y, unit=MM).rotated(rotation)
elif self.shape == Atom.oval:
return ap.ObroundAperture(self.size.x, self.size.y, unit=MM).rotated(self.at.rotation)
return ap.ObroundAperture(self.size.x, self.size.y, 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
@ -386,14 +393,17 @@ class Pad:
# original bounding box, and the trapezoid's base and tip length are 3mm and 1mm.
x, y = self.size.x, self.size.y
dx, dy = self.rect_delta.x, self.rect_delta.y
if self.rect_delta:
dx, dy = self.rect_delta.x, self.rect_delta.y
else: # RF_Antenna/Pulse_W3011 has trapezoid pads w/o rect_delta, which KiCad renders as plain rects.
dx, dy = 0, 0
# Note: KiCad already uses MM units, so no conversion needed here.
return ap.ApertureMacroInstance(GenericMacros.isosceles_trapezoid,
[x+dx, y+dy,
2*max(dx, dy),
0, 0, # no hole
math.radians(self.at.rotation)], unit=MM)
rotation], unit=MM)
elif self.shape == Atom.roundrect:
x, y = self.size.x, self.size.y
@ -402,7 +412,7 @@ class Pad:
[x, y,
r,
0, 0, # no hole
math.radians(self.at.rotation)], unit=MM)
rotation], unit=MM)
elif self.shape == Atom.custom:
primitives = []
@ -410,7 +420,16 @@ class Pad:
for obj in self.primitives.all():
for gn_obj in obj.render():
primitives += gn_obj._aperture_macro_primitives() # todo: precision params
macro = ApertureMacro(primitives=primitives).rotated(self.at.rotation)
if self.options:
if self.options.anchor == Atom.rect and self.size.x > 0 and self.size.y > 0:
primitives.append(amp.CenterLine(MM, [1, self.size.x, self.size.y, 0, 0, 0]))
elif self.options.anchor == Atom.circle and self.size.x > 0:
primitives.append(amp.Circle(MM, [1, self.size.x, 0, 0, 0]))
macro = ApertureMacro(primitives=primitives).rotated(rotation)
return ap.ApertureMacroInstance(macro, unit=MM)
def render_drill(self):

View file

@ -68,6 +68,8 @@ def test_round_trip(kicad_mod_file):
assert original == stage1
# Regrettably, we have to re-implement a significant part of the SVG spec to fix up the SVGs that kicad-cli produces.
def _compute_style(elem):
current_style = {}
for elem in [*reversed(list(elem.parents)), elem]:
@ -187,14 +189,14 @@ def test_render(kicad_mod_file, tmpfile, print_on_error):
layer = stack[('top', 'courtyard')]
bounds = []
print('===== BOUNDS =====')
#print('===== BOUNDS =====')
for obj in layer.objects:
if isinstance(obj, (go.Line, go.Arc)):
bbox = (min_x, min_y), (max_x, max_y) = obj.bounding_box(unit=MM)
import textwrap
print(f'{min_x: 3.6f} {min_y: 3.6f} {max_x: 3.6f} {max_y: 3.6f}', '\n'.join(textwrap.wrap(str(obj), width=80, subsequent_indent=' '*(3+4*(3+1+6)))))
#import textwrap
#print(f'{min_x: 3.6f} {min_y: 3.6f} {max_x: 3.6f} {max_y: 3.6f}', '\n'.join(textwrap.wrap(str(obj), width=80, subsequent_indent=' '*(3+4*(3+1+6)))))
bounds.append(bbox)
print('===== END =====')
#print('===== END =====')
if not bounds:
print('Footprint has no paths on courtyard layer')