Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed


## [2.10.1] 2025-03-24

### Added

* Added `add_mesh` to `compas.datastructures.CellNetwork`.

### Changed

* Fixed logic for method `CellNetwork.cell_neighbors` from common faces search to common 3+ vertices search.

### Removed

## [2.10.0] 2025-03-03

### Added
Expand Down
45 changes: 40 additions & 5 deletions src/compas/datastructures/cell_network/cell_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,32 @@ def add_cell(self, faces, ckey=None, attr_dict=None, **kwattr):

return ckey


def add_mesh(self, input_mesh: Mesh):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have the felling this already exists but under a different name, no @romanarust ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, this does not yet exist

if input_mesh.is_manifold():
# mesh.unify_cycles()
unpacked_mesh = input_mesh.to_vertices_and_faces()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vertices, faces = ...


if self._max_vertex == -1:
vertex_diff = 0
else:
vertex_diff = self._max_vertex + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be simplified to

vertex_offset = self._max_vertex + 1


for vertex in unpacked_mesh[0]:
self.add_vertex(attr_dict = {"x": vertex[0], "y": vertex[1], "z":vertex[2]})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.add_vertex(x=vertex[0], y=vertex[1], z=vertex[2])


faces_lst = []

for face in unpacked_mesh[1]:
new_face = [vertex + vertex_diff for vertex in face]
self.add_face(new_face)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fkey = self.add_face(new_face)

faces_lst.append(self._max_face)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

faces_lst.append(fkey)


self.add_cell(faces_lst)

else:
raise ValueError("Mesh is not manifold to be added as a cell")

# --------------------------------------------------------------------------
# Modifiers
# --------------------------------------------------------------------------
Expand Down Expand Up @@ -4033,7 +4059,7 @@ def cell_face_neighbors(self, cell, face):
return nbrs

def cell_neighbors(self, cell):
"""Find the neighbors of a given cell.
"""Find the neighbors of a given cell based on common vertices.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this should be a different function because it does something else than what was intended by the original one...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I was even thinking about proposing one more datastructure like Mesh Network. Something more practice oriented, because that's not common to have a building represented as masses or adjacent rooms only. Moreover some parts in a model can have clashes, or be adjacent on a face to face level only, or can have common vertices.
So briefly the initial functionality:

  • analyzing meshes adjacency (including collision etc)
  • storing some metadata on a mesh level (attr dict but for meshes)
  • mesh network to graph conversion (each node is a mesh centroid, edge could have some metadata about type of adjacency like collision or face adjacency)
  • graph algorithms
  • integration with compas viewer

Basically all of these could be added to CellNetwork as well, if it has no clashes with initial idea of a CellNetwork

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what you describe is already under development here
https://github.com/BlockResearchGroup/compas_model

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this should be a different function because it does something else than what was intended by the original one...

Agree. Additionally, heavy processing tasks like clash detection shouldn't be tied to the CellNetwork, as they fall under mesh processing. Identifying nearby meshes for clash detection (which I assume is the goal of this function) would be better handled with something like KDtree for spatial awareness.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of this function is to convert meshes to a topologic spatial graph. Clashes were just a thing to consider, the general assumption is that the model is relatively clean with required openings etc. But now I see that maybe CellNetwork should remain more lightweight, especially considering the compas_model developments. I'll have a look at compas_model and investigate how it could be used for this task


Parameters
----------
Expand All @@ -4049,11 +4075,20 @@ def cell_neighbors(self, cell):
--------
:meth:`cell_face_neighbors`
"""

cells_vertices = {}
for cell_ in self.cells():
vertices_of_a_cell = []
for vertex in self.cell_vertices(cell_):
vertices_of_a_cell.append(tuple(self.vertex_coordinates(vertex)))

cells_vertices[cell_] = set(vertices_of_a_cell)

nbrs = []
for face in self.cell_faces(cell):
for nbr in self.face_cells(face):
if nbr != cell:
nbrs.append(nbr)
for key in cells_vertices.keys():
if key != cell and len((cells_vertices[cell] & cells_vertices[key])) > 2:
nbrs.append(key)

return list(set(nbrs))

def is_cell_on_boundary(self, cell):
Expand Down
Loading
Loading