mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Merge branch 'dev' into tangents
Some checks failed
benchmarks / benchmarks (macos-14, 3.12) (push) Has been cancelled
benchmarks / benchmarks (macos-15-intel, 3.12) (push) Has been cancelled
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Has been cancelled
benchmarks / benchmarks (windows-latest, 3.12) (push) Has been cancelled
Upload coverage reports to Codecov / run (push) Has been cancelled
pylint / lint (3.10) (push) Has been cancelled
Run type checker / typecheck (3.10) (push) Has been cancelled
Run type checker / typecheck (3.13) (push) Has been cancelled
Wheel building and publishing / Build wheel on ubuntu-latest (push) Has been cancelled
tests / tests (macos-14, 3.10) (push) Has been cancelled
tests / tests (macos-14, 3.13) (push) Has been cancelled
tests / tests (macos-15-intel, 3.10) (push) Has been cancelled
tests / tests (macos-15-intel, 3.13) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
tests / tests (windows-latest, 3.10) (push) Has been cancelled
tests / tests (windows-latest, 3.13) (push) Has been cancelled
Wheel building and publishing / upload_pypi (push) Has been cancelled
Some checks failed
benchmarks / benchmarks (macos-14, 3.12) (push) Has been cancelled
benchmarks / benchmarks (macos-15-intel, 3.12) (push) Has been cancelled
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Has been cancelled
benchmarks / benchmarks (windows-latest, 3.12) (push) Has been cancelled
Upload coverage reports to Codecov / run (push) Has been cancelled
pylint / lint (3.10) (push) Has been cancelled
Run type checker / typecheck (3.10) (push) Has been cancelled
Run type checker / typecheck (3.13) (push) Has been cancelled
Wheel building and publishing / Build wheel on ubuntu-latest (push) Has been cancelled
tests / tests (macos-14, 3.10) (push) Has been cancelled
tests / tests (macos-14, 3.13) (push) Has been cancelled
tests / tests (macos-15-intel, 3.10) (push) Has been cancelled
tests / tests (macos-15-intel, 3.13) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
tests / tests (windows-latest, 3.10) (push) Has been cancelled
tests / tests (windows-latest, 3.13) (push) Has been cancelled
Wheel building and publishing / upload_pypi (push) Has been cancelled
This commit is contained in:
commit
52b2883fca
3 changed files with 108 additions and 23 deletions
|
|
@ -24,7 +24,7 @@ keywords = [
|
||||||
"brep",
|
"brep",
|
||||||
"cad",
|
"cad",
|
||||||
"cadquery",
|
"cadquery",
|
||||||
"opencscade",
|
"opencascade",
|
||||||
"python",
|
"python",
|
||||||
]
|
]
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
|
|
@ -44,7 +44,7 @@ dependencies = [
|
||||||
"ipython >= 8.0.0, < 10",
|
"ipython >= 8.0.0, < 10",
|
||||||
"lib3mf >= 2.4.1",
|
"lib3mf >= 2.4.1",
|
||||||
"ocpsvg >= 0.5, < 0.6",
|
"ocpsvg >= 0.5, < 0.6",
|
||||||
"ocp_gordon >= 0.1.13",
|
"ocp_gordon >= 0.1.17",
|
||||||
"trianglesolver",
|
"trianglesolver",
|
||||||
"sympy",
|
"sympy",
|
||||||
"scipy",
|
"scipy",
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,12 @@ from OCP.BRepTools import BRepTools, BRepTools_ReShape
|
||||||
from OCP.gce import gce_MakeLin
|
from OCP.gce import gce_MakeLin
|
||||||
from OCP.Geom import (
|
from OCP.Geom import (
|
||||||
Geom_BezierSurface,
|
Geom_BezierSurface,
|
||||||
|
Geom_BSplineCurve,
|
||||||
Geom_RectangularTrimmedSurface,
|
Geom_RectangularTrimmedSurface,
|
||||||
Geom_Surface,
|
Geom_Surface,
|
||||||
Geom_TrimmedCurve,
|
Geom_TrimmedCurve,
|
||||||
)
|
)
|
||||||
from OCP.GeomAbs import GeomAbs_C0, GeomAbs_G1, GeomAbs_G2, GeomAbs_CurveType
|
from OCP.GeomAbs import GeomAbs_C0, GeomAbs_CurveType, GeomAbs_G1, GeomAbs_G2
|
||||||
from OCP.GeomAPI import (
|
from OCP.GeomAPI import (
|
||||||
GeomAPI_ExtremaCurveCurve,
|
GeomAPI_ExtremaCurveCurve,
|
||||||
GeomAPI_PointsToBSplineSurface,
|
GeomAPI_PointsToBSplineSurface,
|
||||||
|
|
@ -104,13 +105,17 @@ from OCP.Standard import (
|
||||||
Standard_NoSuchObject,
|
Standard_NoSuchObject,
|
||||||
)
|
)
|
||||||
from OCP.StdFail import StdFail_NotDone
|
from OCP.StdFail import StdFail_NotDone
|
||||||
from OCP.TColgp import TColgp_HArray2OfPnt
|
from OCP.TColgp import TColgp_Array1OfPnt, TColgp_HArray2OfPnt
|
||||||
from OCP.TColStd import TColStd_HArray2OfReal
|
from OCP.TColStd import (
|
||||||
|
TColStd_Array1OfInteger,
|
||||||
|
TColStd_Array1OfReal,
|
||||||
|
TColStd_HArray2OfReal,
|
||||||
|
)
|
||||||
from OCP.TopExp import TopExp
|
from OCP.TopExp import TopExp
|
||||||
from OCP.TopoDS import TopoDS, TopoDS_Face, TopoDS_Shape, TopoDS_Shell, TopoDS_Solid
|
from OCP.TopoDS import TopoDS, TopoDS_Face, TopoDS_Shape, TopoDS_Shell, TopoDS_Solid
|
||||||
from OCP.TopTools import TopTools_IndexedDataMapOfShapeListOfShape, TopTools_ListOfShape
|
from OCP.TopTools import TopTools_IndexedDataMapOfShapeListOfShape, TopTools_ListOfShape
|
||||||
from typing_extensions import Self
|
|
||||||
from ocp_gordon import interpolate_curve_network
|
from ocp_gordon import interpolate_curve_network
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
from build123d.build_enums import (
|
from build123d.build_enums import (
|
||||||
CenterOf,
|
CenterOf,
|
||||||
|
|
@ -922,32 +927,65 @@ class Face(Mixin2D, Shape[TopoDS_Face]):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_gordon_surface(
|
def make_gordon_surface(
|
||||||
cls,
|
cls,
|
||||||
profiles: Iterable[Edge],
|
profiles: Iterable[VectorLike | Edge],
|
||||||
guides: Iterable[Edge],
|
guides: Iterable[VectorLike | Edge],
|
||||||
tolerance: float = 3e-4,
|
tolerance: float = 3e-4,
|
||||||
) -> Face:
|
) -> Face:
|
||||||
"""
|
"""
|
||||||
Creates a Gordon surface from a network of profile and guide curves.
|
Constructs a Gordon surface from a network of profile and guide curves.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
1. Profiles and guides may be defined as points or curves.
|
||||||
|
2. Only the first or last profile or guide may be a point.
|
||||||
|
3. At least one profile and one guide must be a non-point curve.
|
||||||
|
4. Each profile must intersect with every guide.
|
||||||
|
5. Both ends of every profile must lie on a guide.
|
||||||
|
6. Both ends of every guide must lie on a profile.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
profiles (Iterable[Edge]): Edges representing profile curves.
|
profiles (Iterable[VectorLike | Edge]): Profiles defined as points or edges.
|
||||||
guides (Iterable[Edge]): Edges representing guide curves.
|
guides (Iterable[VectorLike | Edge]): Guides defined as points or edges.
|
||||||
tolerance (float, optional): Tolerance for surface creation and
|
tolerance (float, optional): Tolerance used for surface construction and
|
||||||
intersection calculations.
|
intersection calculations.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: Input edge cannot be empty
|
ValueError: input Edge cannot be empty.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Face: the interpolated Gordon surface
|
Face: the interpolated Gordon surface
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def to_geom_curve(edge: Edge):
|
def create_zero_length_bspline_curve(
|
||||||
if edge.wrapped is None:
|
point: gp_Pnt, degree: int = 1
|
||||||
raise ValueError("input edge cannot be empty")
|
) -> Geom_BSplineCurve:
|
||||||
|
control_points = TColgp_Array1OfPnt(1, 2)
|
||||||
|
control_points.SetValue(1, point)
|
||||||
|
control_points.SetValue(2, point)
|
||||||
|
|
||||||
adaptor = BRepAdaptor_Curve(edge.wrapped)
|
knots = TColStd_Array1OfReal(1, 2)
|
||||||
curve = BRep_Tool.Curve_s(edge.wrapped, 0, 1)
|
knots.SetValue(1, 0.0)
|
||||||
|
knots.SetValue(2, 1.0)
|
||||||
|
|
||||||
|
multiplicities = TColStd_Array1OfInteger(1, 2)
|
||||||
|
multiplicities.SetValue(1, degree + 1)
|
||||||
|
multiplicities.SetValue(2, degree + 1)
|
||||||
|
|
||||||
|
curve = Geom_BSplineCurve(control_points, knots, multiplicities, degree)
|
||||||
|
return curve
|
||||||
|
|
||||||
|
def to_geom_curve(shape: VectorLike | Edge):
|
||||||
|
if isinstance(shape, (Vector, tuple, Sequence)):
|
||||||
|
_shape = Vector(shape)
|
||||||
|
single_point_curve = create_zero_length_bspline_curve(
|
||||||
|
gp_Pnt(_shape.wrapped.XYZ())
|
||||||
|
)
|
||||||
|
return single_point_curve
|
||||||
|
|
||||||
|
if shape.wrapped is None:
|
||||||
|
raise ValueError("input Edge cannot be empty")
|
||||||
|
|
||||||
|
adaptor = BRepAdaptor_Curve(shape.wrapped)
|
||||||
|
curve = BRep_Tool.Curve_s(shape.wrapped, 0, 1)
|
||||||
if not (
|
if not (
|
||||||
(adaptor.IsPeriodic() and adaptor.IsClosed())
|
(adaptor.IsPeriodic() and adaptor.IsClosed())
|
||||||
or adaptor.GetType() == GeomAbs_CurveType.GeomAbs_BSplineCurve
|
or adaptor.GetType() == GeomAbs_CurveType.GeomAbs_BSplineCurve
|
||||||
|
|
@ -958,8 +996,8 @@ class Face(Mixin2D, Shape[TopoDS_Face]):
|
||||||
)
|
)
|
||||||
return curve
|
return curve
|
||||||
|
|
||||||
ocp_profiles = [to_geom_curve(edge) for edge in profiles]
|
ocp_profiles = [to_geom_curve(shape) for shape in profiles]
|
||||||
ocp_guides = [to_geom_curve(edge) for edge in guides]
|
ocp_guides = [to_geom_curve(shape) for shape in guides]
|
||||||
|
|
||||||
gordon_bspline_surface = interpolate_curve_network(
|
gordon_bspline_surface = interpolate_curve_network(
|
||||||
ocp_profiles, ocp_guides, tolerance=tolerance
|
ocp_profiles, ocp_guides, tolerance=tolerance
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,11 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import random
|
import random
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest.mock import PropertyMock, patch
|
||||||
|
|
||||||
from unittest.mock import patch, PropertyMock
|
|
||||||
from OCP.Geom import Geom_RectangularTrimmedSurface
|
from OCP.Geom import Geom_RectangularTrimmedSurface
|
||||||
|
from OCP.GeomAPI import GeomAPI_ExtremaCurveCurve
|
||||||
|
|
||||||
from build123d.build_common import Locations, PolarLocations
|
from build123d.build_common import Locations, PolarLocations
|
||||||
from build123d.build_enums import Align, CenterOf, ContinuityLevel, GeomType
|
from build123d.build_enums import Align, CenterOf, ContinuityLevel, GeomType
|
||||||
from build123d.build_line import BuildLine
|
from build123d.build_line import BuildLine
|
||||||
|
|
@ -57,7 +59,6 @@ from build123d.operations_generic import fillet, offset
|
||||||
from build123d.operations_part import extrude
|
from build123d.operations_part import extrude
|
||||||
from build123d.operations_sketch import make_face
|
from build123d.operations_sketch import make_face
|
||||||
from build123d.topology import Edge, Face, Shell, Solid, Wire
|
from build123d.topology import Edge, Face, Shell, Solid, Wire
|
||||||
from OCP.GeomAPI import GeomAPI_ExtremaCurveCurve
|
|
||||||
|
|
||||||
|
|
||||||
class TestFace(unittest.TestCase):
|
class TestFace(unittest.TestCase):
|
||||||
|
|
@ -448,7 +449,7 @@ class TestFace(unittest.TestCase):
|
||||||
profiles, guides, tolerance=tolerance
|
profiles, guides, tolerance=tolerance
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_make_gordon_surface_edge_types(self):
|
def test_make_gordon_surface_input_types(self):
|
||||||
tolerance = 3e-4
|
tolerance = 3e-4
|
||||||
|
|
||||||
def point_at_uv_against_expected(u: float, v: float, expected_point: Vector):
|
def point_at_uv_against_expected(u: float, v: float, expected_point: Vector):
|
||||||
|
|
@ -538,6 +539,52 @@ class TestFace(unittest.TestCase):
|
||||||
point_at_uv_against_expected(u=0.0, v=0.5, expected_point=guides[0] @ 0.5)
|
point_at_uv_against_expected(u=0.0, v=0.5, expected_point=guides[0] @ 0.5)
|
||||||
point_at_uv_against_expected(u=1.0, v=0.5, expected_point=guides[0] @ 0.5)
|
point_at_uv_against_expected(u=1.0, v=0.5, expected_point=guides[0] @ 0.5)
|
||||||
|
|
||||||
|
profiles = [
|
||||||
|
points[0],
|
||||||
|
ThreePointArc(
|
||||||
|
points[1], (points[1] + points[3]) / 2 + Vector(0, 0, 2), points[3]
|
||||||
|
),
|
||||||
|
points[2],
|
||||||
|
]
|
||||||
|
guides = [
|
||||||
|
Spline(
|
||||||
|
points[0],
|
||||||
|
profiles[1] @ 0,
|
||||||
|
points[2],
|
||||||
|
),
|
||||||
|
Spline(
|
||||||
|
points[0],
|
||||||
|
profiles[1] @ 1,
|
||||||
|
points[2],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
gordon_surface = Face.make_gordon_surface(profiles, guides, tolerance=tolerance)
|
||||||
|
point_at_uv_against_expected(u=0.0, v=1.0, expected_point=guides[0] @ 1)
|
||||||
|
point_at_uv_against_expected(u=1.0, v=1.0, expected_point=guides[1] @ 1)
|
||||||
|
point_at_uv_against_expected(u=1.0, v=0.0, expected_point=points[0])
|
||||||
|
|
||||||
|
profiles = [
|
||||||
|
Line(points[0], points[1]),
|
||||||
|
(points[0] + points[2]) / 2,
|
||||||
|
Line(points[3], points[2]),
|
||||||
|
]
|
||||||
|
guides = [
|
||||||
|
Spline(
|
||||||
|
profiles[0] @ 0,
|
||||||
|
profiles[1],
|
||||||
|
profiles[2] @ 0,
|
||||||
|
),
|
||||||
|
Spline(
|
||||||
|
profiles[0] @ 1,
|
||||||
|
profiles[1],
|
||||||
|
profiles[2] @ 1,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
gordon_surface = Face.make_gordon_surface(
|
||||||
|
profiles, guides, tolerance=tolerance
|
||||||
|
)
|
||||||
|
|
||||||
def test_make_surface(self):
|
def test_make_surface(self):
|
||||||
corners = [Vector(x, y) for x in [-50.5, 50.5] for y in [-24.5, 24.5]]
|
corners = [Vector(x, y) for x in [-50.5, 50.5] for y in [-24.5, 24.5]]
|
||||||
net_exterior = Wire(
|
net_exterior = Wire(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue