Ejemplo n.º 1
0
def test_astar_shortest_path_disconnected():
    n = Network()
    a = n.add_node(x=1, y=0, z=0)
    b = n.add_node(x=2, y=0, z=0)
    c = n.add_node(x=3, y=0, z=0)
    n.add_edge(a, b)
    path = astar_shortest_path(n, a, c)
    assert path is None
Ejemplo n.º 2
0
def test_astar_shortest_path_cycle():
    n = Network()
    a = n.add_node(x=1, y=0, z=0)
    b = n.add_node(x=2, y=0, z=0)
    c = n.add_node(x=3, y=0, z=0)
    d = n.add_node(x=4, y=0, z=0)
    e = n.add_node(x=3.5, y=5, z=0)
    n.add_edge(a, b)
    n.add_edge(a, e)
    n.add_edge(b, c)
    n.add_edge(c, d)
    n.add_edge(e, d)
    path = astar_shortest_path(n, a, d)
    assert path == [a, b, c, d]
Ejemplo n.º 3
0
def meshes_to_network(meshes):
    network = Network()

    network.update_default_node_attributes(mesh=None, vkey=None, fkey=None)
    network.update_default_edge_attributes(mesh=None, fkey=None)

    for i, mesh in enumerate(meshes):
        for vkey in mesh.vertices():
            x, y, z = mesh.vertex_coordinates(vkey)
            network.add_node(x=x, y=y, z=z, mesh=i, vkey=vkey)
        for u, v in mesh.edges():
            u1 = next(network.nodes_where({"vkey": u, "mesh": i}))
            v1 = next(network.nodes_where({"vkey": v, "mesh": i}))
            network.add_edge(u1, v1, mesh=i)

    return network
Ejemplo n.º 4
0
def test_astar_shortest_path():
    n = Network()
    a = n.add_node(x=1, y=2, z=0)
    b = n.add_node(x=3, y=1, z=0)
    n.add_edge(a, b)
    path = astar_shortest_path(n, a, b)
    assert path == [a, b]
Ejemplo n.º 5
0
def test_json_network():
    before = Network()
    a = before.add_node()
    b = before.add_node()
    before.add_edge(a, b)
    after = compas.json_loads(compas.json_dumps(before))
    assert before.dtype == after.dtype
    assert before.attributes == after.attributes
    assert all(before.has_node(node) for node in after.nodes())
    assert all(after.has_node(node) for node in before.nodes())
    assert all(before.has_edge(*edge) for edge in after.edges())
    assert all(after.has_edge(*edge) for edge in before.edges())
Ejemplo n.º 6
0
from itertools import combinations

from compas.datastructures import Network
from compas.utilities import linspace, meshgrid
from compas_rhino.artists import NetworkArtist

X, Y = meshgrid(linspace(0, 10, 10), linspace(0, 5, 5))

points = []
for z in linspace(0, 3, 3):
    for xs, ys in zip(X, Y):
        for x, y in zip(xs, ys):
            points.append([x, y, z])

network = Network()

for point in points:
    network.add_node(x=point[0], y=point[1], z=point[2])

for a, b in combinations(network.nodes(), 2):
    if network.node_attribute(a, 'z') != network.node_attribute(b, 'z'):
        network.add_edge(a, b)

artist = NetworkArtist(network, layer="ITA20::Network")
artist.clear_layer()
artist.draw_nodes()
artist.draw_edges()
Ejemplo n.º 7
0

# clear the Rhino model

compas_rhino.clear()

# create a network

network = Network()

network.update_dna(is_anchor=False)
network.update_dna(rx=0, ry=0, rz=0)
network.update_dna(px=0, py=0, pz=0)
network.update_dea(f=0, q=1)

a = network.add_node(x=0, y=0, z=0, is_anchor=True)
b = network.add_node(x=10, y=0, z=10, is_anchor=True)
c = network.add_node(x=10, y=10, z=0, is_anchor=True)
d = network.add_node(x=0, y=10, z=10, is_anchor=True)

e = network.add_node(x=5, y=5, z=0)

network.add_edge(a, e, q=random.randint(1, 10))
network.add_edge(b, e, q=random.randint(1, 10))
network.add_edge(c, e, q=random.randint(1, 10))
network.add_edge(d, e, q=random.randint(1, 10))

# numerical data

n = network.number_of_nodes()
Ejemplo n.º 8
0
import random

from compas_rhino.artists import NetworkArtist
from compas.datastructures import Network

network = Network()

