Skip to content

Commit fc66906

Browse files
committed
WIP: Face and Edge from primitives
1 parent e283f59 commit fc66906

File tree

2 files changed

+109
-10
lines changed

2 files changed

+109
-10
lines changed

src/compas_rhino/geometry/brep/face.py

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
from compas.geometry import BrepFace
22
from compas_rhino.geometry import RhinoNurbsSurface
3+
from compas_rhino.conversions import plane_to_compas
4+
from compas_rhino.conversions import sphere_to_compas
5+
from compas_rhino.conversions import cylinder_to_compas
6+
from compas_rhino.conversions import plane_to_rhino
7+
from compas_rhino.conversions import sphere_to_rhino
8+
from compas_rhino.conversions import cylinder_to_rhino
39

410
from .loop import RhinoBrepLoop
511

@@ -35,9 +41,7 @@ def __init__(self, rhino_face=None):
3541
def _set_face(self, native_face):
3642
self._face = native_face
3743
self._loops = [RhinoBrepLoop(loop) for loop in self._face.Loops]
38-
self._surface = RhinoNurbsSurface.from_rhino(
39-
self._face.ToNurbsSurface()
40-
) # surface in Rhino will always be NURBS
44+
self._surface = self._face.UnderlyingSurface()
4145

4246
# ==============================================================================
4347
# Data
@@ -47,26 +51,35 @@ def _set_face(self, native_face):
4751
def data(self):
4852
boundary = self._loops[0].data
4953
holes = [loop.data for loop in self._loops[1:]]
50-
surface = {"type": "nurbs"}
51-
surface.update(self.surface.data)
52-
return {"boundary": boundary, "surface": surface, "holes": holes}
54+
surface_type, surface = self._get_surface_geometry(self._surface)
55+
return {"boundary": boundary, "holes": holes, "surface_type": surface_type, "surface": surface}
5356

5457
@data.setter
5558
def data(self, value):
5659
boundary = RhinoBrepLoop.from_data(value["boundary"])
5760
holes = [RhinoBrepLoop.from_data(loop) for loop in value["holes"]]
5861
self._loops = [boundary] + holes
59-
# TODO: should we check surface type here? should we support surfaces other than NURBS?
60-
self._surface = RhinoNurbsSurface.from_data(value["surface"])
62+
type_ = value["surface_type"]
63+
# TODO: using the new serialization mechanism, surface.to_nurbs() should replace all this branching..
64+
# TODO: given that Plane, Sphere, Cylinder etc. all implement to_nurbs()
65+
surface = value["surface"]
66+
if type_ == "plane":
67+
surface = self._make_surface_from_plane_loop(surface, boundary)
68+
elif type_ == "sphere":
69+
surface = RhinoNurbsSurface.from_sphere(surface)
70+
elif type_ == "cylinder":
71+
surface = RhinoNurbsSurface.from_cylinder(surface)
72+
elif type_ == "torus":
73+
raise NotImplementedError("Support for torus surface is not yet implemented!")
74+
self._surface = surface.rhino_surface
6175

6276
# ==============================================================================
6377
# Properties
6478
# ==============================================================================
6579

6680
@property
6781
def native_surface(self):
68-
if self._surface:
69-
return self._surface.rhino_surface
82+
return self._surface
7083

7184
@property
7285
def loops(self):
@@ -87,3 +100,39 @@ def holes(self):
87100
@property
88101
def is_plane(self):
89102
return
103+
104+
@staticmethod
105+
def _get_surface_geometry(surface):
106+
# success, cast_surface = surface.TryGetPlane()
107+
# if success:
108+
# return "plane", plane_to_compas(cast_surface)
109+
# success, cast_surface = surface.TryGetSphere()
110+
# if success:
111+
# return "sphere", sphere_to_compas(cast_surface)
112+
# success, cast_surface = surface.TryGetCylinder()
113+
# if success:
114+
# return "cylinder", cylinder_to_compas(cast_surface)
115+
# success, cast_surface = surface.TryGetTorus()
116+
# if success:
117+
# raise NotImplementedError("Support for torus surface is not yet implemented!")
118+
return "nurbs", RhinoNurbsSurface.from_rhino(surface.ToNurbsSurface())
119+
120+
# @staticmethod
121+
# def _make_surface_from_plane_loop(plane, loop):
122+
# # TODO: replace guesswork here with an actual calculation..
123+
# u_degree, v_degree = 1, 1
124+
# u_p_count, v_p_count = 2, 2
125+
# curve_lengths = [edge.curve.GetLength() for edge in loop.edges]
126+
# max_length = max(curve_lengths)
127+
# u_interval, v_interval = (0.0, max_length), (0.0, max_length)
128+
# return RhinoNurbsSurface.from_plane(plane, u_interval, v_interval, u_degree, v_degree, u_p_count, v_p_count)
129+
130+
@staticmethod
131+
def _make_surface_from_plane_loop(plane, loop):
132+
# TODO: replace guesswork here with an actual calculation..
133+
c0 = loop.edges[0].start_point
134+
c1 = loop.edges[1].start_point
135+
c2 = loop.edges[2].start_point
136+
c3 = loop.edges[3].start_point
137+
surface = RhinoNurbsSurface.from_corners([c3, c2, c1, c0])
138+
return surface

