Skip to content

Commit 0653495

Browse files
author
Robin Oval
committed
rhino surface kinks, closest point on surface or boundaries and mapping/remapping objects on surface
1 parent 1cb4f41 commit 0653495

File tree

1 file changed

+168
-7
lines changed

1 file changed

+168
-7
lines changed

src/compas_rhino/geometry/surface.py

Lines changed: 168 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
import compas_rhino
77

88
from compas_rhino.geometry import RhinoGeometry
9+
from compas_rhino.geometry import RhinoCurve
10+
11+
from compas_rhino.utilities import delete_objects
912

1013
from compas.geometry import subtract_vectors
14+
from compas.geometry import angle_vectors
15+
1116

1217
try:
1318
import rhinoscriptsyntax as rs
@@ -229,6 +234,33 @@ def borders(self, type=1):
229234
curves = rs.ExplodeCurves(border, delete_input=True)
230235
return curves
231236

237+
def kinks(self, threshold=1e-3):
238+
"""Return the XYZ coordinates of kinks, i.e. tangency discontinuities, along the surface's boundaries.
239+
240+
Returns
241+
-------
242+
list
243+
The list of XYZ coordinates of surface boundary kinks.
244+
245+
"""
246+
247+
kinks = []
248+
borders = self.borders(type = 0)
249+
250+
for border in borders:
251+
border = RhinoCurve(border)
252+
extremities = map(lambda x: rs.EvaluateCurve(border.guid, rs.CurveParameter(border.guid, x)), [0., 1.])
253+
254+
if border.is_closed():
255+
start_tgt, end_tgt = border.tangents(extremities)
256+
if angle_vectors(start_tgt, end_tgt) > threshold:
257+
kinks += extremities
258+
259+
else:
260+
kinks += extremities
261+
262+
return list(set(kinks))
263+
232264
def project_point(self, point, direction=(0, 0, 1)):
233265
projections = rs.ProjectPointToSurface(point, self.guid, direction)
234266
if not projections:
@@ -242,13 +274,6 @@ def project_points(self, points, direction=(0, 0, 1), include_none=True):
242274
projections[:] = [self.closest_point(point) if not point else point for point in projections]
243275
return map(list, projections)
244276

245-
def closest_point(self, point, maxdist=None):
246-
point = self.geometry.ClosestPoint(Point3d(*point))
247-
return list(point)
248-
249-
def closest_points(self, points, maxdist=None):
250-
return [self.closest_point(point) for point in points]
251-
252277
def pull_point(self, point):
253278
pass
254279

@@ -278,7 +303,143 @@ def pull_mesh(self, mesh, fixed=None, d=1.0):
278303
def pull_meshes(self, meshes):
279304
pass
280305

306+
def closest_point(self, xyz):
307+
"""Return the XYZ coordinates of the closest point on the surface from input XYZ-coordinates.
308+
309+
Parameters
310+
----------
311+
xyz : list
312+
XYZ coordinates.
313+
314+
Returns
315+
-------
316+
list
317+
The XYZ coordinates of the closest point on the surface.
318+
319+
"""
320+
321+
return rs.EvaluateSurface(self.guid, *rs.SurfaceClosestPoint(self.guid, xyz))
322+
323+
def closest_points(self, points):
324+
return [self.closest_point(point) for point in points]
325+
326+
def closest_point_on_boundaries(self, xyz):
327+
"""Return the XYZ coordinates of the closest point on the boundaries of the surface from input XYZ-coordinates.
328+
329+
Parameters
330+
----------
331+
xyz : list
332+
XYZ coordinates.
333+
334+
Returns
335+
-------
336+
list
337+
The XYZ coordinates of the closest point on the boundaries of the surface.
338+
339+
"""
340+
341+
borders = self.borders(type = 0)
342+
proj_dist = {tuple(proj_xyz): distance_point_point(xyz, proj_xyz) for proj_xyz in [RhinoCurve(border).closest_point(xyz) for border in borders]}
343+
delete_objects(borders)
344+
return min(proj_dist, key = proj_dist.get)
345+
346+
def closest_points_on_boundaries(self, points):
347+
return [self.closest_point_on_boundaries(point) for point in points]
348+
349+
# --------------------------------------------------------------------------
350+
# mapping
351+
# --------------------------------------------------------------------------
352+
353+
def map_uv0(self, xyz):
354+
"""Return the UV(0) point from the mapping of a XYZ point based on the UV parameterisation of the surface.
355+
356+
Parameters
357+
----------
358+
xyz : list
359+
XYZ coordinates.
360+
361+
Returns
362+
-------
363+
list
364+
The UV(0) coordinates of the mapped point.
365+
366+
"""
367+
368+
return rs.SurfaceClosestPoint(self.guid, xyz) + (0.,)
369+
370+
def remap_xyz_point(self, uv):
371+
"""Return the XYZ point from the re-mapping of a UV point based on the UV parameterisation of the surface.
372+
373+
Parameters
374+
----------
375+
uv : list
376+
UV(0) coordinates.
377+
378+
Returns
379+
-------
380+
list
381+
The XYZ coordinates of the re-mapped point.
382+
383+
"""
384+
385+
return tuple(rs.EvaluateSurface(self.guid, *uv))
386+
387+
def remap_xyz_line(self, line):
388+
"""Return the XYZ points from the re-mapping of a UV line based on the UV parameterisation of the surface.
389+
390+
Parameters
391+
----------
392+
uv : list
393+
List of UV(0) coordinates.
394+
395+
Returns
396+
-------
397+
list
398+
The list of XYZ coordinates of the re-mapped line.
399+
400+
"""
401+
402+
return (self.remap_xyz_point(line[0][:2]), self.remap_xyz_point(line[1][:2]))
403+
404+
def remap_xyz_polyline(self, polyline):
405+
"""Return the XYZ points from the re-mapping of a UV polyline based on the UV parameterisation of the surface.
406+
407+
Parameters
408+
----------
409+
uv : list
410+
List of UV(0) coordinates.
411+
412+
Returns
413+
-------
414+
list
415+
The list of XYZ coordinates of the re-mapped polyline.
416+
417+
"""
418+
419+
return [self.remap_xyz_point(vertex[:2]) for vertex in polyline]
420+
421+
def remap_xyz_mesh(self, mesh, cls=None):
422+
"""Return the mesh from the re-mapping of a UV mesh based on the UV parameterisation of the surface.
423+
424+
Parameters
425+
----------
426+
mesh : Mesh
427+
A mesh.
428+
429+
Returns
430+
-------
431+
Mesh, cls
432+
The re-mapped mesh.
433+
434+
"""
435+
436+
if cls is None:
437+
cls = type(mesh)
281438

439+
vertices, faces = mesh.to_vertices_and_faces()
440+
vertices = [self.remap_xyz_point(uv0[:2]) for uv0 in vertices]
441+
return cls.from_vertices_and_faces(vertices, faces)
442+
282443
# ==============================================================================
283444
# Main
284445
# ==============================================================================

0 commit comments

Comments
 (0)