Exemplo n.º 1
0
    def centroid(self):
        """Calculate the mesh centroid.

        Returns
        -------
        list
            The coordinates of the mesh centroid.
        """
        return scale_vector(sum_vectors([scale_vector(self.face_centroid(fkey), self.face_area(fkey)) for fkey in self.faces()]), 1. / self.area())
Exemplo n.º 2
0
    def normal(self):
        """Calculate the average mesh normal.

        Returns
        -------
        list
            The coordinates of the mesh normal.
        """
        return scale_vector(sum_vectors([scale_vector(self.face_normal(fkey), self.face_area(fkey)) for fkey in self.faces()]), 1. / self.area())
Exemplo n.º 3
0
def RunCommand(is_interactive):

    scene = get_scene()
    if not scene:
        return

    pattern = scene.get("pattern")[0]

    if not pattern:
        print("There is no Pattern in the scene.")
        return

    if not list(pattern.datastructure.vertices_where({'is_anchor': True})):
        print(
            "Pattern has no anchor vertices! Please define anchor (support) vertices."
        )
        return

    form = FormDiagram.from_pattern(pattern.datastructure)
    form.vertices_attribute('is_fixed', False)

    normals = [
        form.face_normal(face)
        for face in form.faces_where({'_is_loaded': True})
    ]
    scale = 1 / len(normals)
    normal = scale_vector(sum_vectors(normals), scale)
    if normal[2] < 0:
        form.flip_cycles()

    fixed = list(pattern.datastructure.vertices_where({'is_fixed': True}))

    if fixed:
        for key in fixed:
            if form.has_vertex(key):
                form.vertex_attribute(key, 'is_anchor', True)

    thrust = form.copy(cls=ThrustDiagram)

    bbox_form = form.bounding_box_xy()
    diagonal = length_vector(subtract_vectors(bbox_form[2], bbox_form[0]))
    zmax = 0.25 * diagonal

    scene.settings['Solvers']['tna.vertical.zmax'] = round(zmax, 1)
    scene.clear()
    scene.add(form, name='form')
    scene.add(thrust, name='thrust')
    scene.update()

    print('FormDiagram object successfully created.')
