Add ParabolicCenterArc function

This commit is contained in:
Kuravi H 2025-11-28 17:00:13 -05:00
parent a8fc16b344
commit 05876c15aa
8 changed files with 112 additions and 2 deletions

View file

@ -29,7 +29,7 @@ Objects and arithmetic
:math:`B^2 := \lbrace` ``Sketch``, ``Rectangle``, ``Circle``, ``Ellipse``, ``Rectangle``, ``Polygon``, ``RegularPolygon``, ``Text``, ``Trapezoid``, ``SlotArc``, ``SlotCenterPoint``, ``SlotCenterToCenter``, ``SlotOverall`` :math:`\rbrace`
:math:`B^1 := \lbrace` ``Curve``, ``Bezier``, ``FilletPolyline``, ``PolarLine``, ``Polyline``, ``Spline``, ``Helix``, ``CenterArc``, ``EllipticalCenterArc``, ``RadiusArc``, ``SagittaArc``, ``TangentArc``, ``ThreePointArc``, ``JernArc`` :math:`\rbrace`
:math:`B^1 := \lbrace` ``Curve``, ``Bezier``, ``FilletPolyline``, ``PolarLine``, ``Polyline``, ``Spline``, ``Helix``, ``CenterArc``, ``EllipticalCenterArc``, ``ParabolicCenterArc``, ``RadiusArc``, ``SagittaArc``, ``TangentArc``, ``ThreePointArc``, ``JernArc`` :math:`\rbrace`
with :math:`B^3 \subset C^3, B^2 \subset C^2` and :math:`B^1 \subset C^1`

View file

@ -23,6 +23,7 @@ Cheat Sheet
| :class:`~objects_curve.CenterArc`
| :class:`~objects_curve.DoubleTangentArc`
| :class:`~objects_curve.EllipticalCenterArc`
| :class:`~objects_curve.ParabolicCenterArc`
| :class:`~objects_curve.FilletPolyline`
| :class:`~objects_curve.Helix`
| :class:`~objects_curve.IntersectingLine`

View file

@ -118,6 +118,13 @@ The following objects all can be used in BuildLine contexts. Note that
+++
Elliptical arc defined by center, radii & angles
.. grid-item-card:: :class:`~objects_curve.ParabolicCenterArc`
.. image:: assets/parabolic_center_arc_example.svg
+++
Parabolic arc defined by vertex, focal length & angles
.. grid-item-card:: :class:`~objects_curve.FilletPolyline`
.. image:: assets/filletpolyline_example.svg

View file

@ -125,6 +125,14 @@ svg.add_shape(elliptical_center_arc.line)
svg.add_shape(dot.moved(Location(Vector((0, 0)))))
svg.write("assets/elliptical_center_arc_example.svg")
with BuildLine() as parabolic_center_arc:
ParabolicCenterArc((0, 0), 0.5, 60, 0)
s = 100 / max(*parabolic_center_arc.line.bounding_box().size)
svg = ExportSVG(scale=s)
svg.add_shape(parabolic_center_arc.line)
svg.add_shape(dot.moved(Location(Vector((0, 0)))))
svg.write("assets/parabolic_center_arc_example.svg")
with BuildLine() as helix:
Helix(1, 3, 1)
scene = Compound(helix.line) + Compound.make_triad(0.5)

View file

