Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surface from rhino #1350

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c41b638
added plugin for Surface.from_plane
chenkasirer May 2, 2024
1d0b2c6
made argument `box` optional in `RhinoSurface.from_plane`
chenkasirer May 2, 2024
27a20d9
Merge branch 'main' of https://github.com/compas-dev/compas into surf…
chenkasirer May 2, 2024
b2a18e3
added `NurbsSurface.from_plane`
chenkasirer May 2, 2024
fdd97a9
Merge branch 'main' into surface_from_rhino
chenkasirer Jun 21, 2024
4dd4294
surface domain instead of box
chenkasirer Jun 21, 2024
4354d35
user specifies domain in RhinoNurbsSurface.from_plane
chenkasirer Jun 21, 2024
605a95e
default domains
chenkasirer Jun 21, 2024
7249f1e
noqa on typing imports
chenkasirer Jun 21, 2024
4242ee3
added from_native and native_surface to Surface
chenkasirer Jun 21, 2024
b78432a
Surface() create a RhinoSurface object in Rhino
chenkasirer Jun 21, 2024
5ed8791
added RhinoSurface.from_native plugin with intention to replace from_…
chenkasirer Jun 21, 2024
3e5017c
updated changelog
chenkasirer Jun 21, 2024
5566f95
unused import
chenkasirer Jun 21, 2024
de97233
WIP
chenkasirer Jun 24, 2024
0d72fe5
protect Surface(). Surface object can only be created via alternative…
chenkasirer Jul 2, 2024
0ea3ede
unused import
chenkasirer Jul 2, 2024
6a9c286
merge from_frame/plane. only implement abstract properties
chenkasirer Jul 3, 2024
d4f3ee0
fix search and replace accident
chenkasirer Jul 3, 2024
a3d6ecc
removed Surface.__from_data__
chenkasirer Jul 3, 2024
186ba78
instantiating nurbs surface via from_native
chenkasirer Jul 3, 2024
dafabfa
same from_native in nurbs and normal surface
chenkasirer Jul 3, 2024
5d86721
added domain and frame to nurbs params. __from_data__ is generic but …
chenkasirer Jul 3, 2024
33c388f
removed dead code and unused imports
chenkasirer Jul 3, 2024
9f6631d
added nurbssurface_to_compas
chenkasirer Jul 3, 2024
de25d04
native_surface is readonly
chenkasirer Jul 3, 2024
370ec8f
is_closed_u/v instead of is_closed
chenkasirer Jul 3, 2024
af70a6d
removed debug print
chenkasirer Jul 3, 2024
f8db6c9
updated changelog
chenkasirer Jul 3, 2024
5b5e1ac
linting
chenkasirer Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `VolMesh.vertex_edges`.
* Added `VolMesh.from_meshes`.
* Added `VolMesh.from_polyhedrons`.
* Added pluggable `Surface.from_native`.
* Added deprecation warning on `RhinoSurface.from_rhino`.
* Added `Surface.native_surface`.
* Added `RhinoSurface.native_surface`.
* Added plugin `RhinoSurface.from_native`.

### Changed

Expand All @@ -54,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Updated `compas.geometry.vector.__truediv__` to allow element-wise division with another vector.
* Fixed bug in registration `shapely` boolean plugins.
* Temporarily restrict `numpy` to versions lower than `2.x`.
* Changed `RhinoSurface` plugin `new_surface` to create `RhinoSurface` object when `compas.geometry.Surface()` is called.

### Removed

Expand Down
9 changes: 9 additions & 0 deletions src/compas/geometry/surfaces/nurbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ def new_nurbssurface_from_parameters(cls, *args, **kwargs):
raise PluginNotInstalledError


@pluggable(category="factories")
def new_nurbssurface_from_plane(cls, *args, **kwargs):
raise PluginNotInstalledError


@pluggable(category="factories")
def new_nurbssurface_from_points(cls, *args, **kwargs):
raise PluginNotInstalledError
Expand Down Expand Up @@ -350,6 +355,10 @@ def from_fill(cls, curve1, curve2, curve3=None, curve4=None, style="stretch"):
"""
return new_nurbssurface_from_fill(cls, curve1, curve2, curve3, curve4, style)

@classmethod
def from_plane(cls, plane, u_degree=1, v_degree=1):
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved
return new_nurbssurface_from_plane(cls, plane, u_degree, v_degree)

# ==============================================================================
# Conversions
# ==============================================================================
Expand Down
27 changes: 27 additions & 0 deletions src/compas/geometry/surfaces/surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ def new_surface(cls, *args, **kwargs):
return surface


@pluggable(category="factories")
def from_native(cls, *args, **kwargs):
raise NotImplementedError


@pluggable(category="factories")
def new_surface_from_plane(cls, *args, **kwargs):
raise NotImplementedError
Expand Down Expand Up @@ -47,6 +52,8 @@ class Surface(Geometry):
Flag indicating if the surface is periodic in the U direction.
is_periodic_v : bool, read-only
Flag indicating if the surface is periodic in the V direction.
native_surface : Any, read-only
The CAD native surface object.

"""

