Add sector support

This commit is contained in:
jaseg 2025-12-11 23:30:53 +01:00
parent f452167914
commit 760013eecd
2 changed files with 51 additions and 3 deletions

View file

@ -21,11 +21,12 @@ import os
import sys import sys
from pathlib import Path from pathlib import Path
import warnings import warnings
import math
import click import click
from gerbonara.layers import LayerStack from gerbonara.layers import LayerStack
from .geometry import PlanarInductor, divisors, CircleShape, TrapezoidShape from .geometry import PlanarInductor, divisors, CircleShape, SectorShape
from .kicad import footprint_to_board from .kicad import footprint_to_board
from .svg import make_transparent_svg from .svg import make_transparent_svg
@ -87,8 +88,10 @@ def cli(ctx, footprint_name, clipboard, single_layer, arc_tolerance, circle_segm
footprint = model.render_footprint(footprint_name, arc_tolerance, circle_segments) footprint = model.render_footprint(footprint_name, arc_tolerance, circle_segments)
except ValueError as e: except ValueError as e:
raise
raise click.ClickException(*e.args) raise click.ClickException(*e.args)
except:
import pdb
pdb.post_mortem()
data = None data = None
if format == 'kicad-footprint': if format == 'kicad-footprint':
@ -165,3 +168,17 @@ def circle(ctx, inner_diameter, outer_diameter, outfile):
def trapezoid(ctx, outfile, **kwargs): def trapezoid(ctx, outfile, **kwargs):
shape = TrapezoidShape(**kwargs) shape = TrapezoidShape(**kwargs)
ctx.obj['write'](shape, outfile) ctx.obj['write'](shape, outfile)
@cli.command()
@click.option('--inner-diameter', type=float, default=25, help='Inner diameter [mm]')
@click.option('--outer-diameter', type=float, default=50, help='Outer diameter [mm]')
@click.option('--angle', type=float, default=45, help='Sector angle [deg]')
@click.option('--arc-tolerance', type=float, default=0.05, help='Tolerance for splitting arc into straight segments [mm] (default: 0.05 mm)')
@click.option('--annular-width', type=float, default=5, help='Width of the trace area on the outside of the shape [mm]')
@click.argument('outfile', required=False, type=click.Path(writable=True, dir_okay=False, path_type=Path))
@click.pass_context
def sector(ctx, outfile, angle, **kwargs):
angle = math.radians(angle)
shape = SectorShape(angle=angle, **kwargs)
ctx.obj['write'](shape, outfile)

View file

@ -169,6 +169,8 @@ class OffsetShape(Shape):
def compute_spiral(self, a1, a2, fn=None): def compute_spiral(self, a1, a2, fn=None):
# Skeletonator uses a t coordinate from 0 - 1 per revolution instead of a radian angle. # Skeletonator uses a t coordinate from 0 - 1 per revolution instead of a radian angle.
points = list(self.sk.do_spiral(a1/(2*pi), a2/(2*pi), self.outer_radius, self.inner_radius)) points = list(self.sk.do_spiral(a1/(2*pi), a2/(2*pi), self.outer_radius, self.inner_radius))
if a2 < a1:
points = points[::-1]
arm_length = sum(dist(p1, p2) for p1, p2 in zip(points, points[1:])) arm_length = sum(dist(p1, p2) for p1, p2 in zip(points, points[1:]))
return points, arm_length return points, arm_length
@ -204,6 +206,35 @@ class TrapezoidShape(OffsetShape):
return f'{self.width:.2f} x {self.height:.2f} mm, {self.offset:.2f} mm offset isosceles trapezoidal' return f'{self.width:.2f} x {self.height:.2f} mm, {self.offset:.2f} mm offset isosceles trapezoidal'
@dataclass
class SectorShape(OffsetShape):
inner_diameter: float
outer_diameter: float
angle: float
annular_width: float
arc_tolerance: float = 0.05 # mm
polygon: list = field(init=False)
def __post_init__(self):
# Careful: The inner/outer radius properties are relative to the polygon center and are very different from these!
r1, r2 = self.inner_diameter / 2, self.outer_diameter/2
n1 = ceil(pi / acos(1 - self.arc_tolerance/self.inner_diameter) * self.angle / (2*pi))
n2 = ceil(pi / acos(1 - self.arc_tolerance/self.outer_diameter) * self.angle / (2*pi))
# center on y axis
pt = lambda r, a: (r*sin(a), r*cos(a))
self.polygon = [pt(r2, self.angle/2 - i/n1 * self.angle) for i in range(n1+1)]
self.polygon += [pt(r1, i/n1 * self.angle - self.angle/2) for i in range(n1+1)]
super().__post_init__()
@property
def slug(self):
return f'sector_{self.outer_diameter:.2f}x{self.inner_diameter:.2f}_{degrees(self.angle):.0f}deg'
@property
def desc(self):
return f'{self.outer_diameter:.2f} x {self.inner_diameter:.2f} mm {degrees(self.angle):.0f} deg sector'
@dataclass @dataclass
class PlanarInductor(): class PlanarInductor():
shape: Shape shape: Shape