Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `Element.compute_elementgeometry()`.
* Added `Element.compute_modelgeometry()` to replace `Element.compute_geometry()`.
* Added `Element.compute_modeltransformation()` to replace `Element.compute_worldtransformation()`.
* Added `Element.is_dirty`.

### Changed

Expand Down
4 changes: 2 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
API Reference
********************************************************************************


.. toctree::
:maxdepth: 1
:titlesonly:

api/compas_model.algorithms
api/compas_model.elements
api/compas_model.interactions
api/compas_model.materials
api/compas_model.models
api/compas_model.notebook
api/compas_model.scene
api/compas_model.scene
14 changes: 0 additions & 14 deletions docs/api/compas_model.algorithms.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/api/compas_model.models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ Classes

ElementNode
ElementTree
GroupNode
InteractionGraph
Model
BlockModel
12 changes: 2 additions & 10 deletions docs/api/compas_model.notebook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,12 @@ compas_model.notebook

.. currentmodule:: compas_model.notebook


Classes
=======

.. autosummary::
:toctree: generated/
:nosignatures:

scene.ThreeBlockObject


Functions
=========

.. autosummary::
:toctree: generated/
:nosignatures:
ThreeBlockObject
ThreeModelObject
5 changes: 3 additions & 2 deletions docs/api/compas_model.scene.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ compas_model.scene

.. currentmodule:: compas_model.scene


Classes
=======

.. autosummary::
:toctree: generated/
:nosignatures:

ElementObject
ElementObject
BlockObject
ModelObject
4 changes: 2 additions & 2 deletions docs/examples/dem/000_stack.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ As a result, the stack requires equilibriating "glue" forces (in red) at those i
Code
====

.. literalinclude:: 100_stack.py
:language: python
.. .. literalinclude:: 100_stack.py
.. :language: python
3 changes: 3 additions & 0 deletions src/compas_model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@
"compas_model.rhino",
"compas_model.rhino.scene",
"compas_model.notebook.scene",
"compas_model.interactions",
"compas_model.materials",
"compas_model.models",
]
5 changes: 2 additions & 3 deletions src/compas_model/algorithms/interfaces.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
from math import fabs

from shapely.geometry import Polygon as ShapelyPolygon

from compas.datastructures import Mesh
from compas.geometry import Frame
from compas.geometry import Plane
from compas.geometry import Polygon
from compas.geometry import Transformation
from compas.geometry import Vector
from compas.geometry import bestfit_frame_numpy
from compas.geometry import centroid_polygon
from compas.geometry import is_colinear
from compas.geometry import is_coplanar
from compas.geometry import is_parallel_vector_vector
from compas.geometry import transform_points
from compas.itertools import window
from shapely.geometry import Polygon as ShapelyPolygon

from compas_model.elements import BlockGeometry
from compas_model.interactions import ContactInterface
from compas_model.models import Model
Expand Down
8 changes: 6 additions & 2 deletions src/compas_model/algorithms/overlaps.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from compas.geometry import Brep
from compas.tolerance import TOL
from compas_occ.brep import OCCBrepFace as BrepFace

from compas_model.interactions import ContactInterface
from compas_model.models import Model

