-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #887 from compas-dev/assembly
Basic Assembly data structure
- Loading branch information
Showing
11 changed files
with
516 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
********** | ||
Assemblies | ||
********** | ||
|
||
.. rst-class:: lead | ||
|
||
The :class:`Assembly` data structure provides functionality for modelling and managing | ||
the connections between the individual components of an ... assembly. | ||
Each component is either a part defined by geometrical objects, or another assembly. | ||
|
||
|
||
Basic Usage | ||
=========== | ||
|
||
.. code-block:: python | ||
from compas.datastructures import Part | ||
from compas.datastructures import Assembly | ||
from compas.geometry import Box | ||
assembly = Assembly() | ||
Find Parts | ||
========== | ||
|
||
.. code-block:: python | ||
pass | ||
Access Data | ||
=========== | ||
|
||
.. code-block:: python | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from math import radians | ||
|
||
from compas.datastructures import Assembly | ||
from compas.datastructures import Part | ||
from compas.geometry import Box | ||
from compas.geometry import Cylinder | ||
from compas.geometry import Circle | ||
from compas.geometry import Plane | ||
from compas.geometry import Translation | ||
from compas.geometry import Rotation | ||
from compas.geometry import Frame | ||
|
||
from compas_view2.app import App | ||
|
||
assembly = Assembly() | ||
|
||
a = Part(name='A', | ||
geometry=Box.from_width_height_depth(1, 1, 1)) | ||
|
||
b = Part(name='B', | ||
frame=Frame([0, 0, 1], [1, 0, 0], [0, 1, 0]), | ||
shape=Box.from_width_height_depth(1, 1, 1), | ||
features=[(Cylinder(Circle(Plane.worldXY(), 0.2), 1.0), 'difference')]) | ||
|
||
b.transform(Rotation.from_axis_and_angle([0, 0, 1], radians(45))) | ||
b.transform(Translation.from_vector([0, 0, 1])) | ||
|
||
assembly.add_part(a) | ||
assembly.add_part(b) | ||
|
||
assembly.add_connection(a, b) | ||
|
||
viewer = App() | ||
viewer.add(b.geometry) | ||
viewer.add(b.frame) | ||
viewer.show() |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from __future__ import print_function | ||
from __future__ import absolute_import | ||
from __future__ import division | ||
|
||
from .assembly import Assembly # noqa: F401 F403 | ||
from .part import Part # noqa: F401 F403 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
from __future__ import print_function | ||
from __future__ import absolute_import | ||
from __future__ import division | ||
|
||
from ..datastructure import Datastructure | ||
from ..graph import Graph | ||
from .exceptions import AssemblyError | ||
|
||
|
||
class Assembly(Datastructure): | ||
"""A data structure for managing the connections between different parts of an assembly. | ||
Attributes | ||
---------- | ||
attributes: dict | ||
General attributes of the assembly that will be included in the data dict. | ||
graph: :class:`compas.datastructures.Graph` | ||
The graph that is used under the hood to store the parts and their connections. | ||
""" | ||
|
||
@property | ||
def DATASCHEMA(self): | ||
import schema | ||
return schema.Schema({ | ||
"attributes": dict, | ||
"graph": Graph, | ||
}) | ||
|
||
@property | ||
def JSONSCHEMANAME(self): | ||
return 'assembly' | ||
|
||
def __init__(self, name=None, **kwargs): | ||
super(Assembly, self).__init__() | ||
self.attributes = {'name': name or 'Assembly'} | ||
self.attributes.update(kwargs) | ||
self.graph = Graph() | ||
self._parts = {} | ||
|
||
def __str__(self): | ||
tpl = "<Assembly with {} parts and {} connections>" | ||
return tpl.format(self.graph.number_of_nodes(), self.graph.number_of_edges()) | ||
|
||
@property | ||
def name(self): | ||
"""str : The name of the assembly.""" | ||
return self.attributes.get('name') or self.__class__.__name__ | ||
|
||
@name.setter | ||
def name(self, value): | ||
self.attributes['name'] = value | ||
|
||
@property | ||
def data(self): | ||
"""dict : A data dict representing the assembly data structure for serialization. | ||
""" | ||
data = { | ||
'attributes': self.attributes, | ||
'graph': self.graph.data, | ||
} | ||
return data | ||
|
||
@data.setter | ||
def data(self, data): | ||
self.attributes.update(data['attributes'] or {}) | ||
self.graph.data = data['graph'] | ||
|
||
def add_part(self, part, key=None, **kwargs): | ||
"""Add a part to the assembly. | ||
Parameters | ||
---------- | ||
part: :class:`compas.datastructures.Part` | ||
The part to add. | ||
key: int or str, optional | ||
The identifier of the part in the assembly. | ||
Note that the key is unique only in the context of the current assembly. | ||
Nested assemblies may have the same ``key`` value for one of their parts. | ||
Default is ``None`` in which case the key will be automatically assigned integer value. | ||
kwargs: dict | ||
Additional named parameters collected in a dict. | ||
Returns | ||
------- | ||
int or str | ||
The identifier of the part in the current assembly graph. | ||
""" | ||
if part.guid in self._parts: | ||
raise AssemblyError('Part already added to the assembly') | ||
key = self.graph.add_node(key=key, part=part, **kwargs) | ||
part.key = key | ||
self._parts[part.guid] = part | ||
return key | ||
|
||
def add_connection(self, a, b, **kwargs): | ||
"""Add a connection between two parts. | ||
Parameters | ||
---------- | ||
a: :class:`compas.datastructures.Part` | ||
The "from" part. | ||
b: :class:`compas.datastructures.Part` | ||
The "to" part. | ||
kwargs: dict | ||
Additional named parameters collected in a dict. | ||
Returns | ||
------- | ||
tuple of str or int | ||
The tuple of node identifiers that identifies the connection. | ||
Raises | ||
------ | ||
:class:`AssemblyError` | ||
If ``a`` and/or ``b`` are not in the assembly. | ||
""" | ||
if a.key is None or b.key is None: | ||
raise AssemblyError('Both parts have to be added to the assembly before a connection can be created.') | ||
if not self.graph.has_node(a.key) or not self.graph.has_node(b.key): | ||
raise AssemblyError('Both parts have to be added to the assembly before a connection can be created.') | ||
return self.graph.add_edge(a.key, b.key, **kwargs) | ||
|
||
def parts(self): | ||
"""The parts of the assembly. | ||
Yields | ||
------ | ||
:class:`compas.datastructures.Part` | ||
The individual parts of the assembly. | ||
""" | ||
for node in self.graph.nodes(): | ||
yield self.graph.node_attribute(node, 'part') | ||
|
||
def connections(self, data=False): | ||
"""Iterate over the connections between the parts. | ||
Parameters | ||
---------- | ||
data : bool, optional | ||
If ``True``, yield both the identifier and the attributes of each connection. | ||
Yields | ||
------ | ||
tuple | ||
The next connection identifier (u, v), if ``data`` is ``False``. | ||
Otherwise, the next connector identifier and its attributes as a ((u, v), attr) tuple. | ||
""" | ||
return self.graph.edges(data) | ||
|
||
def find(self, guid): | ||
"""Find a part in the assembly by its GUID. | ||
Parameters | ||
---------- | ||
guid: str | ||
A globally unique identifier. | ||
This identifier is automatically assigned when parts are created. | ||
Returns | ||
------- | ||
:class:`compas.datastructures.Part` or None | ||
The identified part, if any. | ||
""" | ||
return self._parts.get(guid) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
class AssemblyError(Exception): | ||
pass | ||
|
||
|
||
class FrameError(Exception): | ||
pass | ||
|
||
|
||
class FeatureError(Exception): | ||
pass |
Oops, something went wrong.