def face_strip_insert(cls, mesh, vertex_path, pole_extremities, factor=.33):

    # duplicate twice vertices on vertex path
    duplicated_vertices = {}
    for vkey in vertex_path:
        # if closed vertex path, end already included
        if vkey in duplicated_vertices:
            continue
        x, y, z = mesh.vertex_coordinates(vkey)
        vkey_1 = mesh.add_vertex(attr_dict={'x': x, 'y': y, 'z': z})
        vkey_2 = mesh.add_vertex(attr_dict={'x': x, 'y': y, 'z': z})
        duplicated_vertices[vkey] = [vkey_1, vkey_2]

    new_faces = []

    # move along edge path
    for i in range(0, len(vertex_path) - 1):

        u = vertex_path[i]
        v = vertex_path[i + 1]

        if v in mesh.halfedge[u]:
            fkey_left = mesh.halfedge[u][v]
        else:
            fkey_left = None
        if u in mesh.halfedge[v]:
            fkey_right = mesh.halfedge[v][u]
        else:
            fkey_right = None

        # update faces adjacent to vertex path
        if fkey_left is not None:
            face_vertices = [
                duplicated_vertices[vkey][0]
                if vkey in duplicated_vertices else vkey
                for vkey in mesh.face_vertices(fkey_left)
            ]
            mesh.delete_face(fkey_left)
            mesh.add_face(face_vertices, fkey_left)
        if fkey_right is not None:
            face_vertices = [
                duplicated_vertices[vkey][1]
                if vkey in duplicated_vertices else vkey
                for vkey in mesh.face_vertices(fkey_right)
            ]
            mesh.delete_face(fkey_right)
            mesh.add_face(face_vertices, fkey_right)

        # add strip
        face_vertices = [
            duplicated_vertices[u][1], duplicated_vertices[v][1],
            duplicated_vertices[v][0], duplicated_vertices[u][0]
        ]
        new_faces.append(mesh.add_face(face_vertices))

    # delete old vertices
    # remove end if closed vertex path
    if vertex_path[0] == vertex_path[-1]:
        culled_verted_vertex_path = vertex_path[:-1]
    else:
        culled_verted_vertex_path = vertex_path
    for vkey in culled_verted_vertex_path:
        if len(mesh.vertex_faces(vkey)) > 0:
            faces = [
                mesh.halfedge[vkey][a] for a in mesh.vertex_neighbors(vkey)
                if mesh.halfedge[vkey][a] is not None
            ]
            count = len(faces) * 2
            while len(faces) > 0 and count > 0:
                for fkey in faces:
                    for fkey_2 in [
                            fkey_3 for vkey_2 in mesh.face_vertices(fkey)
                            for fkey_3 in mesh.vertex_faces(vkey_2)
                    ]:
                        if duplicated_vertices[vkey][0] in mesh.face_vertices(
                                fkey_2):
                            duplicate = duplicated_vertices[vkey][0]
                            face_vertices = [
                                duplicate if key == vkey else key
                                for key in mesh.face_vertices(fkey)
                            ]
                            mesh.delete_face(fkey)
                            mesh.add_face(face_vertices, fkey)
                            faces.remove(fkey)
                            break
                        if duplicated_vertices[vkey][1] in mesh.face_vertices(
                                fkey_2):
                            duplicate = duplicated_vertices[vkey][1]
                            face_vertices = [
                                duplicate if key == vkey else key
                                for key in mesh.face_vertices(fkey)
                            ]
                            mesh.delete_face(fkey)
                            mesh.add_face(face_vertices, fkey)
                            faces.remove(fkey)
                            break
                    if fkey not in faces:
                        break
        mesh.delete_vertex(vkey)

    # transform pole extemities
    for vkey, is_pole in zip([vertex_path[0], vertex_path[-1]],
                             pole_extremities):
        if is_pole:
            u, v = duplicated_vertices[vkey]
            for fkey in mesh.vertex_faces(v):
                if fkey is not None:
                    new_face_vertices = [
                        u if vkey_2 == v else vkey_2
                        for vkey_2 in mesh.face_vertices(fkey)
                    ]
                    mesh.delete_face(fkey)
                    mesh.add_face(new_face_vertices, fkey)
            duplicated_vertices[vkey].remove(v)
            mesh.delete_vertex(v)

    # move duplicated superimposed vertices towards neighbours' centroid
    moves = {}
    for vkey in [
            vkey for vkeys in duplicated_vertices.values() for vkey in vkeys
    ]:
        #if mesh.is_vertex_on_boundary(vkey):
        #    continue
        xyz = scale_vector(
            sum_vectors([
                mesh.vertex_coordinates(nbr)
                for nbr in mesh.vertex_neighbors(vkey)
            ]), 1. / len(mesh.vertex_neighbors(vkey)))
        moves[vkey] = xyz
    for vkey, xyz in moves.items():
        x, y, z = xyz
        attr = mesh.vertex[vkey]
        attr['x'] += factor * (x - attr['x'])
        attr['y'] += factor * (y - attr['y'])
        attr['z'] += factor * (z - attr['z'])

    return new_faces
def face_strip_insert_2(cls, mesh, vertex_path, factor=.33):

    # check if vertex_path is a loop
    if vertex_path[0] == vertex_path[-1]:
        loop = True
    else:
        loop = False

    edge_path = [[vertex_path[i], vertex_path[i + 1]]
                 for i in range(len(vertex_path) - 1)]
    if loop:
        del edge_path[-1]

    # duplicate the vertices along the edge_path by unwelding the mesh
    duplicates = unweld_mesh_along_edge_path(mesh, edge_path)

    duplicate_list = [i for uv in duplicates for i in uv]

    # move the duplicated vertices towards the centroid of the adjacent faces
    for uv in duplicates:
        for vkey in uv:
            # if was on boundary before unwelding, move along boundary edge
            on_boundary = False
            for nbr in mesh.vertex_neighbors(vkey):
                if mesh.is_edge_on_boundary(vkey,
                                            nbr) and nbr not in duplicate_list:
                    x, y, z = mesh.edge_point(vkey, nbr, factor)
                    on_boundary = True
            if not on_boundary:
                centroids = [
                    mesh.face_centroid(fkey)
                    for fkey in mesh.vertex_faces(vkey)
                ]
                areas = [
                    mesh.face_area(fkey) for fkey in mesh.vertex_faces(vkey)
                ]
                #if len(centroids) != 0:
                x, y, z = sum_vectors([
                    scale_vector(centroid, area / sum(areas))
                    for centroid, area in zip(centroids, areas)
                ])
                attr = mesh.vertex[vkey]
                # factor related to the width of the new face strip compared to the adjacent ones
                attr['x'] += factor * (x - attr['x'])
                attr['y'] += factor * (y - attr['y'])
                attr['z'] += factor * (z - attr['z'])

    # add new face strip
    for i in range(len(duplicates) - 1):
        a = duplicates[i][1]
        b = duplicates[i][0]
        c = duplicates[i + 1][0]
        d = duplicates[i + 1][1]
        mesh.add_face([a, b, c, d])
    # close if loop
    if loop:
        a = duplicates[-1][1]
        b = duplicates[i - 1][0]
        c = duplicates[0][0]
        d = duplicates[0][1]
        mesh.add_face([a, b, c, d])

    return 0
Exemplo n.º 6
0
def discrete_coons_patch(ab, bc, dc, ad):
    """Creates a coons patch from a set of four or three boundary
    polylines (ab, bc, dc, ad).

    Parameters
    ----------
    polylines : sequence
        The XYZ coordinates of the vertices of the polyline.
        The vertices are assumed to be in order.
        The polyline is assumed to be open:

    Returns
    -------
    points : list of tuples
        The points of the coons patch.
    faces : list of lists
        List of faces (face = list of vertex indices as integers)

    Notes
    -----
    Direction and order of polylines::

        b -----> c
        ^        ^
        |        |
        |        |
        |        |
        a -----> d

    One polyline can be None to create a triangular patch
    (Warning! This will result in duplicate vertices)

    For more information see [1]_ and [2]_.

    References
    ----------
    .. [1] Wikipedia. *Coons patch*.
           Available at: https://en.wikipedia.org/wiki/Coons_patch.
    .. [2] Robert Ferreol. *Patch de Coons*.
           Available at: https://www.mathcurve.com/surfaces/patchcoons/patchcoons.shtml

    Examples
    --------
    .. code-block:: python

        #

    See Also
    --------
    * :func:`compas.datastructures.mesh_cull_duplicate_vertices`

    """
    if not ab:
        ab = [ad[0]] * len(dc)
    if not bc:
        bc = [ab[-1]] * len(ad)
    if not dc:
        dc = [bc[-1]] * len(ab)
    if not ad:
        ad = [dc[0]] * len(bc)

    n = len(ab)
    m = len(bc)

    n_norm = normalize_values(range(n))
    m_norm = normalize_values(range(m))

    array = [[0] * m for i in range(n)]
    for i, ki in enumerate(n_norm):
        for j, kj in enumerate(m_norm):
            # first function: linear interpolation of first two opposite curves
            lin_interp_ab_dc = add_vectors(scale_vector(ab[i], (1 - kj)),
                                           scale_vector(dc[i], kj))
            # second function: linear interpolation of other two opposite curves
            lin_interp_bc_ad = add_vectors(scale_vector(ad[j], (1 - ki)),
                                           scale_vector(bc[j], ki))
            # third function: linear interpolation of four corners resulting a hypar
            a = scale_vector(ab[0], (1 - ki) * (1 - kj))
            b = scale_vector(bc[0], ki * (1 - kj))
            c = scale_vector(dc[-1], ki * kj)
            d = scale_vector(ad[-1], (1 - ki) * kj)
            lin_interp_a_b_c_d = sum_vectors([a, b, c, d])
            # coons patch = first + second - third functions
            array[i][j] = subtract_vectors(
                add_vectors(lin_interp_ab_dc, lin_interp_bc_ad),
                lin_interp_a_b_c_d)

    # create vertex list
    vertices = []
    for i in range(n):
        vertices += array[i]

    # create face vertex list
    face_vertices = []
    for i in range(n - 1):
        for j in range(m - 1):
            face_vertices.append([
                i * m + j, i * m + j + 1, (i + 1) * m + j + 1, (i + 1) * m + j
            ])
    return vertices, face_vertices
Exemplo n.º 7
0
    def draw_frictions(self, scale=None, eps=None, mode=0):
        """Draw the contact frictions at the interfaces.

        Parameters
        ----------
        scale : float, optional
            The scale at which the forces should be drawn.
            Default is `0.1`.
        eps : float, optional
            A tolerance for drawing small force vectors.
            Force vectors with a scaled length smaller than this tolerance are not drawn.
            Default is `1e-3`.
        mode : int, optional
            Display mode: 0 normal, 1 resultant forces
            Default is 0

        Notes
        -----
        * Forces are drawn as lines with arrow heads.
        * Forces are drawn on a sub-layer *Frictions* of the base layer, if a base layer was specified.
        * Forces are named according to the following pattern:
          ``"{assembly_name}.friction.{from block}-{to block}.{interface point}"``

        """
        layer = "{}::Frictions".format(self.layer) if self.layer else None
        scale = scale or self.defaults['scale.friction']
        eps = eps or self.defaults['eps.friction']
        color_friction = self.defaults['color.force:friction']

        lines = []
        resultant_lines = []

        for a, b, attr in self.assembly.edges(True):
            if attr['interface_forces'] is None:
                continue

            u, v = attr['interface_uvw'][0], attr['interface_uvw'][1]

            forces = []

            for i in range(len(attr['interface_points'])):
                sp = attr['interface_points'][i]
                fr_u_unit = attr['interface_forces'][i]['c_u']
                fr_v_unit = attr['interface_forces'][i]['c_v']

                fr_u = scale_vector(u, fr_u_unit)
                fr_v = scale_vector(v, fr_v_unit)
                f = add_vectors(fr_u, fr_v)
                f_l = length_vector(f)

                if f_l > 0.0:
                    if scale * f_l < eps:
                        continue
                    color = color_friction
                else:
                    continue

                f = scale_vector(f, scale)

                lines.append({
                    'start':
                    sp,
                    'end': [sp[axis] + f[axis] for axis in range(3)],
                    'color':
                    color,
                    'name':
                    "{0}.friction.{1}-{2}.{3}".format(self.assembly.name, a, b,
                                                      i),
                    'arrow':
                    'end'
                })

                if mode == 1:
                    forces.append(f)

            if mode == 0:
                continue

            resultant_force = sum_vectors(forces)

            if len(forces) == 0:
                continue

            resultant_pt = sum_vectors([
                scale_vector(attr['interface_points'][i],
                             (length_vector(forces[i]) /
                              length_vector(resultant_force)))
                for i in range(len(attr['interface_points']))
            ])

            resultant_lines.append({
                'start':
                resultant_pt,
                'end': [
                    resultant_pt[axis] + resultant_force[axis]
                    for axis in range(3)
                ],
                'color':
                color,
                'name':
                "{0}.resultant-friction.{1}-{2}.{3}".format(
                    self.assembly.name, a, b, i),
                'arrow':
                'end'
            })

        if mode == 0:
            compas_rhino.xdraw_lines(lines,
                                     layer=layer,
                                     clear=False,
                                     redraw=False)
        else:
            compas_rhino.xdraw_lines(resultant_lines,
                                     layer=layer,
                                     clear=False,
                                     redraw=False)
Exemplo n.º 8
0
    # multiply by the local thickness
    # assign to the correct item in the list of loads

xyz, q, f, l, r = numerical.fd_numpy(xyz, edges, fixed, q, loads)

# update the data structure

for key in mesh.vertices():
    if mesh.get_vertex_attribute(key, 'is_fixed'):
        continue

    # compute the load on the vertex
    # compute the forces in the edges connected to the vertex
    # sum up the vectors to compute the residual force

    resultant = sum_vectors(forces)
    mesh.set_vertex_attributes(key, ('rx', 'ry', 'rz'), resultant)

# ==============================================================================
# Visualise the result
# ==============================================================================

artist = MeshArtist(mesh, layer="Selfweight")
artist.clear_layer()
artist.draw_vertices()
artist.draw_edges()
artist.draw_faces()

loads = []
for key in mesh.vertices():
    if mesh.get_vertex_attribute(key, 'is_fixed'):
