diff --git a/cadquery/sketch.py b/cadquery/sketch.py index 82730263a..5a90996a6 100644 --- a/cadquery/sketch.py +++ b/cadquery/sketch.py @@ -13,7 +13,7 @@ cast as tcast, ) from typing_extensions import Literal -from math import tan, sin, cos, pi, radians +from math import tan, sin, cos, pi, radians, remainder from itertools import product, chain from multimethod import multimethod from typish import instance_of, get_type @@ -336,36 +336,27 @@ def rarray(self: T, xs: Real, ys: Real, nx: int, ny: int) -> T: for el in selection ) - def parray(self: T, r: Real, a1: Real, a2: Real, n: int, rotate: bool = True) -> T: + def parray(self: T, r: Real, a1: Real, da: Real, n: int, rotate: bool = True) -> T: """ Generate a polar array of locations. """ if n < 1: - raise ValueError(f"At least 1 elements required, requested {n}") + raise ValueError(f"At least 1 element required, requested {n}") - x = r * sin(radians(a1)) - y = r * cos(radians(a1)) + locs = [] - if rotate: - loc = Location(Vector(x, y), Vector(0, 0, 1), -a1) + if abs(remainder(da, 360)) < 1e-6: + angle = da / n else: - loc = Location(Vector(x, y)) - - locs = [loc] + angle = da / (n - 1) if n > 1 else a1 - angle = (a2 - a1) / (n - 1) - - for i in range(1, n): + for i in range(0, n): phi = a1 + (angle * i) - x = r * sin(radians(phi)) - y = r * cos(radians(phi)) - - if rotate: - loc = Location(Vector(x, y), Vector(0, 0, 1), -phi) - else: - loc = Location(Vector(x, y)) + x = r * cos(radians(phi)) + y = r * sin(radians(phi)) + loc = Location(Vector(x, y)) locs.append(loc) if self._selection: @@ -374,9 +365,18 @@ def parray(self: T, r: Real, a1: Real, a2: Real, n: int, rotate: bool = True) -> selection = [Vector()] return self.push( - (l * el if isinstance(el, Location) else l * Location(el.Center())) - for l in locs - for el in selection + ( + l + * el + * Location( + Vector(0, 0), Vector(0, 0, 1), (a1 + (angle * i)) if rotate else 0 + ) + ) + for i, l in enumerate(locs) + for el in [ + el if isinstance(el, Location) else Location(el.Center()) + for el in selection + ] ) def distribute( @@ -387,7 +387,7 @@ def distribute( """ if not self._selection: - raise ValueError("Nothing selected to distirbute over") + raise ValueError("Nothing selected to distribute over") params = [start + i * (stop - start) / n for i in range(n + 1)] diff --git a/tests/test_sketch.py b/tests/test_sketch.py index fbdc4a8f0..10ae55346 100644 --- a/tests/test_sketch.py +++ b/tests/test_sketch.py @@ -145,9 +145,12 @@ def test_distribute(): s7 = Sketch().parray(2, 0, 90, 3, False).rect(0.5, 0.5).reset().vertices(">(1,1,0)") assert len(s7._selection) == 1 + assert s7._selection[0].toTuple() == approx( + (1.6642135623730951, 1.664213562373095, 0.0) + ) s8 = Sketch().push([(0, 0), (0, 1)]).parray(2, 0, 90, 3).rect(0.5, 0.5) - s8.reset().faces(">(1,1,0)") + s8.reset().faces(">(0,1,0)") assert s8._selection[0].Center().Length == approx(3) @@ -155,6 +158,55 @@ def test_distribute(): assert len(s9._tags["loc"]) == 1 + s10 = Sketch().push([(-4, 1), (0, 0), (4, -1)]).parray(2, 10, 50, 3).rect(1.0, 0.5) + s10.reset().vertices(">(-1,0,0)") + + assert s10._selection[0].toTuple() == approx( + (-3.46650635094611, 2.424038105676658, 0.0) + ) + + s10.reset().vertices(">(1,0,0)") + + assert s10._selection[0].toTuple() == approx( + (6.505431426947252, -0.8120814940857262, 0.0) + ) + + s11 = Sketch().parray(1, 135, 0, 1).circle(0.1) + s11.reset().faces() + + assert len(s11._selection) == 1 + assert s11._selection[0].Center().toTuple() == approx( + (-0.7071067811865475, 0.7071067811865476, 0.0) + ) + + s12 = Sketch().parray(4, 20, 360, 6).rect(1.0, 0.5) + + assert len(s12._faces.Faces()) == 6 + + s12.reset().vertices(">(0,-1,0)") + + assert s12._selection[0].toTuple() == approx( + (-0.5352148612481344, -4.475046932971669, 0.0) + ) + + s13 = ( + Sketch() + .push([(-4, 1)]) + .circle(0.1) + .reset() + .faces() + .parray(2, 10, 50, 3) + .rect(1.0, 0.5, 40, "a", "rects") + ) + + assert len(s13._faces.Faces()) == 4 + + s13.reset().vertices(">(-1,0,0)", tag="rects") + + assert s13._selection[0].toTuple() == approx( + (-3.3330260270865173, 3.1810426396582487, 0.0) + ) + def test_each():