diff options
author | jaseg <git@jaseg.de> | 2022-02-05 12:34:28 +0100 |
---|---|---|
committer | jaseg <git@jaseg.de> | 2022-02-05 12:34:28 +0100 |
commit | 57941b1b76ffbdb9a5eeb9fef5e3c2365e3a4b84 (patch) | |
tree | b75d54db39ad522ee0ee6ee0d3b3679d84247bd6 /gerbonara | |
parent | 4cbda84aa61158c06acc78aac4b318bbea5b6214 (diff) | |
download | gerbonara-57941b1b76ffbdb9a5eeb9fef5e3c2365e3a4b84.tar.gz gerbonara-57941b1b76ffbdb9a5eeb9fef5e3c2365e3a4b84.tar.bz2 gerbonara-57941b1b76ffbdb9a5eeb9fef5e3c2365e3a4b84.zip |
Arc approx WIP
Diffstat (limited to 'gerbonara')
-rw-r--r-- | gerbonara/graphic_objects.py | 42 | ||||
-rw-r--r-- | gerbonara/ipc356.py | 7 | ||||
-rw-r--r-- | gerbonara/rs274x.py | 3 |
3 files changed, 51 insertions, 1 deletions
diff --git a/gerbonara/graphic_objects.py b/gerbonara/graphic_objects.py index 97a39c8..c14b411 100644 --- a/gerbonara/graphic_objects.py +++ b/gerbonara/graphic_objects.py @@ -20,7 +20,7 @@ import math import copy from dataclasses import dataclass, KW_ONLY, astuple, replace, field, fields -from .utils import MM, InterpMode, to_unit +from .utils import MM, InterpMode, to_unit, rotate_point from . import graphic_primitives as gp @@ -556,6 +556,46 @@ class Arc(GraphicObject): """ return self.tool.plated + def approximate(self, max_error=1e-2, unit=MM, clip_max_error=True): + """ Approximate this :py:class:`~.graphic_objects.Arc` using a list of multiple + :py:class:`~.graphic_objects.Line` instances to the given precision. + + :param float max_error: Maximum approximation error in ``unit`` units. + :param unit: Either a :py:class:`.LengthUnit` instance or one of the strings ``'mm'`` or ``'inch'``. + :param bool clip_max_error: Clip max error such that at least a square is always rendered. + + :returns: list of :py:class:`~.graphic_objects.Line` instances. + :rtype: list + """ + # TODO the max_angle calculation below is a bit off -- we over-estimate the error, and thus produce finer + # results than necessary. Fix this. + + r = math.hypot(self.cx, self.cy) + + max_error = self.unit(max_error, unit) + if clip_max_error: + # 1 - math.sqrt(1 - 0.5*math.sqrt(2)) + max_error = min(max_error, r*0.4588038998538031) + + elif max_error >= r: + return [Line(*self.p1, *self.p2, aperture=self.aperture, polarity_dark=self.polarity_dark)] + + # see https://www.mathopenref.com/sagitta.html + l = math.sqrt(r**2 - (r - max_error)**2) + + angle_max = math.asin(l/r) + sweep_angle = self.sweep_angle() + num_segments = math.ceil(sweep_angle / angle_max) + angle = sweep_angle / num_segments + + if not self.clockwise: + angle = -angle + + cx, cy = self.center + points = [ rotate_point(self.x1, self.y1, i*angle, cx, cy) for i in range(num_segments + 1) ] + return [ Line(*p1, *p2, aperture=self.aperture, polarity_dark=self.polarity_dark) + for p1, p2 in zip(points[0::], points[1::]) ] + def _rotate(self, rotation, cx=0, cy=0): # rotate center first since we need old x1, y1 here new_cx, new_cy = gp.rotate_point(*self.center, rotation, cx, cy) diff --git a/gerbonara/ipc356.py b/gerbonara/ipc356.py index 175cb5e..ae341be 100644 --- a/gerbonara/ipc356.py +++ b/gerbonara/ipc356.py @@ -95,6 +95,13 @@ class Netlist(CamFile): for obj in self.objects: obj.rotate(angle, cx, cy, unit) + def __str__(self): + name = f'{self.original_path.name} ' if self.original_path else '' + return f'<IPC-356 Netlist {name}with {len(self.test_records)} records, {len(self.conductors)} conductors and {len(self.outlines)} outlines>' + + def __repr__(self): + return str(self) + @property def objects(self): yield from self.test_records diff --git a/gerbonara/rs274x.py b/gerbonara/rs274x.py index b355bda..51a5e19 100644 --- a/gerbonara/rs274x.py +++ b/gerbonara/rs274x.py @@ -232,6 +232,9 @@ class GerberFile(CamFile): name = f'{self.original_path.name} ' if self.original_path else '' return f'<GerberFile {name}with {len(self.apertures)} apertures, {len(self.objects)} objects>' + def __repr__(self): + return str(self) + def save(self, filename, settings=None, drop_comments=True): """ Save this Gerber file to the file system. See :py:meth:`~.GerberFile.generate_gerber` for the meaning of the arguments. """ |