Skip to content

Commit

Permalink
Merge pull request #56 from BlockResearchGroup/new_feature_elements_a…
Browse files Browse the repository at this point in the history
…nd_interactions

Elements and Interactions
  • Loading branch information
tomvanmele authored Jan 21, 2025
2 parents adc7001 + 2950874 commit 5310b89
Show file tree
Hide file tree
Showing 18 changed files with 996 additions and 22 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `compas_model.models.bvh.ElementBVH`.
* Added `compas_model.models.bvh.ElementAABBNode`.
* Added `compas_model.models.bvh.ElementOBBNode`.
* Added `compas_model.elements.BeamElement`.
* Added `compas_model.elements.ColumnElement`.
* Added `compas_model.elements.PlateElement`.
* Added `compas_model.models.Model.collisions` iterator.
* Added `compas_model.models.graph.InteractionGraph.clear_edges`.

Expand Down
1 change: 1 addition & 0 deletions data/frame.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Model::Line::Segments": [{"dtype": "compas.geometry/Line", "data": {"start": [-3000.0, -3000.0, 0.0], "end": [-3000.0, -3000.0, 3800.0]}, "guid": "fb541808-f597-4887-ad14-dfc9f6986049"}, {"dtype": "compas.geometry/Line", "data": {"start": [-3000.0, 3000.0, 0.0], "end": [-3000.0, 3000.0, 3800.0]}, "guid": "af2c15a8-358e-4a76-9929-09220abb5a37"}, {"dtype": "compas.geometry/Line", "data": {"start": [3000.0, 3000.0, 0.0], "end": [3000.0, 3000.0, 3800.0]}, "guid": "ad7b8d31-4b4c-460f-ba88-015cdbece5ef"}, {"dtype": "compas.geometry/Line", "data": {"start": [3000.0, -3000.0, 0.0], "end": [3000.0, -3000.0, 3800.0]}, "guid": "7984e9ad-322e-43de-a3bf-0b85e71520c3"}, {"dtype": "compas.geometry/Line", "data": {"start": [-3000.0, -3000.0, 3800.0], "end": [-3000.0, 3000.0, 3800.0]}, "guid": "54127e6c-3e59-486f-bdb1-104e3d640608"}, {"dtype": "compas.geometry/Line", "data": {"start": [3000.0, 3000.0, 3800.0], "end": [3000.0, -3000.0, 3800.0]}, "guid": "1c9712d8-c7eb-4b8d-8536-9f6150a8ee61"}, {"dtype": "compas.geometry/Line", "data": {"start": [-3000.0, 3000.0, 3800.0], "end": [3000.0, 3000.0, 3800.0]}, "guid": "ec1ef974-8366-4350-a998-87a0f6f1cd7a"}, {"dtype": "compas.geometry/Line", "data": {"start": [3000.0, -3000.0, 3800.0], "end": [-3000.0, -3000.0, 3800.0]}, "guid": "b59e5ff5-fe5b-42e8-945c-8c6b768617db"}], "Model::Mesh::Floor": [{"dtype": "compas.datastructures/Mesh", "data": {"attributes": {}, "default_vertex_attributes": {"x": 0.0, "y": 0.0, "z": 0.0}, "default_edge_attributes": {}, "default_face_attributes": {}, "vertex": {"0": {"x": -3000.0, "y": -3000.0, "z": 3800.0}, "1": {"x": -3000.0, "y": 3000.0, "z": 3800.0}, "2": {"x": 3000.0, "y": 3000.0, "z": 3800.0}, "3": {"x": 3000.0, "y": -3000.0, "z": 3800.0}}, "face": {"0": [0, 1, 2, 3]}, "facedata": {"0": {}}, "edgedata": {}, "max_vertex": 3, "max_face": 0}, "guid": "0334f95a-f3fa-4e72-9d43-07d5da2b19ee"}]}
26 changes: 26 additions & 0 deletions docs/examples/elements/beam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from compas.datastructures import Mesh
from compas.geometry import Rotation
from compas.geometry import Translation
from compas_model.elements import BeamElement
from compas_model.models import Model
from compas_viewer import Viewer

