Switched make_helix from Wire to Edge method Issue #320

This commit is contained in:
gumyr 2023-09-25 13:44:28 -04:00
parent 3c25ab3ccd
commit 77bb57988f
4 changed files with 74 additions and 70 deletions

View file

@ -26,6 +26,7 @@ license:
limitations under the License.
"""
from build123d import *
from ocp_vscode import show_object
with BuildLine() as roller_coaster:
powerup = Spline(
@ -40,5 +41,4 @@ with BuildLine() as roller_coaster:
Spline(corner @ 1, screw @ 0, tangents=(corner % 1, screw % 0))
Spline(screw @ 1, (-100, 30, 10), powerup @ 0, tangents=(screw % 1, powerup % 0))
if "show_object" in locals():
show_object(roller_coaster.line.wrapped, name="roller_coaster")
show_object(roller_coaster, name="roller_coaster")

View file

@ -340,7 +340,7 @@ class Helix(BaseLineObject):
validate_inputs(context, self)
center_pnt = WorkplaneList.localize(center)
helix = Wire.make_helix(
helix = Edge.make_helix(
pitch, height, radius, center_pnt, direction, cone_angle, lefthand
)
super().__init__(helix, mode=mode)

View file

@ -162,7 +162,7 @@ from OCP.Geom import (
Geom_Surface,
Geom_TrimmedCurve,
)
from OCP.Geom2d import Geom2d_Curve, Geom2d_Line
from OCP.Geom2d import Geom2d_Curve, Geom2d_Line, Geom2d_TrimmedCurve
from OCP.Geom2dAdaptor import Geom2dAdaptor_Curve
from OCP.Geom2dAPI import Geom2dAPI_InterCurveCurve
from OCP.GeomAbs import GeomAbs_C0, GeomAbs_Intersection, GeomAbs_JoinType
@ -4528,6 +4528,70 @@ class Edge(Shape, Mixin1D):
).Edge()
)
@classmethod
def make_helix(
cls,
pitch: float,
height: float,
radius: float,
center: VectorLike = (0, 0, 0),
normal: VectorLike = (0, 0, 1),
angle: float = 0.0,
lefthand: bool = False,
) -> Wire:
"""make_helix
Make a helix with a given pitch, height and radius. By default a cylindrical surface is
used to create the helix. If the :angle: is set (the apex given in degree) a conical
surface is used instead.
Args:
pitch (float): distance per revolution along normal
height (float): total height
radius (float):
center (VectorLike, optional): Defaults to (0, 0, 0).
normal (VectorLike, optional): Defaults to (0, 0, 1).
angle (float, optional): conical angle. Defaults to 0.0.
lefthand (bool, optional): Defaults to False.
Returns:
Wire: helix
"""
# 1. build underlying cylindrical/conical surface
if angle == 0.0:
geom_surf: Geom_Surface = Geom_CylindricalSurface(
gp_Ax3(Vector(center).to_pnt(), Vector(normal).to_dir()), radius
)
else:
geom_surf = Geom_ConicalSurface(
gp_Ax3(Vector(center).to_pnt(), Vector(normal).to_dir()),
angle * DEG2RAD,
radius,
)
# 2. construct an segment in the u,v domain
# Determine the length of the 2d line which will be wrapped around the surface
line_sign = -1 if lefthand else 1
line_dir = Vector(line_sign * 2 * pi, pitch).normalized()
line_len = (height / line_dir.Y) / cos(radians(angle))
# Create an infinite 2d line in the direction of the helix
helix_line = Geom2d_Line(gp_Pnt2d(0, 0), gp_Dir2d(line_dir.X, line_dir.Y))
# Trim the line to the desired length
helix_curve = Geom2d_TrimmedCurve(
helix_line, 0, line_len, theAdjustPeriodic=True
)
# 3. Wrap the line around the surface
edge_builder = BRepBuilderAPI_MakeEdge(helix_curve, geom_surf)
topods_edge = edge_builder.Edge()
# 4. Convert the edge made with 2d geometry to 3d
BRepLib.BuildCurves3d_s(topods_edge)
return cls(topods_edge)
def distribute_locations(
self: Union[Wire, Edge],
count: int,
@ -5753,8 +5817,8 @@ class Solid(Shape, Mixin3D):
# make an auxiliary spine
pitch = 360.0 / angle * normal.length
aux_spine_w = Wire.make_helix(
pitch, normal.length, 1, center=center, normal=normal
aux_spine_w = Wire.make_wire(
[Edge.make_helix(pitch, normal.length, 1, center=center, normal=normal)]
).wrapped
# extrude the outer wire
@ -6546,66 +6610,6 @@ class Wire(Shape, Mixin1D):
return cls(wire_builder.Wire())
@classmethod
def make_helix(
cls,
pitch: float,
height: float,
radius: float,
center: VectorLike = (0, 0, 0),
normal: VectorLike = (0, 0, 1),
angle: float = 0.0,
lefthand: bool = False,
) -> Wire:
"""make_helix
Make a helix with a given pitch, height and radius. By default a cylindrical surface is
used to create the helix. If the :angle: is set (the apex given in degree) a conical
surface is used instead.
Args:
pitch (float): distance per revolution along normal
height (float): total height
radius (float):
center (VectorLike, optional): Defaults to (0, 0, 0).
normal (VectorLike, optional): Defaults to (0, 0, 1).
angle (float, optional): conical angle. Defaults to 0.0.
lefthand (bool, optional): Defaults to False.
Returns:
Wire: helix
"""
# 1. build underlying cylindrical/conical surface
if angle == 0.0:
geom_surf: Geom_Surface = Geom_CylindricalSurface(
gp_Ax3(Vector(center).to_pnt(), Vector(normal).to_dir()), radius
)
else:
geom_surf = Geom_ConicalSurface(
gp_Ax3(Vector(center).to_pnt(), Vector(normal).to_dir()),
angle * DEG2RAD,
radius,
)
# 2. construct an segment in the u,v domain
if lefthand:
geom_line = Geom2d_Line(gp_Pnt2d(0.0, 0.0), gp_Dir2d(-2 * pi, pitch))
else:
geom_line = Geom2d_Line(gp_Pnt2d(0.0, 0.0), gp_Dir2d(2 * pi, pitch))
# 3. put it together into a wire
u_start = geom_line.Value(0.0)
u_stop = geom_line.Value((height / pitch) * sqrt((2 * pi) ** 2 + pitch**2))
geom_seg = GCE2d_MakeSegment(u_start, u_stop).Value()
topo_edge = BRepBuilderAPI_MakeEdge(geom_seg, geom_surf).Edge()
# 4. Convert to wire and fix building 3d geom from 2d geom
wire = BRepBuilderAPI_MakeWire(topo_edge).Wire()
BRepLib.BuildCurves3d_s(wire, 1e-6, MaxSegment=2000) # NB: preliminary values
return cls(wire)
def stitch(self, other: Wire) -> Wire:
"""Attempt to stich wires

View file

@ -908,6 +908,10 @@ class TestEdge(DirectApiTestCase):
with self.assertRaises(ValueError):
edge.param_at_point((-1, 1))
def test_conical_helix(self):
helix = Edge.make_helix(1, 4, 1, normal=(-1, 0, 0), angle=10, lefthand=True)
self.assertAlmostEqual(helix.bounding_box().min.X, -4, 5)
class TestFace(DirectApiTestCase):
def test_make_surface_from_curves(self):
@ -3016,10 +3020,6 @@ class TestWire(DirectApiTestCase):
)
self.assertAlmostEqual(full_ellipse.area / 2, half_ellipse.area, 5)
def test_conical_helix(self):
helix = Wire.make_helix(1, 4, 1, normal=(-1, 0, 0), angle=10, lefthand=True)
self.assertAlmostEqual(helix.length, 34.102023034708374, 5)
def test_stitch(self):
half_ellipse1 = Wire.make_ellipse(
2, 1, start_angle=0, end_angle=180, closed=False