Skip to content
This repository has been archived by the owner on Feb 9, 2021. It is now read-only.

Add radius arc #254

Merged
merged 4 commits into from
Apr 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions cadquery/cq.py
Original file line number Diff line number Diff line change
Expand Up @@ -1320,11 +1320,13 @@ def threePointArc(self, point1, point2, forConstruction=False):
provide tangent arcs
"""

gstartPoint = self._findFromPoint(False)
gpoint1 = self.plane.toWorldCoords(point1)
gpoint2 = self.plane.toWorldCoords(point2)
startPoint = self._findFromPoint(False)
if not isinstance(point1, Vector):
point1 = self.plane.toWorldCoords(point1)
if not isinstance(point2, Vector):
point2 = self.plane.toWorldCoords(point2)

arc = Edge.makeThreePointArc(gstartPoint, gpoint1, gpoint2)
arc = Edge.makeThreePointArc(startPoint, point1, point2)

if not forConstruction:
self._addPendingEdge(arc)
Expand All @@ -1347,8 +1349,8 @@ def sagittaArc(self, endPoint, sag, forConstruction=False):
See "https://en.wikipedia.org/wiki/Sagitta_(geometry)" for more information.
"""

startPoint = self._findFromPoint(False)
endPoint = self.plane.toWorldCoords(endPoint)
startPoint = self._findFromPoint(useLocalCoords=True)
endPoint = Vector(endPoint)
midPoint = endPoint.add(startPoint).multiply(0.5)

sagVector = endPoint.sub(startPoint).normalized().multiply(abs(sag))
Expand All @@ -1359,12 +1361,37 @@ def sagittaArc(self, endPoint, sag, forConstruction=False):

sagPoint = midPoint.add(sagVector)

arc = Edge.makeThreePointArc(startPoint, sagPoint, endPoint)
return self.threePointArc(sagPoint, endPoint, forConstruction)

if not forConstruction:
self._addPendingEdge(arc)
def radiusArc(self, endPoint, radius, forConstruction=False):
"""
Draw an arc from the current point to endPoint with an arc defined by the sag (sagitta).

return self.newObject([arc])
:param endPoint: end point for the arc
:type endPoint: 2-tuple, in workplane coordinates
:param radius: the radius of the arc
:type radius: float, the radius of the arc between start point and end point.
:return: a workplane with the current point at the end of the arc

Given that a closed contour is drawn clockwise;
A positive radius means convex arc and negative radius means concave arc.
"""

startPoint = self._findFromPoint(useLocalCoords=True)
endPoint = Vector(endPoint)

# Calculate the sagitta from the radius
length = endPoint.sub(startPoint).Length / 2.0
try:
sag = abs(radius) - math.sqrt(radius**2 - length**2)
except ValueError:
raise ValueError("Arc radius is not large enough to reach the end point.")

# Return a sagittaArc
if radius > 0:
return self.sagittaArc(endPoint, sag, forConstruction)
else:
return self.sagittaArc(endPoint, -sag, forConstruction)

def rotateAndCopy(self, matrix):
"""
Expand Down
23 changes: 14 additions & 9 deletions examples/FreeCAD/Ex005_Extruded_Lines_and_Arcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,28 @@
# half-way back to the origin in the X direction and 0.5 mm above where
# the last line ended at. The arc then ends at (0.0, 1.0), which is 1.0 mm
# above (in the Y direction) where our first line started from.
# 5. An arc is drawn from the last point that ends on (0.3, 0.2), the sag of
# the curve 0.1 determines that the curve is concave with the midpoint 0.1 mm
# from the arc baseline. If the sag was -0.1 the arc would be convex.
# 5. An arc is drawn from the last point that ends on (-0.5, 1.0), the sag of
# the curve 0.2 determines that the curve is concave with the midpoint 0.1 mm
# from the arc baseline. If the sag was -0.2 the arc would be convex.
# This convention is valid when the profile is drawn counterclockwise.
# The reverse is true if the profile is drawn clockwise.
# Clockwise: +sag => convex, -sag => concave
# Counterclockwise: +sag => concave, -sag => convex
# 6. close() is called to automatically draw the last line for us and close
# 6. An arc is drawn from the last point that ends on (-0.7, -0.2), the arc is
# determined by the radius of -1.5 mm.
# Clockwise: +radius => convex, -radius => concave
# Counterclockwise: +radius => concave, -radius => convex
# 7. close() is called to automatically draw the last line for us and close
# the sketch so that it can be extruded.
# 6a. Without the close(), the 2D sketch will be left open and the extrude
# 7a. Without the close(), the 2D sketch will be left open and the extrude
# operation will provide unpredictable results.
# 7. The 2D sketch is extruded into a solid object of the specified thickness.
# 8. The 2D sketch is extruded into a solid object of the specified thickness.
result = cq.Workplane("front").lineTo(width, 0) \
.lineTo(width, 1.0) \
.threePointArc((1.0, 2.5), (0.2, 2.6)) \
.sagittaArc((0.3, 0.2), 0.1) \
.threePointArc((1.0, 1.5), (0.0, 1.0)) \
.sagittaArc((-0.5, 1.0), 0.2) \
.radiusArc((-0.7, -0.2), -1.5) \
.close().extrude(thickness)

# Displays the result of this script
show_object(result)
16 changes: 13 additions & 3 deletions tests/TestCadQuery.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,9 +867,19 @@ def test2DDrawing(self):
r.vertices(selectors.NearestToPointSelector((0.0, 0.0, 0.0)))\
.first().val().Y))

# Test the sagittaArc functions
s = Workplane(Plane.YZ())
r = s.sagittaArc((10, 8), 1).close()
# Test the sagittaArc and radiusArc functions
a1 = Workplane(Plane.YZ()).threePointArc((5, 1), (10, 0))
a2 = Workplane(Plane.YZ()).sagittaArc((10, 0), -1)
a3 = Workplane(Plane.YZ()).threePointArc((6, 2), (12, 0))
a4 = Workplane(Plane.YZ()).radiusArc((12, 0), -10)

assert(a1.edges().first().val().geomType() == "CIRCLE")
assert(a2.edges().first().val().geomType() == "CIRCLE")
assert(a3.edges().first().val().geomType() == "CIRCLE")
assert(a4.edges().first().val().geomType() == "CIRCLE")

assert(a1.edges().first().val().Length() == a2.edges().first().val().Length())
assert(a3.edges().first().val().Length() == a4.edges().first().val().Length())

def testLargestDimension(self):
"""
Expand Down