Exemplo n.º 9
0
def discrete_coons_patch(ab, bc, dc, ad):
    """Creates a coons patch from a set of four or three boundary
    polylines (ab, bc, dc, ad).

    Parameters
    ----------
    ab : list[[float, float, float] | :class:`compas.geometry.Point`]
        The XYZ coordinates of the vertices of the first polyline.
    bc : list[[float, float, float] | :class:`compas.geometry.Point`]
        The XYZ coordinates of the vertices of the second polyline.
    dc : list[[float, float, float] | :class:`compas.geometry.Point`]
        The XYZ coordinates of the vertices of the third polyline.
    ad : list[[float, float, float] | :class:`compas.geometry.Point`]
        The XYZ coordinates of the vertices of the fourth polyline.

    Returns
    -------
    list[[float, float, float]]
        The points of the coons patch.
    list[list[int]]
        List of faces, with every face a list of indices into the point list.

    Notes
    -----
    The vertices of the polylines are assumed to be in the following order::

        b -----> c
        ^        ^
        |        |
        |        |
        a -----> d

    To create a triangular patch, one of the input polylines should be None.
    (Warning! This will result in duplicate vertices.)

    For more information see [1]_ and [2]_.

    References
    ----------
    .. [1] Wikipedia. *Coons patch*.
           Available at: https://en.wikipedia.org/wiki/Coons_patch.
    .. [2] Robert Ferreol. *Patch de Coons*.
           Available at: https://www.mathcurve.com/surfaces/patchcoons/patchcoons.shtml

    Examples
    --------
    >>>

    """
    if not ab:
        ab = [ad[0]] * len(dc)
    if not bc:
        bc = [ab[-1]] * len(ad)
    if not dc:
        dc = [bc[-1]] * len(ab)
    if not ad:
        ad = [dc[0]] * len(bc)

    n = len(ab)
    m = len(bc)

    n_norm = normalize_values(range(n))
    m_norm = normalize_values(range(m))

    array = [[0] * m for i in range(n)]
    for i, ki in enumerate(n_norm):
        for j, kj in enumerate(m_norm):
            # first function: linear interpolation of first two opposite curves
            lin_interp_ab_dc = add_vectors(scale_vector(ab[i], (1 - kj)),
                                           scale_vector(dc[i], kj))
            # second function: linear interpolation of other two opposite curves
            lin_interp_bc_ad = add_vectors(scale_vector(ad[j], (1 - ki)),
                                           scale_vector(bc[j], ki))
            # third function: linear interpolation of four corners resulting a hypar
            a = scale_vector(ab[0], (1 - ki) * (1 - kj))
            b = scale_vector(bc[0], ki * (1 - kj))
            c = scale_vector(dc[-1], ki * kj)
            d = scale_vector(ad[-1], (1 - ki) * kj)
            lin_interp_a_b_c_d = sum_vectors([a, b, c, d])
            # coons patch = first + second - third functions
            array[i][j] = subtract_vectors(
                add_vectors(lin_interp_ab_dc, lin_interp_bc_ad),
                lin_interp_a_b_c_d)

    # create vertex list
    vertices = []
    for i in range(n):
        vertices += array[i]

    # create face vertex list
    faces = []
    for i in range(n - 1):
        for j in range(m - 1):
            faces.append([
                i * m + j, i * m + j + 1, (i + 1) * m + j + 1, (i + 1) * m + j
            ])
    return vertices, faces
Exemplo n.º 10
0
    for node in embedding.leaves():
        u = embedding.neighbors(node)[0]
        if u in fixed:
            continue

        a = embedding.node_attributes(u, 'xyz')

        vectors = []
        for v in noleaves.neighbors(u):
            b = embedding.node_attributes(v, 'xyz')
            vectors.append(normalize_vector(subtract_vectors(b, a)))

        ab = scale_vector(
            normalize_vector(
                scale_vector(sum_vectors(vectors), 1 / len(vectors))), length)
        embedding.node_attributes(node, 'xyz', subtract_vectors(a, ab))

# ==============================================================================
# Construct a form diagram of the embedding
# ==============================================================================

form = FormDiagram.from_graph(embedding)

# ==============================================================================
# Visualize the result
# ==============================================================================

plotter = MeshPlotter(form, figsize=(12, 7.5))
plotter.draw_vertices(text='key', radius=0.3)
plotter.draw_edges()