Skip to content

Commit

Permalink
Merge pull request #1365 from compas-dev/update-discretisations
Browse files Browse the repository at this point in the history
Update discretisations
  • Loading branch information
tomvanmele authored Jun 5, 2024
2 parents bb60abc + 33b7a74 commit 40cf2c0
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 324 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

* Added `maxiter` parameter to `compas.geometry.icp_numpy`.
* Added `resolution_u` and `resolution_v` to `compas.geometry.Shape` to control discretisation resolution.
* Added `vertices`, `edges`, `faces`, `triangles` to `compas.geometry.Shape`.
* Added `points`, `lines`, `polygons` to `compas.geometry.Shape`.
* Added abstract `compute_vertices`, `compute_edges`, `compute_faces`, `compute_triangles` to `compas.geometry.Shape`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Box`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Capsule`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Cone`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Cylinder`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Sphere`.
* Added implementation of `compute_vertices`, `compute_edges`, `compute_faces` to `compas.geometry.Torus`.

### Changed

* Changed `compas_ghpython/utilities/drawing.py` to remove `System` dependency.
* Fixed bug in `compas.geometry.ic_numpy`, which was caused by returning only the last transformation of the iteration process.
* Changed check for empty vertices and faces to use `is None` to add support for `numpy` arrays.
* Changed order of `u` and `v` of `compas.geometry.SphericalSurface` to the match the excpected parametrisation.
* Changed `compas.geometry.Shape.to_vertices_and_faces` to use `Shape.vertices` and `Shape.faces` or `Shape.triangles`.

### Removed

* Removed `System`dependency in `compas_ghpython/utilities/drawing.py`.

## [2.1.1] 2024-05-14
Expand Down
3 changes: 2 additions & 1 deletion src/compas/datastructures/mesh/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from compas.geometry import Point
from compas.geometry import Polygon
from compas.geometry import Polyhedron
from compas.geometry import Shape # noqa: F401
from compas.geometry import Vector
from compas.geometry import add_vectors
from compas.geometry import angle_points
Expand Down Expand Up @@ -529,7 +530,7 @@ def from_polyhedron(cls, f): # type: (...) -> Mesh
return cls.from_vertices_and_faces(p.vertices, p.faces)

@classmethod
def from_shape(cls, shape, **kwargs): # type: (...) -> Mesh
def from_shape(cls, shape, **kwargs): # type: (Shape, dict) -> Mesh
"""Construct a mesh from a primitive shape.
Parameters
Expand Down
4 changes: 2 additions & 2 deletions src/compas/datastructures/volmesh/volmesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ def add_halfface(self, vertices, fkey=None, attr_dict=None, **kwattr):
self._halfface[fkey] = vertices
for name, value in attr.items():
self.face_attribute(fkey, name, value)
for u, v in iter_edges_from_vertices(vertices):
for u, v in pairwise(vertices + vertices[:1]):
if v not in self._plane[u]:
self._plane[u][v] = {}
self._plane[u][v][fkey] = None
Expand Down Expand Up @@ -831,7 +831,7 @@ def add_cell(self, faces, ckey=None, attr_dict=None, **kwattr):
for vertices in faces:
fkey = self.add_halfface(vertices)
vertices = self.halfface_vertices(fkey)
for u, v in iter_edges_from_vertices(vertices):
for u, v in pairwise(vertices + vertices[:1]):
if u not in self._cell[ckey]:
self._cell[ckey][u] = {}
self._plane[u][v][fkey] = ckey
Expand Down
6 changes: 3 additions & 3 deletions src/compas/geometry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@
from .curves.bezier import Bezier
from .curves.nurbs import NurbsCurve

from .polygon import Polygon
from .polyhedron import Polyhedron

from .surfaces.surface import Surface
from .surfaces.spherical import SphericalSurface
from .surfaces.cylindrical import CylindricalSurface
Expand All @@ -401,9 +404,6 @@
from .shapes.sphere import Sphere
from .shapes.torus import Torus

from .polygon import Polygon
from .polyhedron import Polyhedron

from .brep.errors import (
BrepError,
BrepInvalidError,
Expand Down
4 changes: 2 additions & 2 deletions src/compas/geometry/polyhedron.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def __or__(self, other):

@property
def vertices(self):
if not self._vertices:
if self._vertices is None:
self._vertices = []
return self._vertices

Expand All @@ -281,7 +281,7 @@ def vertices(self, vertices):

@property
def faces(self):
if not self._faces:
if self._faces is None:
self._faces = []
return self._faces

Expand Down
81 changes: 13 additions & 68 deletions src/compas/geometry/shapes/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,28 +269,6 @@ def left(self):
def top(self):
return [4, 5, 6, 7]

@property
def points(self):
point = self.frame.point
xaxis = self.frame.xaxis
yaxis = self.frame.yaxis
zaxis = self.frame.zaxis

dx = 0.5 * self.xsize
dy = 0.5 * self.ysize
dz = 0.5 * self.zsize

a = point + xaxis * -dx + yaxis * -dy + zaxis * -dz
b = point + xaxis * -dx + yaxis * +dy + zaxis * -dz
c = point + xaxis * +dx + yaxis * +dy + zaxis * -dz
d = point + xaxis * +dx + yaxis * -dy + zaxis * -dz
e = a + zaxis * self.zsize
f = d + zaxis * self.zsize
g = c + zaxis * self.zsize
h = b + zaxis * self.zsize

return [a, b, c, d, e, f, g, h]

# ==========================================================================
# Constructors
# ==========================================================================
Expand Down Expand Up @@ -474,24 +452,11 @@ def from_points(cls, points): # type: (...) -> Box
return cls.from_bounding_box(bbox)

# ==========================================================================
# Conversions
# Discretisation
# ==========================================================================

def to_vertices_and_faces(self, triangulated=False):
"""Returns a list of vertices and faces.
Parameters
----------
triangulated: bool, optional
If True, triangulate the faces.
Returns
-------
list[list[float]], list[list[int]]
A list of vertex locations, and a list of faces,
with each face defined as a list of indices into the list of vertices.
"""
def compute_vertices(self): # type: () -> list[list[float]]
"""Compute the vertices of the discrete representation of the box."""
point = self.frame.point
xaxis = self.frame.xaxis
yaxis = self.frame.yaxis
Expand All @@ -510,39 +475,19 @@ def to_vertices_and_faces(self, triangulated=False):
g = c + zaxis * self.zsize
h = b + zaxis * self.zsize

vertices = [a, b, c, d, e, f, g, h]
_faces = [self.bottom, self.front, self.right, self.back, self.left, self.top]

if triangulated:
faces = []
for a, b, c, d in _faces:
faces.append([a, b, c])
faces.append([a, c, d])
else:
faces = _faces

return vertices, faces

def to_mesh(self, triangulated=False):
"""Returns a mesh representation of the box.
Parameters
----------
triangulated: bool, optional
If True, triangulate the faces.
Returns
-------
:class:`compas.datastructures.Mesh`
"""
from compas.datastructures import Mesh
return [a, b, c, d, e, f, g, h]

vertices, faces = self.to_vertices_and_faces(triangulated=triangulated)
def compute_faces(self): # type: () -> list[list[int]]
"""Compute the faces of the discrete representation of the box."""
return [self.bottom, self.front, self.right, self.back, self.left, self.top]

mesh = Mesh.from_vertices_and_faces(vertices, faces)
def compute_edges(self): # type: () -> list[tuple[int, int]]
"""Compute the faces of the discrete representation of the box."""
return [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 7), (2, 6), (3, 5)]

return mesh
# ==========================================================================
# Conversions
# ==========================================================================

def to_brep(self):
"""Returns a BREP representation of the box.
Expand Down
79 changes: 30 additions & 49 deletions src/compas/geometry/shapes/capsule.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,40 +240,20 @@ def from_circle_and_height(cls, circle, height): # type: (...) -> Capsule
return cls(frame=circle.frame, radius=circle.radius, height=height)

# =============================================================================
# Conversions
# Discretisation
# =============================================================================

def to_vertices_and_faces(self, u=16, v=16, triangulated=False):
"""Returns a list of vertices and faces.
Note that the vertex coordinates are defined with respect to the global coordinate system,
and not to the local coordinate system of the capsule.
Parameters
----------
u : int, optional
Number of faces in the 'u' direction.
v : int, optional
Number of faces in the 'v' direction.
triangulated: bool, optional
If True, triangulate the faces.
def compute_vertices(self): # type: () -> list[list[float]]
"""Compute the vertices of the discrete representation of the capsule.
Returns
-------
list[list[float]], list[list[int]]
A list of vertex locations, and a list of faces,
with each face defined as a list of indices into the list of vertices.
Raises
------
ValueError
If the value for ``u`` or ``v`` is smaller than 3.
list[list[float]]
"""
if u < 3:
raise ValueError("The value for u should be u > 3.")
if v < 3:
raise ValueError("The value for v should be v > 3.")
u = self.resolution_u
v = self.resolution_v

if v % 2 == 1:
v += 1

Expand All @@ -300,6 +280,25 @@ def to_vertices_and_faces(self, u=16, v=16, triangulated=False):
vertices.append([0, 0, halfheight + self.radius])
vertices.append([0, 0, -halfheight - self.radius])

vertices = transform_points(vertices, self.transformation)
return vertices

def compute_faces(self): # type: () -> list[list[int]]
"""Compute the faces of the discrete representation of the capsule.
Returns
-------
list[list[int]]
"""
u = self.resolution_u
v = self.resolution_v

if v % 2 == 1:
v += 1

vertices = self._vertices

faces = []

# south pole triangle fan
Expand All @@ -323,29 +322,11 @@ def to_vertices_and_faces(self, u=16, v=16, triangulated=False):
nn = len(vertices) - 3 - (j + 1) % u
faces.append([np, nn, nc])

if triangulated:
triangles = []
for face in faces:
if len(face) == 4:
triangles.append(face[0:3])
triangles.append([face[0], face[2], face[3]])
else:
triangles.append(face)
faces = triangles

vertices = transform_points(vertices, self.transformation)

return vertices, faces

def to_brep(self):
"""Returns a BRep representation of the capsule.
return faces

Returns
-------
:class:`compas.brep.Brep`
"""
raise NotImplementedError
# =============================================================================
# Conversions
# =============================================================================

# =============================================================================
# Transformations
Expand Down
55 changes: 25 additions & 30 deletions src/compas/geometry/shapes/cone.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,29 +232,19 @@ def from_circle_and_height(cls, circle, height): # type: (...) -> Cone
frame = circle.frame
return cls(frame=frame, radius=circle.radius, height=height)

# ==========================================================================
# Conversions
# ==========================================================================
# =============================================================================
# Discretisation
# =============================================================================

def to_vertices_and_faces(self, u=16, triangulated=False):
"""Returns a list of vertices and faces.
Parameters
----------
u : int, optional
Number of faces in the "u" direction.
triangulated: bool, optional
If True, triangulate the faces.
def compute_vertices(self): # type: () -> list[list[float]]
"""Compute the vertices of the discrete representation of the cone.
Returns
-------
list[list[float]], list[list[int]]
A list of vertex locations, and a list of faces,
with each face defined as a list of indices into the list of vertices.
list[list[float]]
"""
if u < 3:
raise ValueError("The value for u should be u > 3.")
u = self.resolution_u

vertices = [[0, 0, 0]]
a = 2 * pi / u
Expand All @@ -263,7 +253,20 @@ def to_vertices_and_faces(self, u=16, triangulated=False):
x = radius * cos(i * a)
y = radius * sin(i * a)
vertices.append([x, y, 0]) # type: ignore
vertices.append([0, 0, self.height]) # type: ignore
vertices.append([0, 0, self.height])

vertices = transform_points(vertices, self.transformation)
return vertices

def compute_faces(self): # type: () -> list[list[int]]
"""Compute the faces of the discrete representation of the cone.
Returns
-------
list[list[int]]
"""
vertices = self._vertices

faces = []
first = 0
Expand All @@ -274,19 +277,11 @@ def to_vertices_and_faces(self, u=16, triangulated=False):
faces.append([last - 1, 1, last])
faces.append([1, last - 1, first])

if triangulated:
triangles = []
for face in faces:
if len(face) == 4:
triangles.append(face[0:3])
triangles.append([face[0], face[2], face[3]])
else:
triangles.append(face)
faces = triangles
return faces

vertices = transform_points(vertices, self.transformation)

return vertices, faces
# ==========================================================================
# Conversions
# ==========================================================================

def to_brep(self):
"""Returns a BRep representation of the cone.
Expand Down
Loading

0 comments on commit 40cf2c0

Please sign in to comment.