Expand Down Expand Up @@ -104,6 +102,12 @@ def brep_brep_overlaps(
This means that if the

"""

try:
from compas_occ.brep import OCCBrepFace as BrepFace
except ImportError:
raise ImportError("compas_occ is required for this functionality. Please install it via conda.")

faces_A, faces_B = A.overlap(B, deflection=deflection, tolerance=tolerance)
faces_A: list[BrepFace]
faces_B: list[BrepFace]
Expand Down
12 changes: 8 additions & 4 deletions src/compas_model/analysis/cra.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
from compas_assembly.datastructures import Assembly
from compas_assembly.datastructures import Block
from compas_cra.equilibrium import cra_penalty_solve as _cra_penalty_solve

from compas_model.interactions import ContactInterface
from compas_model.models import Model

Expand All @@ -15,6 +11,14 @@ def cra_penalty_solve(
verbose: bool = False,
timer: bool = False,
):
try:
from compas_cra.equilibrium import cra_penalty_solve as _cra_penalty_solve

from compas_assembly.datastructures import Assembly
from compas_assembly.datastructures import Block
except ImportError:
raise ImportError("compas_cra, compas_assembly is required for this functionality. Please install it via conda.")

assembly = Assembly()

element_block = {}
Expand Down
1 change: 0 additions & 1 deletion src/compas_model/elements/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from compas.geometry import oriented_bounding_box
from compas.geometry import volume_polyhedron
from compas.geometry.brep.brep import Brep

from compas_model.elements import Element
from compas_model.elements import Feature

Expand Down
37 changes: 35 additions & 2 deletions src/compas_model/elements/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from compas.geometry import Frame
from compas.geometry import Shape
from compas.geometry import Transformation

from compas_model.materials import Material

if TYPE_CHECKING:
Expand Down Expand Up @@ -93,6 +92,8 @@ class Element(Data):
Scaling factor to inflate the AABB with.
inflate_obb : float
Scaling factor to inflate the OBB with.
is_dirty : bool
Flag to indicate that modelgeometry has to be recomputed.

"""

Expand Down Expand Up @@ -141,6 +142,8 @@ def __init__(
self.inflate_aabb = 0.0
self.inflate_obb = 0.0

self._is_dirty = True

# this is not entirely correct
def __repr__(self) -> str:
return f"Element(frame={self.frame!r}, name={self.name})"
Expand Down Expand Up @@ -178,6 +181,19 @@ def parent(self) -> "ElementNode":
def features(self) -> list[Feature]:
return self._features

@property
def is_dirty(self):
return self._is_dirty

@is_dirty.setter
def is_dirty(self, value):
self._is_dirty = value

if value:
elements = list(self.model.elements())
for neighbor in self.model.graph.neighbors_out(self.graphnode):
elements[neighbor].is_dirty = value

# ==========================================================================
# Computed attributes
# ==========================================================================
Expand Down Expand Up @@ -291,7 +307,24 @@ def compute_modelgeometry(self) -> Union[Brep, Mesh]:
:class:`compas.datastructures.Mesh` | :class:`compas.geometry.Brep`

"""
raise NotImplementedError
graph = self.model.graph
elements = list(self.model.elements())
xform = self.modeltransformation
modelgeometry = self.elementgeometry.transformed(xform)

for neighbor in graph.neighbors_in(self.graphnode):
for interaction in graph.edge_interactions((neighbor, self.graphnode)): # graph.edge_modififers()
# Interaction types: Modifier, Collision, Interface
if hasattr(interaction, "modify"): # Modifier
modelgeometry = interaction.modify(modelgeometry, elements[neighbor].modelgeometry)
elif hasattr(interaction, "collide"): # Collision:
modelgeometry = interaction.collide(modelgeometry, elements[neighbor].modelgeometry)
elif hasattr(interaction, "overlap"): # Interface:
modelgeometry = interaction.touch(modelgeometry, elements[neighbor].modelgeometry)

self.is_dirty = False

return modelgeometry

def compute_aabb(self) -> Box:
"""Computes the Axis Aligned Bounding Box (AABB) of the geometry of the element.
Expand Down
1 change: 0 additions & 1 deletion src/compas_model/elements/plate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from compas.geometry import bounding_box
from compas.geometry import oriented_bounding_box
from compas.itertools import pairwise

from compas_model.elements import Element
from compas_model.elements import Feature

Expand Down
7 changes: 5 additions & 2 deletions src/compas_model/models/blockmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from compas.geometry import Brep
from compas.tolerance import Tolerance
from compas_occ.brep import OCCBrepFace as BrepFace

from compas_model.algorithms.nnbrs import find_nearest_neighbours
from compas_model.elements import Element
from compas_model.interactions import ContactInterface
Expand All @@ -22,6 +20,11 @@ def compute_overlaps(self, deflection=None, tolerance=1, max_distance=50, min_ar
pass

def compute_interfaces(self, deflection=None, tolerance=1, max_distance=50, min_area=0, nmax=10):
try:
from compas_occ.brep import OCCBrepFace as BrepFace
except ImportError:
raise ImportError("compas_occ is required for this functionality. Please install it via conda.")

deflection = deflection or Tolerance().lineardeflection

node_index = {node: index for index, node in enumerate(self.graph.nodes())}
Expand Down
1 change: 0 additions & 1 deletion src/compas_model/models/elementnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Optional

from compas.datastructures import TreeNode

from compas_model.elements import Element

if TYPE_CHECKING:
Expand Down
1 change: 0 additions & 1 deletion src/compas_model/models/elementtree.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Optional

from compas.datastructures import Tree

from compas_model.elements import Element

from .elementnode import ElementNode
Expand Down
1 change: 0 additions & 1 deletion src/compas_model/models/interactiongraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Optional

from compas.datastructures import Graph

from compas_model.elements import Element # noqa: F401
from compas_model.interactions import Interaction # noqa: F401

Expand Down
9 changes: 8 additions & 1 deletion src/compas_model/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from compas.datastructures import Datastructure
from compas.geometry import Frame
from compas.geometry import Transformation

from compas_model.elements import Element
from compas_model.interactions import Interaction
from compas_model.materials import Material
Expand Down Expand Up @@ -380,6 +379,8 @@ def add_interaction(self, a: Element, b: Element, interaction: Optional[Interact
interactions.append(interaction)
self.graph.edge_attribute(edge, name="interactions", value=interactions)

self._guid_element[str(b.guid)].is_dirty = True

return edge

def remove_element(self, element: Element) -> None:
Expand All @@ -398,6 +399,9 @@ def remove_element(self, element: Element) -> None:
guid = str(element.guid)
if guid not in self._guid_element:
raise Exception("Element not in the model.")

self._guid_element[guid].is_dirty = True

del self._guid_element[guid]

self.graph.delete_node(element.graphnode)
Expand All @@ -420,6 +424,9 @@ def remove_interaction(self, a: Element, b: Element, interaction: Optional[Inter
if interaction:
raise NotImplementedError

elements = list(self.elements())
elements[b.graphnode]._is_dirty = True

edge = a.graphnode, b.graphnode
if self.graph.has_edge(edge):
self.graph.delete_edge(edge)
Expand Down
6 changes: 6 additions & 0 deletions src/compas_model/notebook/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .scene import ThreeBlockObject, ThreeModelObject

__all__ = [
"ThreeBlockObject",
"ThreeModelObject",
]
6 changes: 0 additions & 6 deletions src/compas_model/notebook/scene/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,3 @@ def register_scene_objects():
register(Model, ThreeModelObject, context="Notebook")

# print("PyThreeJS Model elements registered.")


__all__ = [
"ThreeBlockObject",
"ThreeModelObjec",
]
8 changes: 4 additions & 4 deletions src/compas_model/notebook/scene/blockobject.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import compas.datastructures # noqa: F401
import compas.geometry # noqa: F401
import numpy
import pythreejs as three
from compas.geometry import Polygon
from compas.geometry import earclip_polygon
from compas_notebook.scene import ThreeSceneObject

import compas.datastructures # noqa: F401
import compas.geometry # noqa: F401
from compas.geometry import Polygon
from compas.geometry import earclip_polygon
from compas_model.scene import BlockObject


Expand Down
4 changes: 2 additions & 2 deletions src/compas_model/notebook/scene/modelobject.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import compas.datastructures # noqa: F401
import compas.geometry # noqa: F401
from compas_notebook.scene import ThreeSceneObject

import compas.datastructures # noqa: F401
import compas.geometry # noqa: F401
from compas_model.scene import ElementObject
from compas_model.scene import ModelObject

Expand Down
Loading
Loading