Skip to content

Commit 064b8f6

Browse files
committed
log and update to latest compas
1 parent ec09a46 commit 064b8f6

File tree

10 files changed

+369
-363
lines changed

10 files changed

+369
-363
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
* Added `compas_occ.geometry.OCCCurve`.
13+
* Added `compas_occ.geometry.OCCSurface`.
14+
* Added `compas_occ.brep.BRep.__add__` to support boolean union through "+".
15+
* Added `compas_occ.brep.BRep.__sub__` to support boolean difference through "-".
16+
* Added `compas_occ.brep.BRep.__and__` to support boolean intersection through "&".
17+
1218
### Changed
1319

20+
* Changed base class of `compas_occ.geometry.OCCNurbsCurve` to `compas_occ.geometry.OCCCurve`.
21+
* Changed base class of `compas_occ.geometry.OCCNurbsSurface` to `compas_occ.geometry.OCCSurface`.
22+
* Changed `compas_occ.brep.BRepEdge` to use `compas_occ.geometry.OCCCurve`.
23+
* Fixed bug in `compas_occ.brep.BRep.to_meshes`.
24+
* Fixed registration of curve plugin constructors to support multiple inheritance.
25+
* Fixed registration of surface plugin constructors to support multiple inheritance.
26+
1427
### Removed
1528

1629

docs/examples/surface_random.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@
3131
for col in zip(* surface.points):
3232
view.add(Polyline(col), show_points=True, pointsize=20, pointcolor=(1, 0, 0), linewidth=2, linecolor=(0.3, 0.3, 0.3))
3333

34-
view.add(surface.to_mesh(nu=100, nv=50))
34+
view.add(surface.to_mesh(nu=100, nv=100))
3535

3636
view.run()

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
compas>=1.10
1+
compas>=1.14
22
nptyping
33
typing_extensions

src/compas_occ/conversions/primitives.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
from compas.geometry import Vector
55
from compas.geometry import Line
66
from compas.geometry import Frame
7+
from compas.geometry import Circle
78

89
from OCC.Core.gp import gp_Ax3
910
from OCC.Core.gp import gp_Pnt
1011
from OCC.Core.gp import gp_Vec
1112
from OCC.Core.gp import gp_Dir
1213
from OCC.Core.gp import gp_Lin
14+
from OCC.Core.gp import gp_Circ
1315

1416

1517
def compas_point_to_occ_point(self: Point) -> gp_Pnt:
@@ -182,3 +184,7 @@ def compas_frame_from_occ_position(cls: Type[Frame], position: gp_Ax3) -> Frame:
182184
compas_vector_from_occ_direction(Vector, position.XDirection()),
183185
compas_vector_from_occ_direction(Vector, position.YDirection())
184186
)
187+
188+
189+
def compas_circle_to_occ(circle: Circle) -> gp_Circ:
190+
""""""

src/compas_occ/geometry/curves/curve.py

Lines changed: 193 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from compas.geometry import Frame
44
from compas.geometry import Curve
55
from compas.geometry import Box
6+
from compas.geometry import distance_point_point
7+
68

79
from OCC.Core.gp import gp_Trsf
810
from OCC.Core.gp import gp_Pnt
@@ -12,6 +14,14 @@
1214
from OCC.Core.GCPnts import GCPnts_AbscissaPoint_Length
1315
from OCC.Core.Bnd import Bnd_Box
1416
from OCC.Core.BndLib import BndLib_Add3dCurve_Add
17+
from OCC.Core.GeomAPI import GeomAPI_ProjectPointOnCurve
18+
from OCC.Core.GeomAPI import GeomAPI_ExtremaCurveCurve
19+
from OCC.Core.TopoDS import topods_Edge
20+
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
21+
from OCC.Core.Interface import Interface_Static_SetCVal
22+
from OCC.Core.IFSelect import IFSelect_RetDone
23+
from OCC.Core.STEPControl import STEPControl_Writer
24+
from OCC.Core.STEPControl import STEPControl_AsIs
1525

1626
from compas_occ.conversions import compas_point_from_occ_point
1727
from compas_occ.conversions import compas_vector_from_occ_vector
@@ -30,14 +40,8 @@ class OCCCurve(Curve):
3040
3141
Attributes
3242
----------
33-
continuity : int, read-only
34-
The degree of continuity of the curve.
35-
degree : int, read-only
36-
The degree of the curve.
3743
dimension : int, read-only
3844
The dimension of the curve.
39-
order : int, read-only
40-
The order of the curve (= degree + 1).
4145
domain : tuple[float, float], read-only
4246
The domain of the parameter space of the curve.
4347
start : :class:`~compas.geometry.Point`, read-only
@@ -60,49 +64,32 @@ def __init__(self, name=None):
6064
super().__init__(name=name)
6165
self._occ_curve = None
6266