@ -88,6 +88,7 @@ __all__ = [
"DoubleTangentArc",
"EllipticalCenterArc",
"EllipticalStartArc",
"ParabolicCenterArc",
"FilletPolyline",
"Helix",
"IntersectingLine",

View file

@ -287,6 +287,7 @@ def import_svg_as_buildline_code(
"QuadraticBezier": ["Bezier", "start", "control", "end"],
"Arc": [
"EllipticalCenterArc",
"ParabolicCenterArc",
# "EllipticalStartArc",
"start",
"end",

View file

@ -741,6 +741,61 @@ class EllipticalCenterArc(BaseEdgeObject):
super().__init__(curve, mode=mode)
class ParabolicCenterArc(BaseEdgeObject):
"""Line Object: Parabolic Center Arc
Create a parabolic arc defined by a vertex point and focal length (distance from focus to vertex).
Args:
vertex (VectorLike): parabola vertex
focal_length (float): focal length the parabola (distance from the vertex to focus along the x-axis of plane)
start_angle (float, optional): arc start angle.
Defaults to 0.0
end_angle (float, optional): arc end angle.
Defaults to 90.0
rotation (float, optional): angle to rotate arc. Defaults to 0.0
angular_direction (AngularDirection, optional): arc direction.
Defaults to AngularDirection.COUNTER_CLOCKWISE
plane (Plane, optional): base plane. Defaults to Plane.XY
mode (Mode, optional): combination mode. Defaults to Mode.ADD
"""
_applies_to = [BuildLine._tag]
def __init__(
self,
vertex: VectorLike,
focal_length: float,
start_angle: float = 0.0,
end_angle: float = 90.0,
rotation: float = 0.0,
angular_direction: AngularDirection = AngularDirection.COUNTER_CLOCKWISE,
mode: Mode = Mode.ADD,
):
context: BuildLine | None = BuildLine._get_context(self)
validate_inputs(context, self)
vertex_pnt = WorkplaneList.localize(vertex)
if context is None:
parabola_workplane = Plane.XY
else:
parabola_workplane = copy_module.copy(
WorkplaneList._get_context().workplanes[0]
)
parabola_workplane.origin = vertex_pnt
curve = Edge.make_parabola(
focal_length=focal_length,
plane=parabola_workplane,
start_angle=start_angle,
end_angle=end_angle,
angular_direction=angular_direction,
).rotate(
Axis(parabola_workplane.origin, parabola_workplane.z_dir.to_dir()), rotation
)
super().__init__(curve, mode=mode)
class Helix(BaseEdgeObject):
"""Line Object: Helix

View file

@ -88,7 +88,7 @@ from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeOffset
from OCP.BRepPrimAPI import BRepPrimAPI_MakeHalfSpace
from OCP.BRepProj import BRepProj_Projection
from OCP.BRepTools import BRepTools, BRepTools_WireExplorer
from OCP.GC import GC_MakeArcOfCircle, GC_MakeArcOfEllipse
from OCP.GC import GC_MakeArcOfCircle, GC_MakeArcOfEllipse, GC_MakeArcOfParabola
from OCP.GCPnts import (
GCPnts_AbscissaPoint,
GCPnts_QuasiUniformDeflection,
@ -151,6 +151,7 @@ from OCP.gp import (
gp_Dir,
gp_Dir2d,
gp_Elips,
gp_Parab,
gp_Pln,
gp_Pnt,
gp_Pnt2d,
@ -2204,6 +2205,42 @@ class Edge(Mixin1D[TopoDS_Edge]):
return ellipse
@classmethod
def make_parabola(
cls,
focal_length: float,
plane: Plane = Plane.XY,
start_angle: float = 0.0,
end_angle: float = 90.0,
angular_direction: AngularDirection = AngularDirection.COUNTER_CLOCKWISE,
) -> Edge:
"""make parabola
Makes an parabola centered at the origin of plane.
Args:
focal_length (float): focal length the parabola (distance from the vertex to focus along the x-axis of plane)
plane (Plane, optional): base plane. Defaults to Plane.XY.
start_angle (float, optional): Defaults to 0.0.
end_angle (float, optional): Defaults to 90.0.
angular_direction (AngularDirection, optional): arc direction.
Defaults to AngularDirection.COUNTER_CLOCKWISE.
Returns:
Edge: full or partial parabola
"""
parabola_gp = gp_Parab(plane.to_gp_ax2(), focal_length)
parabola_geom = GC_MakeArcOfParabola(
parabola_gp,
start_angle * DEG2RAD,
end_angle * DEG2RAD,
angular_direction == AngularDirection.COUNTER_CLOCKWISE,
).Value()
parabola = cls(BRepBuilderAPI_MakeEdge(parabola_geom).Edge())
return parabola
@classmethod
def make_helix(
cls,