mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Switched make_helix from Wire to Edge method Issue #320
This commit is contained in:
parent
3c25ab3ccd
commit
77bb57988f
4 changed files with 74 additions and 70 deletions
|
|
@ -26,6 +26,7 @@ license:
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
"""
|
"""
|
||||||
from build123d import *
|
from build123d import *
|
||||||
|
from ocp_vscode import show_object
|
||||||
|
|
||||||
with BuildLine() as roller_coaster:
|
with BuildLine() as roller_coaster:
|
||||||
powerup = Spline(
|
powerup = Spline(
|
||||||
|
|
@ -40,5 +41,4 @@ with BuildLine() as roller_coaster:
|
||||||
Spline(corner @ 1, screw @ 0, tangents=(corner % 1, screw % 0))
|
Spline(corner @ 1, screw @ 0, tangents=(corner % 1, screw % 0))
|
||||||
Spline(screw @ 1, (-100, 30, 10), powerup @ 0, tangents=(screw % 1, powerup % 0))
|
Spline(screw @ 1, (-100, 30, 10), powerup @ 0, tangents=(screw % 1, powerup % 0))
|
||||||
|
|
||||||
if "show_object" in locals():
|
show_object(roller_coaster, name="roller_coaster")
|
||||||
show_object(roller_coaster.line.wrapped, name="roller_coaster")
|
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ class Helix(BaseLineObject):
|
||||||
validate_inputs(context, self)
|
validate_inputs(context, self)
|
||||||
|
|
||||||
center_pnt = WorkplaneList.localize(center)
|
center_pnt = WorkplaneList.localize(center)
|
||||||
helix = Wire.make_helix(
|
helix = Edge.make_helix(
|
||||||
pitch, height, radius, center_pnt, direction, cone_angle, lefthand
|
pitch, height, radius, center_pnt, direction, cone_angle, lefthand
|
||||||
)
|
)
|
||||||
super().__init__(helix, mode=mode)
|
super().__init__(helix, mode=mode)
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ from OCP.Geom import (
|
||||||
Geom_Surface,
|
Geom_Surface,
|
||||||
Geom_TrimmedCurve,
|
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.Geom2dAdaptor import Geom2dAdaptor_Curve
|
||||||
from OCP.Geom2dAPI import Geom2dAPI_InterCurveCurve
|
from OCP.Geom2dAPI import Geom2dAPI_InterCurveCurve
|
||||||
from OCP.GeomAbs import GeomAbs_C0, GeomAbs_Intersection, GeomAbs_JoinType
|
from OCP.GeomAbs import GeomAbs_C0, GeomAbs_Intersection, GeomAbs_JoinType
|
||||||
|
|
@ -4528,6 +4528,70 @@ class Edge(Shape, Mixin1D):
|
||||||
).Edge()
|
).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(
|
def distribute_locations(
|
||||||
self: Union[Wire, Edge],
|
self: Union[Wire, Edge],
|
||||||
count: int,
|
count: int,
|
||||||
|
|
@ -5753,8 +5817,8 @@ class Solid(Shape, Mixin3D):
|
||||||
|
|
||||||
# make an auxiliary spine
|
# make an auxiliary spine
|
||||||
pitch = 360.0 / angle * normal.length
|
pitch = 360.0 / angle * normal.length
|
||||||
aux_spine_w = Wire.make_helix(
|
aux_spine_w = Wire.make_wire(
|
||||||
pitch, normal.length, 1, center=center, normal=normal
|
[Edge.make_helix(pitch, normal.length, 1, center=center, normal=normal)]
|
||||||
).wrapped
|
).wrapped
|
||||||
|
|
||||||
# extrude the outer wire
|
# extrude the outer wire
|
||||||
|
|
@ -6546,66 +6610,6 @@ class Wire(Shape, Mixin1D):
|
||||||
|
|
||||||
return cls(wire_builder.Wire())
|
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:
|
def stitch(self, other: Wire) -> Wire:
|
||||||
"""Attempt to stich wires
|
"""Attempt to stich wires
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -908,6 +908,10 @@ class TestEdge(DirectApiTestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
edge.param_at_point((-1, 1))
|
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):
|
class TestFace(DirectApiTestCase):
|
||||||
def test_make_surface_from_curves(self):
|
def test_make_surface_from_curves(self):
|
||||||
|
|
@ -3016,10 +3020,6 @@ class TestWire(DirectApiTestCase):
|
||||||
)
|
)
|
||||||
self.assertAlmostEqual(full_ellipse.area / 2, half_ellipse.area, 5)
|
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):
|
def test_stitch(self):
|
||||||
half_ellipse1 = Wire.make_ellipse(
|
half_ellipse1 = Wire.make_ellipse(
|
||||||
2, 1, start_angle=0, end_angle=180, closed=False
|
2, 1, start_angle=0, end_angle=180, closed=False
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue