Skip to content

Commit e0a103a

Browse files
committed
small updates and fixes for the mcneel workshop
1 parent 8e21328 commit e0a103a

File tree

7 files changed

+134
-3
lines changed

7 files changed

+134
-3
lines changed

CHANGELOG.md

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

1010
### Added
1111

12+
* Added `compas_rhino.geometry.RhinoCurve.offset`.
13+
* Added `compas.geometry.Surface.from_plane`.
14+
* Added `compas.geometry.surfaces.surface.new_surface_from_plane` pluggable.
15+
* Added `compas_rhino.geometry.surfaces.new_surface_from_plane` plugin.
16+
* Added `compas_rhino.geometry.RhinoSurface.intersections_with_curve`.
17+
1218
### Changed
1319

20+
* Fixed bug in `compas_rhino.geometry.RhinoCurve.frame_at`.
21+
* Changed implementation of `compas.datastructures.mesh_planarize_faces` to include edge midpoints.
22+
1423
### Removed
1524

1625

src/compas/datastructures/halfedge/halfedge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ def vertices_where_predicate(self, predicate, data=False):
712712
----------
713713
predicate : callable
714714
The condition you want to evaluate.
715-
The callable takes 2 parameters: the vertex identifier and the vertex attributs,
715+
The callable takes 2 parameters: the vertex identifier and the vertex attributes,
716716
and should return True or False.
717717
data : bool, optional
718718
If True, yield the vertex attributes in addition to the vertex identifiers.

src/compas/datastructures/mesh/planarisation.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
from compas.geometry import project_points_plane
66
from compas.geometry import centroid_points
7+
from compas.geometry import midpoint_point_point
78
from compas.geometry import distance_point_point
89
from compas.geometry import distance_line_line
910
from compas.geometry import bestfit_plane
1011

1112
from compas.utilities import window
13+
from compas.utilities import pairwise
1214

1315

1416
__all__ = [
@@ -98,7 +100,10 @@ def mesh_planarize_faces(mesh, fixed=None, kmax=100, callback=None, callback_arg
98100
for fkey in mesh.faces():
99101
vertices = mesh.face_vertices(fkey)
100102
points = [mesh.vertex_coordinates(key) for key in vertices]
101-
plane = bestfit_plane(points)
103+
midpoints = []
104+
for a, b in pairwise(points + points[:1]):
105+
midpoints.append(midpoint_point_point(a, b))
106+
plane = bestfit_plane(points + midpoints)
102107
projections = project_points_plane(points, plane)
103108

104109
for index, key in enumerate(vertices):

src/compas/geometry/surfaces/surface.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ def new_surface(cls, *args, **kwargs):
1414
raise NotImplementedError
1515

1616

17+
@pluggable(category="factories")
18+
def new_surface_from_plane(cls, *args, **kwargs):
19+
raise NotImplementedError
20+
21+
1722
class Surface(Geometry):
1823
"""Class representing a general surface object.
1924
@@ -107,6 +112,22 @@ def from_obj(cls, filepath):
107112
"""
108113
raise NotImplementedError
109114

115+
@classmethod
116+
def from_plane(cls, plane, *args, **kwargs):
117+
"""Construct a surface from a plane.
118+
119+
Parameters
120+
----------
121+
plane : :class:`compas.geometry.Plane`
122+
The plane.
123+
124+
Returns
125+
-------
126+
:class:`~compas.geometry.Surface`
127+
128+
"""
129+
return new_surface_from_plane(cls, plane, *args, **kwargs)
130+
110131
# ==============================================================================
111132
# Conversions
112133
# ==============================================================================
@@ -393,3 +414,17 @@ def intersections_with_line(self, line):
393414
394415
"""
395416
raise NotImplementedError
417+
418+
def intersections_with_curve(self, curve):
419+
"""Compute the intersections with a curve.
420+
421+
Parameters
422+
----------
423+
line : :class:`~compas.geometry.Curve`
424+
425+
Returns
426+
-------
427+
list[:class:`~compas.geometry.Point`]
428+
429+
"""
430+
raise NotImplementedError

src/compas_rhino/geometry/curves/curve.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
from __future__ import division
44

55
from compas.geometry import Curve
6+
from compas.geometry import Plane
67

78
from compas_rhino.conversions import point_to_rhino
89
from compas_rhino.conversions import point_to_compas
910
from compas_rhino.conversions import vector_to_compas
1011
from compas_rhino.conversions import xform_to_rhino
1112
from compas_rhino.conversions import plane_to_compas_frame
13+
from compas_rhino.conversions import plane_to_rhino
1214
from compas_rhino.conversions import box_to_compas
1315

1416

@@ -227,7 +229,7 @@ def frame_at(self, t):
227229
The corresponding local frame.
228230
229231
"""
230-
plane = self.rhino_curve.FrameAt(t)
232+
t, plane = self.rhino_curve.FrameAt(t)
231233
return plane_to_compas_frame(plane)
232234

233235
def torsion_at(self, t):
@@ -346,3 +348,36 @@ def length(self, precision=1e-8):
346348
347349
"""
348350
return self.rhino_curve.GetLength(precision)
351+
352+
def fair(self, tol=1e-3):
353+
raise NotImplementedError
354+
355+
def offset(self, distance, direction, tolerance=1e-3):
356+
"""Compute the length of the curve.
357+
358+
Parameters
359+
----------
360+
distance : float
361+
The offset distance.
362+
direction : :class:`compas.geometry.Vector`
363+
The normal direction of the offset plane.
364+
tolerance : float, optional
365+
366+
Returns
367+
-------
368+
None
369+
370+
"""
371+
point = self.point_at(self.domain[0])
372+
plane = Plane(point, direction)
373+
plane = plane_to_rhino(plane)
374+
self.rhino_curve = self.rhino_curve.Offset(plane, distance, tolerance, 0)[0]
375+
376+
def smooth(self):
377+
raise NotImplementedError
378+
379+
def split(self):
380+
raise NotImplementedError
381+
382+
def trim(self):
383+
raise NotImplementedError

src/compas_rhino/geometry/surfaces/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ def new_surface(cls, *args, **kwargs):
1111
return super(Surface, cls).__new__(cls)
1212

1313

14+
@plugin(category="factories", requires=["Rhino"])
15+
def new_surface_from_plane(cls, *args, **kwargs):
16+
return RhinoSurface.from_plane(*args, **kwargs)
17+
18+
1419
@plugin(category="factories", requires=["Rhino"])
1520
def new_nurbssurface(cls, *args, **kwargs):
1621
return super(NurbsSurface, cls).__new__(cls)

src/compas_rhino/geometry/surfaces/surface.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from compas_rhino.conversions import point_to_compas
99
from compas_rhino.conversions import vector_to_compas
1010
from compas_rhino.conversions import plane_to_compas_frame
11+
from compas_rhino.conversions import plane_to_rhino
1112
from compas_rhino.conversions import box_to_compas
1213
from compas_rhino.conversions import xform_to_rhino
1314
from compas_rhino.conversions import sphere_to_rhino
@@ -167,6 +168,25 @@ def from_rhino(cls, rhino_surface):
167168
curve.rhino_surface = rhino_surface
168169
return curve
169170

171+
@classmethod
172+
def from_plane(cls, plane, box):
173+
"""Construct a surface from a plane.
174+
175+
Parameters
176+
----------
177+
plane : :class:`compas.geometry.Plane`
178+
The plane.
179+
180+
Returns
181+
-------
182+
:class:`~compas_rhino.geometry.RhinoSurface`
183+
184+
"""
185+
plane = plane_to_rhino(plane)
186+
box = Rhino.Geometry.BoundingBox(box.xmin, box.ymin, box.zmin, box.xmax, box.ymax, box.zmax)
187+
rhino_surface = Rhino.Geometry.PlaneSurface.CreateThroughBox(plane, box)
188+
return cls.from_rhino(rhino_surface)
189+
170190
# ==============================================================================
171191
# Conversions
172192
# ==============================================================================
@@ -337,3 +357,25 @@ def aabb(self, precision=0.0, optimal=False):
337357
"""
338358
box = self.rhino_surface.GetBoundingBox(optimal)
339359
return box_to_compas(Rhino.Geometry.Box(box))
360+
361+
def intersections_with_curve(self, curve, tolerance=1e-3, overlap=1e-3):
362+
"""Compute the intersections with a curve.
363+
364+
Parameters
365+
----------
366+
line : :class:`~compas.geometry.Curve`
367+
368+
Returns
369+
-------
370+
list[:class:`~compas.geometry.Point`]
371+
372+
"""
373+
intersections = Rhino.Geometry.Intersect.Intersection.CurveSurface(
374+
curve.rhino_curve, self.rhino_surface, tolerance, overlap
375+
)
376+
points = []
377+
for event in intersections:
378+
if event.IsPoint:
379+
point = point_to_compas(event.PointA)
380+
points.append(point)
381+
return points

0 commit comments

Comments
 (0)