Expand Down Expand Up @@ -95,6 +102,10 @@ def transformation(self):
self._transformation = Transformation.from_frame(self.frame)
return self._transformation

@property
def native_surface(self):
raise NotImplementedError

@property
def point(self):
if not self._point:
Expand Down Expand Up @@ -197,6 +208,22 @@ def from_plane(cls, plane, *args, **kwargs):
"""
return new_surface_from_plane(cls, plane, *args, **kwargs)

@classmethod
def from_native(cls, surface):
"""Construct a surface from a CAD native surface object.

Parameters
----------
surface : Any
A native surface object.

Returns
-------
:class:`compas.geometry.Surface`

"""
return from_native(cls, surface)

# ==============================================================================
# Conversions
# ==============================================================================
Expand Down
10 changes: 6 additions & 4 deletions src/compas_rhino/geometry/surfaces/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from .surface import RhinoSurface # noqa : F401
from .nurbs import RhinoNurbsSurface

from compas.geometry import Surface
from compas.geometry import NurbsSurface
from compas.plugins import plugin


@plugin(category="factories", requires=["Rhino"])
def new_surface(cls, *args, **kwargs):
surface = super(Surface, cls).__new__(cls)
surface.__init__(*args, **kwargs)
return surface
return object.__new__(RhinoSurface)
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved


@plugin(category="factories", requires=["Rhino"])
def new_surface_from_plane(cls, *args, **kwargs):
return RhinoSurface.from_plane(*args, **kwargs)


@plugin(category="factories", requires=["Rhino"])
Expand Down
40 changes: 40 additions & 0 deletions src/compas_rhino/geometry/surfaces/nurbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from compas.geometry import Point
from compas.geometry import knots_and_mults_to_knotvector
from compas.itertools import flatten
from compas_rhino.conversions import plane_to_rhino
from compas_rhino.conversions import point_to_compas
from compas_rhino.conversions import point_to_rhino

Expand Down Expand Up @@ -361,6 +362,45 @@ def from_fill(cls, curve1, curve2):
surface.rhino_surface = Rhino.Geometry.NurbsSurface.CreateRuledSurface(curve1, curve2)
return surface

@classmethod
def from_plane(cls, plane, u_degree=1, v_degree=1, u_domain=(0.0, 1.0), v_domain=(0.0, 1.0)):
"""Construct a NURBS surface from a plane.

Parameters
----------
plane : :class:`compas.geometry.Plane`
The plane from which to construct the surface.
u_degree : int, optional
The degree of the surface in the U direction.
Default is ``1``.
v_degree : int, optional
The degree of the surface in the V direction.
Default is ``1``.
u_domain : tuple(float), optional
The domain of the surface in the U direction.
Default is ``(0, 1)``.
v_domain : tuple(float), optional
The domain of the surface in the V direction.
Default is ``(0, 1)``.

Returns
-------
:class:`compas_rhino.geometry.RhinoNurbsSurface`

"""
plane = plane_to_rhino(plane)
surface = cls()
surface.rhino_surface = Rhino.Geometry.NurbsSurface.CreateFromPlane(
plane,
Rhino.Geometry.Interval(*u_domain),
Rhino.Geometry.Interval(*v_domain),
u_degree,
v_degree,
u_degree + 1,
v_degree + 1,
)
return surface

# ==============================================================================
# Conversions
# ==============================================================================
Expand Down
71 changes: 59 additions & 12 deletions src/compas_rhino/geometry/surfaces/surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

import Rhino.Geometry # type: ignore

import compas

if not compas.IPY:
from typing import Tuple # noqa: F401

from compas.geometry import Plane # noqa: F401
from compas.geometry import Surface
from compas_rhino.conversions import box_to_compas
from compas_rhino.conversions import cylinder_to_rhino
Expand Down Expand Up @@ -31,12 +37,19 @@ class RhinoSurface(Surface):
True if the surface is periodic in the U direction.
is_periodic_v: bool
True if the surface is periodic in the V direction.
native_surface: :class:`Rhino.Geometry.Surface`
The underlying Rhino surface object.

"""

def __init__(self, name=None):
super(RhinoSurface, self).__init__(name=name)
self._rhino_surface = None
# empty surface is not really a valid RhinoSurface object.
self._rhino_surface = Rhino.Geometry.PlaneSurface(Rhino.Geometry.Plane.WorldXY, Rhino.Geometry.Interval(0, 1), Rhino.Geometry.Interval(0, 1))
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved

@property
def native_surface(self):
return self._rhino_surface

@property
def rhino_surface(self):
Expand Down Expand Up @@ -95,7 +108,7 @@ def from_corners(cls, corners):

