diff --git a/cadquery/cq.py b/cadquery/cq.py index 1fceb9edb..f3df9c8cf 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -1344,6 +1344,7 @@ def polarArray( angle: float, count: int, fill: bool = True, + rotate: bool = True, ) -> "Workplane": """ Creates an polar array of points and pushes them onto the stack. @@ -1356,15 +1357,23 @@ def polarArray( value will fill in the counter-clockwise direction. If fill is false, angle is the angle between elements. :param count: Number of elements in array. ( > 0 ) + :param fill: Interpret the angle as total if True (default: True). + :param rotate: Rorate every item (default: True). """ if count <= 0: raise ValueError("No elements in array") # First element at start angle, convert to cartesian coords - x = radius * math.cos(math.radians(startAngle)) - y = radius * math.sin(math.radians(startAngle)) - points = [(x, y)] + x = radius * math.sin(math.radians(startAngle)) + y = radius * math.cos(math.radians(startAngle)) + + if rotate: + loc = Location(Vector(x, y), Vector(0, 0, 1), -startAngle) + else: + loc = Location(Vector(x, y)) + + locs = [loc] # Calculate angle between elements if fill: @@ -1376,12 +1385,19 @@ def polarArray( # Add additional elements for i in range(1, count): - phi = math.radians(startAngle + (angle * i)) - x = radius * math.cos(phi) - y = radius * math.sin(phi) - points.append((x, y)) + phi_deg = startAngle + (angle * i) + phi = math.radians(phi_deg) + x = radius * math.sin(phi) + y = radius * math.cos(phi) - return self.pushPoints(points) + if rotate: + loc = Location(Vector(x, y), Vector(0, 0, 1), -phi_deg) + else: + loc = Location(Vector(x, y)) + + locs.append(loc) + + return self.pushPoints(locs) def pushPoints(self, pntList: Iterable[Union[VectorLike, Location]]) -> "Workplane": """ @@ -1403,10 +1419,11 @@ def pushPoints(self, pntList: Iterable[Union[VectorLike, Location]]) -> "Workpla Here the circle function operates on all three points, and is then extruded to create three holes. See :py:meth:`circle` for how it works. """ - vecs = [] + vecs: List[Union[Location, Vector]] = [] for pnt in pntList: - vec = self.plane.toWorldCoords(pnt) - vecs.append(vec) + vecs.append( + pnt if isinstance(pnt, Location) else self.plane.toWorldCoords(pnt) + ) return self.newObject(vecs) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 23100716d..2ca7b63ee 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -969,25 +969,42 @@ def testPolarArray(self): s = Workplane("XY").polarArray(radius, 0, 180, 6) self.assertEqual(6, s.size()) + to_x = lambda l: l.wrapped.Transformation().TranslationPart().X() + to_y = lambda l: l.wrapped.Transformation().TranslationPart().Y() + to_angle = ( + lambda l: l.wrapped.Transformation().GetRotation().GetRotationAngle() + * 180.0 + / math.pi + ) + # Test for proper placement when fill == True s = Workplane("XY").polarArray(radius, 0, 180, 3) - self.assertAlmostEqual(0, s.objects[1].x) - self.assertAlmostEqual(radius, s.objects[1].y) + self.assertAlmostEqual(0, to_y(s.objects[1])) + self.assertAlmostEqual(radius, to_x(s.objects[1])) # Test for proper placement when angle to fill is multiple of 360 deg s = Workplane("XY").polarArray(radius, 0, 360, 4) - self.assertAlmostEqual(0, s.objects[1].x) - self.assertAlmostEqual(radius, s.objects[1].y) + self.assertAlmostEqual(0, to_y(s.objects[1])) + self.assertAlmostEqual(radius, to_x(s.objects[1])) # Test for proper placement when fill == False s = Workplane("XY").polarArray(radius, 0, 90, 3, fill=False) - self.assertAlmostEqual(0, s.objects[1].x) - self.assertAlmostEqual(radius, s.objects[1].y) + self.assertAlmostEqual(0, to_y(s.objects[1])) + self.assertAlmostEqual(radius, to_x(s.objects[1])) # Test for proper operation of startAngle s = Workplane("XY").polarArray(radius, 90, 180, 3) - self.assertAlmostEqual(0, s.objects[0].x) - self.assertAlmostEqual(radius, s.objects[0].y) + self.assertAlmostEqual(radius, to_x(s.objects[0])) + self.assertAlmostEqual(0, to_y(s.objects[0])) + + # Test for local rotation + s = Workplane().polarArray(radius, 0, 180, 3) + self.assertAlmostEqual(0, to_angle(s.objects[0])) + self.assertAlmostEqual(90, to_angle(s.objects[1])) + + s = Workplane().polarArray(radius, 0, 180, 3, rotate=False) + self.assertAlmostEqual(0, to_angle(s.objects[0])) + self.assertAlmostEqual(0, to_angle(s.objects[1])) def testNestedCircle(self): s = (