# Create an element.
beam = BeamElement(0.2, 0.3, 3)

# Element transformation can be set or modified as an attribute.
R = Rotation.from_axis_and_angle([0, 1, 0], 3.14 / 2, beam.center_line.midpoint)
T = Translation.from_vector([0, 0, 1.5])
beam.transformation = T * R

# But the transformation is applied when beam.modelgeometry is computed.
model = Model()
model.add_element(beam)
mesh_in_element_space: Mesh = beam.elementgeometry
mesh_in_model_space: Mesh = beam.modelgeometry

# Vizualize.
viewer = Viewer()
viewer.scene.add(mesh_in_element_space)
viewer.scene.add(mesh_in_model_space)
viewer.show()
27 changes: 27 additions & 0 deletions docs/examples/elements/column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from compas.geometry import Translation
from compas_model.elements import ColumnElement
from compas_model.models import Model
from compas_viewer import Viewer

# Create an element.
column = ColumnElement(0.2, 0.2, 3)

# Element transformation can be set or modified as an attribute.
vectors: list[list[float]] = [
[-3, -3, 0],
[-3, 3, 0],
[3, 3, 0],
[3, -3, 0],
]

model = Model()
for v in vectors:
column_copy = column.copy()
column_copy.transformation = Translation.from_vector(v)
model.add_element(column_copy)

# Vizualize.
viewer = Viewer()
for element in model.elements():
viewer.scene.add(element.modelgeometry)
viewer.show()
18 changes: 18 additions & 0 deletions docs/examples/elements/plate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from compas.geometry import Polygon
from compas_model.elements import PlateElement
from compas_viewer import Viewer

# Create an element.
points: list[list[float]] = [
[-3, -3, 0],
[-3, 3, 0],
[3, 3, 0],
[3, -3, 0],
]
polygon: Polygon = Polygon(points)
plate = PlateElement(polygon=polygon, thickness=0.2)

# Vizualize.
viewer = Viewer()
viewer.scene.add(plate.elementgeometry)
viewer.show()
30 changes: 30 additions & 0 deletions docs/examples/interactions/000_boolean_modifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from compas.geometry import Rotation
from compas.geometry import Translation
from compas_model.elements import BeamElement
from compas_model.interactions import BooleanModifier
from compas_model.models import Model
from compas_viewer import Viewer

# Create an element.
beam0: BeamElement = BeamElement(0.2, 0.3, 3, name="beam0")
beam1: BeamElement = beam0.copy()
beam1.name = "beam1"

# Element transformation can be set or modified as an attribute.
R = Rotation.from_axis_and_angle([0, 1, 0], 3.14 / 2, beam0.center_line.midpoint)
T = Translation.from_vector([0, 0, 1.5])
beam0.transformation = T * R # Rotate then translate

# But the transformation is applied when beam.modelgeometry is computed.
model = Model()
model.add_element(beam0)
model.add_element(beam1)

model.add_interaction(beam1, beam0)
model.add_modifier(beam1, beam0, BooleanModifier)

# Vizualize.
viewer = Viewer()
for element in model.elements():
viewer.scene.add(element.modelgeometry, hide_coplanaredges=True)
viewer.show()
30 changes: 30 additions & 0 deletions docs/examples/interactions/001_slicer_modifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from compas.geometry import Rotation
from compas.geometry import Translation
from compas_model.elements import BeamElement
from compas_model.interactions import SlicerModifier
from compas_model.models import Model
from compas_viewer import Viewer

# Create an element.
beam0: BeamElement = BeamElement(0.2, 0.3, 3, name="beam0")
beam1: BeamElement = beam0.copy()
beam1.name = "beam1"

# Element transformation can be set or modified as an attribute.
R = Rotation.from_axis_and_angle([0, 1, 0], 3.14 / 2, beam0.center_line.midpoint)
T = Translation.from_vector([0, 0, 1.5])
beam0.transformation = T * R # Rotate then translate

# But the transformation is applied when beam.modelgeometry is computed.
model = Model()
model.add_element(beam0)
model.add_element(beam1)