63-
@property
64-
def occ_curve(self):
65-
return self._occ_curve
66-
67-
@occ_curve.setter
68-
def occ_curve(self, curve):
69-
self._occ_curve = curve
67+
def __eq__(self, other):
68+
return self.occ_curve.IsEqual(other.occ_curve)
7069

7170
# ==============================================================================
7271
# Data
7372
# ==============================================================================
7473

7574
# ==============================================================================
76-
# Customization
75+
# OCC Properties
7776
# ==============================================================================
7877

79-
def __eq__(self, other):
80-
return self.occ_curve.IsEqual(other.occ_curve)
81-
82-
# ==============================================================================
83-
# Constructors
84-
# ==============================================================================
85-
86-
@classmethod
87-
def from_occ(cls, occ_curve):
88-
"""Construct a NURBS curve from an existing OCC BSplineCurve.
89-
90-
Parameters
91-
----------
92-
occ_curve : Geom_BSplineCurve
78+
@property
79+
def occ_curve(self):
80+
return self._occ_curve
9381

94-
Returns
95-
-------
96-
:class:`OCCNurbsCurve`
82+
@occ_curve.setter
83+
def occ_curve(self, curve):
84+
self._occ_curve = curve
9785

98-
"""
99-
curve = cls()
100-
curve.occ_curve = occ_curve
101-
return curve
86+
@property
87+
def occ_shape(self):
88+
return BRepBuilderAPI_MakeEdge(self.occ_curve).Shape()
10289

103-
# ==============================================================================
104-
# Conversions
105-
# ==============================================================================
90+
@property
91+
def occ_edge(self):
92+
return topods_Edge(self.occ_shape)
10693

10794
# ==============================================================================
10895
# Properties
@@ -113,24 +100,10 @@ def dimension(self):
113100
if self.occ_curve:
114101
return 3
115102

116-
@property
117-
def continuity(self):
118-
if self.occ_curve:
119-
return self.occ_curve.Continuity()
120-
121-
@property
122-
def degree(self):
123-
if self.occ_curve:
124-
return self.occ_curve.Degree()
125-
126103
@property
127104
def domain(self):
128-
return self.occ_curve.FirstParameter(), self.occ_curve.LastParameter()
129-
130-
@property
131-
def order(self):
132105
if self.occ_curve:
133-
return self.degree + 1
106+
return self.occ_curve.FirstParameter(), self.occ_curve.LastParameter()
134107

135108
@property
136109
def start(self):
@@ -154,10 +127,83 @@ def is_periodic(self):
154127
if self.occ_curve:
155128
return self.occ_curve.IsPeriodic()
156129

130+
# ==============================================================================
131+
# Constructors
132+
# ==============================================================================
133+
134+
@classmethod
135+
def from_occ(cls, occ_curve):
136+
"""Construct a NURBS curve from an existing OCC BSplineCurve.
137+
138+
Parameters
139+
----------
140+
occ_curve : Geom_Curve
141+
142+
Returns
143+
-------
144+
:class:`OCCCurve`
145+
146+
"""
147+
curve = cls()
148+
curve.occ_curve = occ_curve
149+
return curve
150+
151+
# @classmethod
152+
# def from_circle(cls, circle):
153+
# """Construct a general parametric curve from a circle.
154+
155+
# Parameters
156+
# ----------
157+
# circle : :class:`~compas.geometry.Circle`
158+
# A primitive circle.
159+
160+
# Returns
161+
# -------
162+
# :class:`OCCCurve`
163+
164+
# """
165+
166+
# ==============================================================================
167+
# Conversions
168+
# ==============================================================================
169+
170+
def to_step(self, filepath, schema="AP203"):
171+
"""Write the curve geometry to a STP file.
172+
173+
Parameters
174+
----------
175+
filepath : str
176+
schema : str, optional
177+
178+
Returns
179+
-------
180+
None
181+
182+
"""
183+
step_writer = STEPControl_Writer()
184+
Interface_Static_SetCVal("write.step.schema", schema)
185+
step_writer.Transfer(self.occ_edge, STEPControl_AsIs)
186+
status = step_writer.Write(filepath)
187+
if status != IFSelect_RetDone:
188+
raise AssertionError("Operation failed.")
189+
157190
# ==============================================================================
158191
# Methods
159192
# ==============================================================================
160193

194+
def copy(self):
195+
"""Make an independent copy of the current curve.
196+
197+
Returns
198+
-------
199+
:class:`compas_occ.geometry.OCCCurve`
200+
201+
"""
202+
cls = type(self)
203+
curve = cls()
204+
curve.occ_curve = self.occ_curve.Copy()
205+
return curve
206+
161207
def transform(self, T):
162208
"""Transform this curve.
163209
@@ -288,6 +334,10 @@ def frame_at(self, t):
288334
self.occ_curve.D2(t, point, uvec, vvec)
289335
return Frame(Point.from_occ(point), Vector.from_occ(uvec), Vector.from_occ(vvec))
290336

337+
# ==============================================================================
338+
# Methods continued
339+
# ==============================================================================
340+
291341
def aabb(self, precision=0.0):
292342
"""Compute the axis aligned bounding box of the curve.
293343
@@ -304,7 +354,8 @@ def aabb(self, precision=0.0):
304354
BndLib_Add3dCurve_Add(GeomAdaptor_Curve(self.occ_curve), precision, box)
305355
return Box.from_diagonal((
306356
Point.from_occ(box.CornerMin()),
307-
Point.from_occ(box.CornerMax())))
357+
Point.from_occ(box.CornerMax())
358+
))
308359

309360
def length(self, precision=1e-3):
310361
"""Compute the length of the curve.
@@ -319,3 +370,91 @@ def length(self, precision=1e-3):
319370
320371
"""
321372
return GCPnts_AbscissaPoint_Length(GeomAdaptor_Curve(self.occ_curve))
373+
374+
def closest_point(self, point, return_parameter=False):
375+
"""Compute the closest point on the curve to a given point.
376+
If an orthogonal projection is not possible, the start or end point is returned, whichever is closer.
377+
378+
Parameters
379+
----------
380+
point : :class:`~compas.geometry.Point`
381+
The point to project to the curve.
382+
return_parameter : bool, optional
383+
If True, return the curve parameter in addition to the closest point.
384+
385+
Returns
386+
-------
387+
:class:`~compas.geometry.Point` | tuple[:class:`~compas.geometry.Point`, float]
388+
If `return_parameter` is False, the nearest point on the curve.
389+
If `return_parameter` is True, the nearest point on the curve and the corresponding parameter.
390+
391+
"""
392+
projector = GeomAPI_ProjectPointOnCurve(point.to_occ(), self.occ_curve)
393+
try:
394+
point = Point.from_occ(projector.NearestPoint())
395+
if return_parameter:
396+
parameter = projector.LowerDistanceParameter()
397+
except RuntimeError as e:
398+
if e.args[0].startswith('StdFail_NotDoneGeomAPI_ProjectPointOnCurve::NearestPoint'):
399+
start = self.start
400+
end = self.end
401+
if distance_point_point(point, start) <= distance_point_point(point, end):
402+
point = start
403+
if return_parameter:
404+
parameter = self.occ_curve.FirstParameter()
405+
else:
406+
point = end
407+
if return_parameter:
408+
parameter = self.occ_curve.LastParameter()
409+
else:
410+
raise
411+
if not return_parameter:
412+
return point
413+
return point, parameter
414+
415+
def closest_parameters_curve(self, curve, return_distance=False):
416+
"""Computes the curve parameters where the curve is the closest to another given curve.
417+
418+
Parameters
419+
----------
420+
curve : :class:`~compas_occ.geometry.OCCNurbsCurve`
421+
The curve to find the closest distance to.
422+
return_distance : bool, optional
423+
If True, return the minimum distance between the two curves in addition to the curve parameters.
424+
425+
Returns
426+
-------
427+
tuple[float, float] | tuple[tuple[float, float], float]
428+
If `return_distance` is False, the lowest distance parameters on the two curves.
429+
If `return_distance` is True, the distance between the two curves in addition to the curve parameters.
430+
431+
"""
432+
extrema = GeomAPI_ExtremaCurveCurve(self.occ_curve, curve.occ_curve)
433+
if not return_distance:
434+
return extrema.LowerDistanceParameters()
435+
return extrema.LowerDistanceParameters(), extrema.LowerDistance()
436+
437+
def closest_points_curve(self, curve, return_distance=False):
438+
"""Computes the points on curves where the curve is the closest to another given curve.
439+
440+
Parameters
441+
----------
442+
curve : :class:`~compas_occ.geometry.OCCNurbsCurve`
443+
The curve to find the closest distance to.
444+
return_distance : bool, optional
445+
If True, return the minimum distance between the curves in addition to the closest points.
446+
447+
Returns
448+
-------
449+
tuple[:class:`~compas.geometry.Point`, :class:`~compas.geometry.Point`] | tuple[tuple[:class:`~compas.geometry.Point`, :class:`~compas.geometry.Point`], float]
450+
If `return_distance` is False, the closest points.
451+
If `return_distance` is True, the distance in addition to the closest points.
452+
453+
"""
454+
a, b = gp_Pnt(), gp_Pnt()
455+
extrema = GeomAPI_ExtremaCurveCurve(self.occ_curve, curve.occ_curve)
456+
extrema.NearestPoints(a, b)
457+
points = Point.from_occ(a), Point.from_occ(b)
458+
if not return_distance:
459+
return points
460+
return points, extrema.LowerDistance()

0 commit comments

Comments
 (0)