last_node = None
for i in range(12):
    node = network.add_node(x=i // 3, y=i % 3, z=0)
    network.node_attribute(node, 'weight', random.choice(range(20)))

    if last_node:
        network.add_edge(node, i - 1)
    last_node = node

print(network.summary())
print(network.to_data())

text = {
    node: network.node_attribute(node, 'weight')
    for node in network.nodes()
}

artist = NetworkArtist(network, layer='network')
artist.clear_layer()
artist.draw_nodelabels(text)
artist.draw()
artist.redraw()
Ejemplo n.º 9
0
def test_add_node():
    network = Network()
    assert network.add_node(1) == 1
    assert network.add_node('1', x=0, y=0, z=0) == '1'
    assert network.add_node(2) == 2
    assert network.add_node(0, x=1) == 0
class Assembly(FromToData, FromToJson):
    """A data structure for discrete element assemblies.

    An assembly is essentially a network of assembly elements.
    Each element is represented by a node of the network.
    Each interface or connection between elements is represented by an edge of the network.

    Attributes
    ----------
    network : :class:`compas.Network`, optional
    elements : list of :class:`Element`, optional
        A list of assembly elements.
    attributes : dict, optional
        User-defined attributes of the assembly.
        Built-in attributes are:
        * name (str) : ``'Assembly'``
    default_element_attribute : dict, optional
        User-defined default attributes of the elements of the assembly.
        The built-in attributes are:
        * is_planned (bool) : ``False``
        * is_placed (bool) : ``False``
    default_connection_attributes : dict, optional
        User-defined default attributes of the connections of the assembly.

    Examples
    --------
    >>> assembly = Assembly()
    >>> for i in range(2):
    >>>     element = Element.from_box(Box(Frame.worldXY(), 10, 5, 2))
    >>>     assembly.add_element(element)
    """
    def __init__(self,
                 elements=None,
                 attributes=None,
                 default_element_attributes=None,
                 default_connection_attributes=None):

        self.network = Network()
        self.network.attributes.update({'name': 'Assembly'})

        if attributes is not None:
            self.network.attributes.update(attributes)

        self.network.default_node_attributes.update({
            'is_planned': False,
            'is_placed': False
        })

        if default_element_attributes is not None:
            self.network.default_node_attributes.update(
                default_element_attributes)

        if default_connection_attributes is not None:
            self.network.default_edge_attributes.update(
                default_connection_attributes)

        if elements:
            for element in elements:
                self.add_element(element)

    @property
    def name(self):
        """str : The name of the assembly."""
        return self.network.attributes.get('name', None)

    @name.setter
    def name(self, value):
        self.network.attributes['name'] = value

    def number_of_elements(self):
        """Compute the number of elements of the assembly.

        Returns
        -------
        int
            The number of elements.

        """
        return self.network.number_of_nodes()

    def number_of_connections(self):
        """Compute the number of connections of the assembly.

        Returns
        -------
        int
            the number of connections.

        """
        return self.network.number_of_edges()

    @property
    def data(self):
        """Return a data dictionary of the assembly.
        """
        # Network data does not recursively serialize to data...
        d = self.network.data
        # so we need to trigger that for elements stored in nodes
        node = {}
        for vkey, vdata in d['data']['node'].items():
            node[vkey] = {
                key: vdata[key]
                for key in vdata.keys() if key != 'element'
            }
            node[vkey]['element'] = vdata['element'].to_data()
        d['data']['node'] = node
        return d

    @data.setter
    def data(self, data):
        # Deserialize elements from node dictionary
        for _vkey, vdata in data['data']['node'].items():
            vdata['element'] = Element.from_data(vdata['element'])

        self.network = Network.from_data(data)

    def clear(self):
        """Clear all the assembly data."""
        self.network.clear()

    def add_element(self, element, key=None, attr_dict={}, **kwattr):
        """Add an element to the assembly.

        Parameters
        ----------
        element : Element
            The element to add.
        attr_dict : dict, optional
            A dictionary of element attributes. Default is ``None``.

        Returns
        -------
        hashable
            The identifier of the element.
        """
        attr_dict.update(kwattr)
        x, y, z = element.frame.point
        key = self.network.add_node(key=key,
                                    attr_dict=attr_dict,
                                    x=x,
                                    y=y,
                                    z=z,
                                    element=element)
        return key

    def add_connection(self, u, v, attr_dict=None, **kwattr):
        """Add a connection between two elements and specify its attributes.

        Parameters
        ----------
        u : hashable
            The identifier of the first element of the connection.
        v : hashable
            The identifier of the second element of the connection.
        attr_dict : dict, optional
            A dictionary of connection attributes.
        kwattr
            Other connection attributes as additional keyword arguments.

        Returns
        -------
        tuple
            The identifiers of the elements.
        """
        return self.network.add_edge(u, v, attr_dict, **kwattr)

    def transform(self, transformation):
        """Transforms this assembly.

        Parameters
        ----------
        transformation : :class:`Transformation`

        Returns
        -------
        None
        """
        for _k, element in self.elements(data=False):
            element.transform(transformation)

    def transformed(self, transformation):
        """Returns a transformed copy of this assembly.

        Parameters
        ----------
        transformation : :class:`Transformation`

        Returns
        -------
        Assembly
        """
        assembly = self.copy()
        assembly.transform(transformation)
        return assembly

    def copy(self):
        """Returns a copy of this assembly.
        """
        raise NotImplementedError

    def element(self, key, data=False):
        """Get an element by its key."""
        if data:
            return self.network.node[key]['element'], self.network.node[key]
        else:
            return self.network.node[key]['element']

    def elements(self, data=False):
        """Iterate over the elements of the assembly.

        Parameters
        ----------
        data : bool, optional
            If ``True``, yield both the identifier and the attributes.

        Yields
        ------
        2-tuple
            The next element as a (key, element) tuple, if ``data`` is ``False``.
        3-tuple
            The next element as a (key, element, attr) tuple, if ``data`` is ``True``.

        """
        if data:
            for vkey, vattr in self.network.nodes(True):
                yield vkey, vattr['element'], vattr
        else:
            for vkey in self.network.nodes(data):
                yield vkey, self.network.node[vkey]['element']

    def connections(self, data=False):
        """Iterate over the connections of the network.

        Parameters
        ----------
        data : bool, optional
            If ``True``, yield both the identifier and the attributes.

        Yields
        ------
        2-tuple
            The next connection identifier (u, v), if ``data`` is ``False``.
        3-tuple
            The next connection as a (u, v, attr) tuple, if ``data`` is ``True``.

        """
        return self.network.edges(data)
Ejemplo n.º 11
0
from compas.datastructures import Network


HERE = os.path.dirname(__file__)
FILE = os.path.join(HERE, 'clusters.json')

network = Network()
network.update_default_node_attributes({'cluster': None, 'base': False})

cloud = Pointcloud.from_bounds(10, 5, 3, 100)
kmeans = KMeans(n_clusters=10, n_init=500, max_iter=100).fit(array(cloud, dtype=float))

clusters = {}
for i, point in zip(kmeans.labels_, cloud):
    print(i)
    if i not in clusters:
        clusters[i] = []
    clusters[i].append(point)

for index in clusters:
    nodes = []
    for point in clusters[index]:
        node = network.add_node(x=point[0], y=point[1], z=point[2], cluster=index)
        nodes.append(node)
    x, y, z = centroid_points(clusters[index])
    base = network.add_node(x=x, y=y, z=z, cluster=index, base=True)
    for node in nodes:
        network.add_edge(base, node)

network.to_json(FILE)
Ejemplo n.º 12
0
class AMModel(FromToData, FromToJson):
    """A data structure for non-discrete element fabrication.

    A model is essentially a network of nodes.
    Each geometrical node is represented by a layer in fabrication.
    The sequence of layers in fabrication is represented by an edge of the network.

    Attributes
    ----------
    network : :class:`compas.Network`, optional
    layers : list of :class:`Layer`, optional
        A list of model layers.
    attributes : dict, optional
        User-defined attributes of the model.
        Built-in attributes are:
        * name (str) : ``'AMModel'``
    default_layer_attribute : dict, optional
        User-defined default attributes of the layers of the model.
        The built-in attributes are:
        * is_planned (bool) : ``False``
        * is_placed (bool) : ``False``

    Examples
    --------

    """
    def __init__(self,
                 layers=None,
                 attributes=None,
                 default_layer_attribute=None,
                 default_connection_attributes=None):

        self.network = Network()
        self.network.attributes.update({'name': 'AMModel'})

        if attributes is not None:
            self.network.attributes.update(attributes)

        self.network.default_node_attributes.update({
            'is_planned': False,
            'is_placed': False
        })

        if default_layer_attribute is not None:
            self.network.default_node_attributes.update(
                default_layer_attribute)

        if default_connection_attributes is not None:
            self.network.default_edge_attributes.update(
                default_connection_attributes)

        if layers:
            for layer in layers:
                self.add_layer(layer)

    @property
    def name(self):
        """str : The name of the model."""
        return self.network.attributes.get('name', None)

    @name.setter
    def name(self, value):
        self.network.attributes['name'] = value

    def number_of_layers(self):
        """Compute the number of layers of the model.

        Returns
        -------
        int
            The number of nodes.

        """
        return self.network.number_of_nodes()

    def number_of_connections(self):
        """Compute the number of connections of the model.

        Returns
        -------
        int
            the number of connections.

        """
        return self.network.number_of_edges()

    @property
    def data(self):
        """Return a data dictionary of the model.
        """
        # Network data does not recursively serialize to data...
        d = self.network.data
        #print(d.keys())
        # so we need to trigger that for layers stored in nodes
        node = {}
        for vkey, vdata in d['data']['node'].items():
            node[vkey] = {
                key: vdata[key]
                for key in vdata.keys() if key != 'layer'
            }
            node[vkey]['layer'] = vdata['layer'].to_data()

        d['data']['node'] = node
        return d

    @data.setter
    def data(self, data):
        # Deserialize elements from node dictionary
        for _vkey, vdata in data['data']['node'].items():
            vdata['layer'] = Layer.from_data(vdata['layer'])

        self.network = Network.from_data(data)

    def clear(self):
        """Clear all the model data."""
        self.network.clear()

    def add_layer(self, layer, key=None, attr_dict={}, **kwattr):
        """Add an element to the model.

        Parameters
        ----------
        layer : Layer
            The layer to add.
        attr_dict : dict, optional
            A dictionary of layer attributes. Default is ``None``.

        Returns
        -------
        hashable
            The identifier of the element.
        """
        attr_dict.update(kwattr)
        key = self.network.add_node(key=key, attr_dict=attr_dict, layer=layer)
        return key

    def add_edge(self, u, v, attr_dict=None, **kwattr):
        """Add a connection between two elements and specify its attributes.

        Parameters
        ----------
        u : hashable
            The identifier of the first element of the connection.
        v : hashable
            The identifier of the second element of the connection.
        attr_dict : dict, optional
            A dictionary of connection attributes.
        kwattr
            Other connection attributes as additional keyword arguments.

        Returns
        -------
        tuple
            The identifiers of the elements.
        """
        return self.network.add_edge(u, v, attr_dict, **kwattr)

    def transform(self, transformation):
        """Transforms this model.

        Parameters
        ----------
        transformation : :class:`Transformation`

        Returns
        -------
        None
        """
        for _k, layer in self.layers(data=False):
            layer.transform(transformation)

    def transformed(self, transformation):
        """Returns a transformed copy of this model.

        Parameters
        ----------
        transformation : :class:`Transformation`

        Returns
        -------
        Assembly
        """
        model = self.copy()
        model.transform(transformation)
        return model

    def copy(self):
        """Returns a copy of this model.
        """
        layers = []
        for key, layer in self.layers():
            layers.append(layer.copy())
        return AMModel(layers, self.network.attributes)

    def layer(self, key, data=False):
        """Get an layer by its key."""
        if data:
            return self.network.node[key]['layer'], self.network.node[key]
        else:
            return self.network.node[key]['layer']

    def layers(self, data=False):
        """Iterate over the elements of the model.

        Parameters
        ----------
        data : bool, optional
            If ``True``, yield both the identifier and the attributes.

        Yields
        ------
        2-tuple
            The next element as a (key, element) tuple, if ``data`` is ``False``.
        3-tuple
            The next element as a (key, element, attr) tuple, if ``data`` is ``True``.

        """
        if data:
            for vkey, vattr in self.network.nodes(True):
                yield vkey, vattr['layer'], vattr
        else:
            for vkey in self.network.nodes(data):
                yield vkey, self.network.node[vkey]['layer']

    def connections(self, data=False):
        """Iterate over the connections of the network.

        Parameters
        ----------
        data : bool, optional
            If ``True``, yield both the identifier and the attributes.

        Yields
        ------
        2-tuple
            The next connection identifier (u, v), if ``data`` is ``False``.
        3-tuple
            The next connection as a (u, v, attr) tuple, if ``data`` is ``True``.

        """
        return self.network.edges(data)
Ejemplo n.º 13
0
class Layer:
    """Data structure representing a discrete set of nodes of an model.

    Attributes
    ----------
    network : :class:`compas.Network`, optional
    nodes : :list:class:`Node`, optional
        Nodes discribing the layer geometry
    attributes : dict, optional
        User-defined attributes of the model.
        Built-in attributes are:
        * name (str) : ``'Layer'``
    trajectory : :class:`compas_fab.robots.JointTrajectory`
        The robot trajectory in joint space
    path : :list: :class:`compas.geometry.Frame`
        The robot tool path in cartesian space

    Examples
    --------

    """

    def __init__(self, nodes=None, attributes=None, edges=None):
        self.network = Network()
        self.network.attributes.update({'name': 'Layer',
                                        'is_constructed': False})
        self.is_constructed = False

        if attributes is not None:
            self.network.attributes.update(attributes)
        
        if nodes:
            for node in nodes:
                self.add_node(node)

        self.trajectory = None

    @classmethod
    def from_nodes(cls, nodes):
        """Class method for constructing a layer from a Node objects.

        Parameters
        ----------
        nodes :list: :class:`Node`
            List of Node objects.
        """
        return cls(nodes)

    @property
    def name(self):
        """str : The name of the layer."""
        return self.network.attributes.get('name', None)

    @name.setter
    def name(self, value):
        self.network.attributes['name'] = value
    
    def number_of_nodes(self):
        return self.network.number_of_nodes()
    
    def number_of_edges(self):
        return self.network.number_of_edges()

    def node(self, key, data=False):
        if data:
            return self.network.node[key]['node'], self.network.node[key]
        else:
            return self.network.node[key]['node']

    def nodes(self, data=False):
        if data:
            for vkey, vattr in self.network.nodes(True):
                yield vkey, vattr['node'], vattr
        else:
            for vkey in self.network.nodes(data):
                yield vkey, self.network.node[vkey]['node']

    def edges(self, data=False):
        return self.network.edges(data)

    @property
    def path(self):
        return [node.frame for key, node in self.nodes(False)]

    @path.setter
    def path(self, p):
        self.__path = p

    @classmethod
    def from_data(cls, data):
        """Construct an layer from its data representation.

        Parameters
        ----------
        data : :obj:`dict`
            The data dictionary.

        Returns
        -------
        Layer
            The constructed layer.
        """
        layer = cls()
        layer.data = data
        return layer

    def to_data(self):
        """
        docstring
        """
        return self.data

    @property
    def data(self):
        """Returns the data dictionary that represents the layer.

        Returns
        -------
        dict
            The layer data.

        Examples
        --------
        >>> layer = Layer()
        >>> print(layer.data)
        """
        d = self.network.data
        
        node = {}
        for vkey, vdata in d['data']['node'].items():
            node[vkey] = {key: vdata[key] for key in vdata.keys() if key != 'node'}
            node[vkey]['node'] = vdata['node'].to_data()

        d['data']['node'] = node
        d['data']['is_constructed'] = self.is_constructed
        if self.trajectory:
            d['data']['attributes']['trajectory'] = [f.to_data() for f in self.trajectory]
        if self.path:
            d['data']['attributes']['path'] = [f.to_data() for f in self.path]

        return d

    @data.setter
    def data(self, data):
        for _vkey, vdata in data['data']['node'].items():
            vdata['node'] = Node.from_data(vdata['node'])
        
        if 'is_constructed' in data:
            self.is_constructed = _deserialize_from_data(data['data']['attributes']['is_constructed'])
        if 'trajectory' in data:
            self.trajectory = _deserialize_from_data(data['data']['attributes']['trajectory'])
        if 'path' in data:
            self.path = [Frame.from_data(d) for d in data['data']['attributes']['path']]
        
        self.network = Network.from_data(data)

    def add_node(self, node, key=None, attr_dict={}, **kwattr):
        attr_dict.update(kwattr)
        key = self.network.add_node(key=key, attr_dict=attr_dict, node=node)
        return key
    
    def add_edge(self, u, v, attr_dict=None, **kwattr):
        return self.network.add_edge(u, v, attr_dict, **kwattr)

    def transform(self, transformation):
        for key, node in self.nodes(data=False):
            node.transform(transformation)

    def transformed(self, transformation):
        layer = self.copy()
        layer.transform(transformation)
        return layer

    def copy(self):
        """Returns a copy of this layer.

        Returns
        -------
        Layer
        """
        nodes = []
        for key, node in self.nodes():
            nodes.append(node.copy())
        return Layer(nodes, self.network.attributes)