model.add_interaction(beam0, beam1)
model.add_modifier(beam0, beam1, SlicerModifier)

# Vizualize.
viewer = Viewer()
for element in model.elements():
viewer.scene.add(element.modelgeometry, hide_coplanaredges=True)
viewer.show()
102 changes: 102 additions & 0 deletions docs/examples/interactions/002_frame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from pathlib import Path

from compas import json_dump
from compas import json_load
from compas.datastructures import Mesh
from compas.geometry import Frame
from compas.geometry import Line
from compas.geometry import Point
from compas.geometry import Transformation
from compas.geometry import Translation
from compas.geometry import Vector
from compas.tolerance import TOL
from compas_model.elements import BeamElement
from compas_model.elements import ColumnElement
from compas_model.models import Model
from compas_viewer import Viewer
from compas_viewer.config import Config

# =============================================================================
# Create Geometry
# =============================================================================
points = [
Point(-3000, -3000, 0),
Point(-3000, 3000, 0),
Point(3000, 3000, 0),
Point(3000, -3000, 0),
Point(-3000, -3000, 3800),
Point(-3000, 3000, 3800),
Point(3000, 3000, 3800),
Point(3000, -3000, 3800),
]

lines = [
Line(points[0], points[4]),
Line(points[1], points[5]),
Line(points[2], points[6]),
Line(points[3], points[7]),
Line(points[4], points[5]),
Line(points[6], points[7]),
Line(points[5], points[6]),
Line(points[7], points[4]),
]

mesh = Mesh.from_vertices_and_faces(points[4:], [[0, 1, 2, 3]])

# =============================================================================
# Serialize Geometry into a JSON file
# =============================================================================
model_input = {"Model::Line::Segments": lines, "Model::Mesh::Floor": [mesh]}
json_dump(model_input, Path("data/frame.json"))


# =============================================================================
# Load Geometry from JSON and Create Model
# =============================================================================
rhino_geometry = json_load(Path("data/frame.json"))
lines = rhino_geometry["Model::Line::Segments"]

model = Model()

# Add columns
columns = []
for i in range(4):
column = ColumnElement(300, 300, lines[i].length)
column.transformation = Transformation.from_frame_to_frame(Frame.worldXY(), Frame(lines[i].start))
model.add_element(column)
columns.append(column)

# Add beams
beams = []
for i in range(4, len(lines)):
beam = BeamElement(width=300, depth=700, length=lines[i].length)
point = lines[i].start
xaxis = Vector.Zaxis().cross(lines[i].vector)
yaxis = Vector.Zaxis()
target_frame = Frame(point, xaxis, yaxis)
X = Transformation.from_frame_to_frame(Frame.worldXY(), target_frame)
T = Translation.from_vector([0, beam.depth * -0.5, 0])
beam.transformation = X * T
beam.extend(150)
model.add_element(beam)
beams.append(beam)

# Add interactions and modifiers
for column in columns:
for beam in beams:
model.add_interaction(column, beam)
model.add_modifier(column, beam) # column -> cuts -> beam

# =============================================================================
# Visualize Final Model
# =============================================================================
config = Config()
config.camera.target = [0, 0, 100]
config.camera.position = [10000, -10000, 10000]
config.camera.near = 10
config.camera.far = 100000

viewer = Viewer(config=config)
for element in model.elements():
viewer.scene.add(element.modelgeometry, hide_coplanaredges=True)
viewer.show()
12 changes: 12 additions & 0 deletions src/compas_model/elements/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
from .element import reset_computed
from .element import Element
from .element import Feature
from .beam import BeamElement
from .beam import BeamFeature
from .column import ColumnElement
from .column import ColumnFeature
from .plate import PlateElement
from .plate import PlateFeature


__all__ = [
"reset_computed",
"Element",
"Feature",
"BeamElement",
"BeamFeature",
"ColumnElement",
"ColumnFeature",
"PlateElement",
"PlateFeature",
]
Loading

0 comments on commit 5310b89

Please sign in to comment.