"""
rhino_points = [Rhino.Geometry.Point3d(corner.x, corner.y, corner.z) for corner in corners]
return cls.from_rhino(Rhino.Geometry.NurbsSurface.CreateFromCorners(*rhino_points))
return cls.from_native(Rhino.Geometry.NurbsSurface.CreateFromCorners(*rhino_points))

@classmethod
def from_sphere(cls, sphere):
Expand All @@ -113,7 +126,7 @@ def from_sphere(cls, sphere):
"""
sphere = sphere_to_rhino(sphere)
surface = Rhino.Geometry.NurbsSurface.CreateFromSphere(sphere)
return cls.from_rhino(surface)
return cls.from_native(surface)

@classmethod
def from_cylinder(cls, cylinder):
Expand All @@ -131,7 +144,7 @@ def from_cylinder(cls, cylinder):
"""
cylinder = cylinder_to_rhino(cylinder)
surface = Rhino.Geometry.NurbsSurface.CreateFromCylinder(cylinder)
return cls.from_rhino(surface)
return cls.from_native(surface)

@classmethod
def from_torus(cls, torus):
Expand All @@ -153,6 +166,9 @@ def from_torus(cls, torus):
def from_rhino(cls, rhino_surface):
"""Construct a NURBS surface from an existing Rhino surface.

.. deprecated:: 2.1.1
``from_rhino`` will be removed in the future. Use ``from_native`` instead.

Parameters
----------
rhino_surface : :rhino:`Rhino.Geometry.Surface`
Expand All @@ -162,29 +178,60 @@ def from_rhino(cls, rhino_surface):
-------
:class:`compas_rhino.geometry.RhinoSurface`

"""
from warnings import warn

warn("RhinoSurface.from_rhino will be removed in the future. Use RhinoSurface.from_native instead.", DeprecationWarning)
return cls.from_native(rhino_surface)

@classmethod
def from_native(cls, native_surface):
"""Construct a surface from an existing Rhino surface.

Parameters
----------
native_surface : :rhino:`Rhino.Geometry.Surface`
A Rhino surface.

Returns
-------
:class:`compas_rhino.geometry.RhinoSurface`

"""
curve = cls()
curve.rhino_surface = rhino_surface
curve.rhino_surface = native_surface
return curve

@classmethod
def from_plane(cls, plane, box):
def from_plane(cls, plane, u_domain=(0.0, 1.0), v_domain=(0.0, 1.0)):
# type: (Plane, Tuple[float, float], Tuple[float, float]) -> RhinoSurface
"""Construct a surface from a plane.

Parameters
----------
plane : :class:`compas.geometry.Plane`
The plane.
u_domain : tuple(float, float), optional
The parametric domain of the U parameter. u_domain[0] => u_domain[1].
Default is ``(0.0, 1.0)``.
v_domain : tuple(float, float), optional
The parametric domain of the V parameter. v_domain[0] => v_domain[1].
Default is ``(0.0, 1.0)``.

Note
----
While the plane's origin is its center, the surface's parametric origin is at the surface's corner.
For the plane to overlap with the surface, the plane's origin should be first shifted by half it's domain.
Alternatively, the surface's domain can be adjusted to match the plane's origin.

Returns
-------
:class:`compas_rhino.geometry.RhinoSurface`

"""
plane = plane_to_rhino(plane)
box = Rhino.Geometry.BoundingBox(box.xmin, box.ymin, box.zmin, box.xmax, box.ymax, box.zmax)
rhino_surface = Rhino.Geometry.PlaneSurface.CreateThroughBox(plane, box)
return cls.from_rhino(rhino_surface)
rhino_surface = Rhino.Geometry.PlaneSurface(plane, Rhino.Geometry.Interval(*u_domain), Rhino.Geometry.Interval(*v_domain))
return cls.from_native(rhino_surface)

@classmethod
def from_frame(cls, frame, u_interval, v_interval):
Expand Down Expand Up @@ -213,7 +260,7 @@ def from_frame(cls, frame, u_interval, v_interval):
if not surface:
msg = "Failed creating PlaneSurface from frame:{} u_interval:{} v_interval:{}"
raise ValueError(msg.format(frame, u_interval, v_interval))
return cls.from_rhino(surface)
return cls.from_native(surface)

# ==============================================================================
# Conversions
Expand Down Expand Up @@ -264,7 +311,7 @@ def u_isocurve(self, u):

"""
curve = self.rhino_surface.IsoCurve(1, u) # type: ignore
return RhinoCurve.from_rhino(curve)
return RhinoCurve.from_native(curve)

def v_isocurve(self, v):
"""Compute the isoparametric curve at parameter v.
Expand All @@ -279,7 +326,7 @@ def v_isocurve(self, v):

"""
curve = self.rhino_surface.IsoCurve(0, v) # type: ignore
return RhinoCurve.from_rhino(curve)
return RhinoCurve.from_native(curve)

def point_at(self, u, v):
"""Compute a point on the surface.
Expand Down
Loading