src/compas_rhino/geometry/surfaces/surface.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
from compas_rhino.conversions import plane_to_compas_frame
1111
from compas_rhino.conversions import box_to_compas
1212
from compas_rhino.conversions import xform_to_rhino
13+
from compas_rhino.conversions import plane_to_rhino
14+
from compas_rhino.conversions import sphere_to_rhino
15+
from compas_rhino.conversions import cylinder_to_rhino
1316

1417
from compas_rhino.geometry.curves import RhinoCurve
1518

@@ -76,6 +79,35 @@ def is_v_periodic(self):
7679
# Constructors
7780
# ==============================================================================
7881

82+
@classmethod
83+
def from_plane(cls, plane, u_interval, v_interval, u_degree, v_degree, u_point_count, v_point_count):
84+
plane = plane_to_rhino(plane)
85+
u_interval = Rhino.Geometry.Interval(u_interval[0], u_interval[1])
86+
v_interval = Rhino.Geometry.Interval(v_interval[0], v_interval[1])
87+
rhino_surface = Rhino.Geometry.NurbsSurface.CreateFromPlane(plane, u_interval, v_interval, u_degree, v_degree, u_point_count, v_point_count)
88+
return cls.from_rhino(rhino_surface)
89+
90+
@classmethod
91+
def from_corners(cls, corners):
92+
rhino_points = [Rhino.Geometry.Point3d(corner.x, corner.y, corner.z) for corner in corners]
93+
return cls.from_rhino(Rhino.Geometry.NurbsSurface.CreateFromCorners(*rhino_points))
94+
95+
@classmethod
96+
def from_sphere(cls, sphere):
97+
sphere = sphere_to_rhino(sphere)
98+
surface = Rhino.Geometry.NurbsSurface.CreateFromSphere(sphere)
99+
return cls.from_rhino(surface)
100+
101+
@classmethod
102+
def from_cylinder(cls, cylinder):
103+
cylinder = cylinder_to_rhino(cylinder)
104+
surface = Rhino.Geometry.NurbsSurface.CreateFromCylinder(cylinder)
105+
return cls.from_rhino(surface)
106+
107+
@classmethod
108+
def from_torus(cls, cylinder):
109+
raise NotImplementedError
110+
79111
@classmethod
80112
def from_rhino(cls, rhino_surface):
81113
"""Construct a NURBS surface from an existing Rhino surface.
@@ -255,3 +287,21 @@ def aabb(self, precision=0.0, optimal=False):
255287
"""
256288
box = self.rhino_surface.GetBoundingBox(optimal)
257289
return box_to_compas(Rhino.Geometry.Box(box))
290+
291+
def extend_u_by(self, value):
292+
self._extend_domain(0, value)
293+
294+
def extend_v_by(self, value):
295+
self._extend_domain(1, value)
296+
297+
def _extend_domain(self, domain, value):
298+
if not (domain == 0 or domain == 1):
299+
raise ValueError("Expected domain: 0 or 1")
300+
lower = self.rhino_surface.Domain(domain)[0]
301+
upper = self.rhino_surface.Domain(domain)[1]
302+
self.rhino_surface.Extend(domain, Rhino.Geometry.Interval(lower - value, upper + value))
303+
304+
def reverse(self):
305+
brep = self.rhino_surface.ToBrep()
306+
brep.Flip()
307+
self.rhino_surface = brep.Surfaces[0]

0 commit comments

Comments
 (0)