Пример #1
0
def plot_structure(structure):
    eks = []
    for ep in structure.element_properties:
        elements = structure.element_properties[ep].elements
        elset = structure.element_properties[ep].elset
        if elements:
            eks = elements
        elif elset:
            eks = structure.sets[elset].selection
        sec = structure.element_properties[ep].section
        t = structure.sections[sec].geometry['t']
        for ek in eks:
            nodes = structure.elements[ek].nodes
            vert = [structure.nodes[nk].xyz() for nk in nodes]
            n = scale_vector(normalize_vector(normal_polygon(vert)), t / 2.)
            n_ = scale_vector(n, -1)
            v_out = [add_vectors(v, n) for v in vert]
            v_in = [add_vectors(v, n_) for v in vert]
            s1 = rs.AddSrfPt(v_out)
            s2 = rs.AddSrfPt(v_in)
            srfs = [s1, s2]
            for i in range(len(v_in)):
                srf = rs.AddSrfPt(
                    [v_in[-i], v_in[-i - 1], v_out[-i - 1], v_out[-i]])
                if srf:
                    srfs.append(srf)
            rs.JoinSurfaces(srfs, delete_input=True)
Пример #2
0
def bmesh_face_normals(bmesh):
    """ Retrieve the face normals of a Blender mesh.

    Parameters:
        bmesh (obj): Blender mesh object.

    Returns:
        list: Normals of each face.
    """
    vertices, edges, faces = bmesh_data(bmesh)
    polygons = [[vertices[i] for i in face] for face in faces]
    normals = [normal_polygon(polygon) for polygon in polygons]
    return normals
Пример #3
0
def offset_polygon(polygon, distance, tol=1e-6):
    """Offset a polygon (closed) by a distance.

    Parameters
    ----------
    polygon : sequence[point] | :class:`compas.geometry.Polygon`
        The XYZ coordinates of the corners of the polygon.
        The first and last coordinates must not be identical.
    distance : float | list[tuple[float, float]]
        The offset distance as float.
        A single value determines a constant offset globally.
        A list of pairs of local offset values per line segment can be used to create variable offsets.
    tol : float, optional
        A tolerance value for intersection calculations.

    Returns
    -------
    list[[float, float, float]]
        The XYZ coordinates of the corners of the offset polygon.
        The first and last coordinates are identical.

    Notes
    -----
    The offset direction is determined by the normal of the polygon.
    If the polygon is in the XY plane and the normal is along the positive Z axis,
    positive offset distances will result in an offset towards the inside of the
    polygon.

    The algorithm works also for spatial polygons that do not perfectly fit a plane.

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

    """
    normal = normal_polygon(polygon)

    if not is_item_iterable(distance):
        distance = [distance]
    distances = iterable_like(polygon, distance, distance[-1])

    polygon = polygon + polygon[:1]
    segments = offset_segments(polygon, distances, normal)

    offset = []
    for s1, s2 in pairwise(segments[-1:] + segments):
        point = intersect(s1, s2, tol)
        offset.append(point)

    return offset
Пример #4
0
    def face_normal(self, face, unitized=True):
        """Compute the oriented normal of a face.

        Parameters
        ----------
        face : int
            The identifier of the face.
        unitized : bool, optional
            If True, unitize the normal vector.

        Returns
        -------
        list[float]
            The components of the normal vector.

        """
        return normal_polygon(self.face_coordinates(face), unitized=unitized)
Пример #5
0
    def face_normal(self, fkey, unitized=True):
        """Compute the normal of a face.

        Parameters
        ----------
        fkey : int
            The identifier of the face.
        unitized : bool, optional
            Unitize the normal vector.
            Default is ``True``.

        Returns
        -------
        list
            The components of the normal vector.
        """
        return normal_polygon(self.face_coordinates(fkey), unitized=unitized)
Пример #6
0
    def in_polyhedron(self, polyhedron):
        """Determine if the point lies inside the given polyhedron.

        Parameters
        ----------
        polyhedron : [vertices, faces] or :class:`compas.geometry.Polyhedron`.
            The polyhedron.

        Returns
        -------
        bool
            True, if the point lies on the polyline.
            False, otherwise.
        """
        vertices, faces = polyhedron
        polygons = [[vertices[index] for index in face] for face in faces]
        planes = [[centroid_points(polygon), normal_polygon(polygon)] for polygon in polygons]
        return all(is_point_behind_plane(self, plane) for plane in planes)
Пример #7
0
 def face_normal(self, fkey, normalized=True):
     """Return the normal of a face."""
     return normal_polygon(self.face_coordinates(fkey), normalized=normalized)
Пример #8
0
def offset_polygon(polygon, distance):
    """Offset a polygon (closed) by a distance.

    Parameters
    ----------
    polygon : list of point
        The XYZ coordinates of the corners of the polygon.
        The first and last coordinates must be identical.
    distance : float or list of tuples of floats
        The offset distance as float.
        A single value determines a constant offset globally.
        Alternatively, pairs of local offset values per line segment can be used to create variable offsets.
        Distance > 0: offset to the outside, distance < 0: offset to the inside.

    Returns
    -------
    offset polygon : list of point
        The XYZ coordinates of the corners of the offset polygon.
        The first and last coordinates are identical.

    Notes
    -----
    The offset direction is determined by the normal of the polygon.
    The algorithm works also for spatial polygons that do not perfectly fit a plane.

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

        polygon = [
            (0.0, 0.0, 0.0),
            (3.0, 0.0, 1.0),
            (3.0, 3.0, 2.0),
            (1.5, 1.5, 2.0),
            (0.0, 3.0, 1.0),
            (0.0, 0.0, 0.0)
            ]

        distance = 0.5 # constant offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

        distance = [
            (0.1, 0.2),
            (0.2, 0.3),
            (0.3, 0.4),
            (0.4, 0.3),
            (0.3, 0.1)
            ] # variable offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

    """
    normal = normal_polygon(polygon)

    if isinstance(distance, list) or isinstance(distance, tuple):
        distances = distance
        if len(distances) < len(polygon):
            distances = distances + [distances[-1]
                                     ] * (len(polygon) - len(distances) - 1)
    else:
        distances = [[distance, distance]] * len(polygon)

    lines = [polygon[i:i + 2] for i in range(len(polygon[:-1]))]
    lines_offset = []
    for i, line in enumerate(lines):
        lines_offset.append(offset_line(line, distances[i], normal))

    polygon_offset = []

    for i in range(len(lines_offset)):
        intx_pt1, intx_pt2 = intersection_line_line(lines_offset[i - 1],
                                                    lines_offset[i])

        if intx_pt1 and intx_pt2:
            polygon_offset.append(centroid_points([intx_pt1, intx_pt2]))
        else:
            polygon_offset.append(lines_offset[i][0])

    polygon_offset.append(polygon_offset[0])
    return polygon_offset
Пример #9
0
def offset_polygon(polygon, distance, tol=1e-6):
    """Offset a polygon (closed) by a distance.

    Parameters
    ----------
    polygon : list of point
        The XYZ coordinates of the corners of the polygon.
        The first and last coordinates must not be identical.
    distance : float or list of float
        The offset distance as float.
        A single value determines a constant offset globally.
        Alternatively, pairs of local offset values per line segment can be used to create variable offsets.
        Distance > 0: offset to the outside, distance < 0: offset to the inside.

    Returns
    -------
    offset polygon : list of point
        The XYZ coordinates of the corners of the offset polygon.
        The first and last coordinates are identical.

    Notes
    -----
    The offset direction is determined by the normal of the polygon.
    If the polygon is in the XY plane and the normal is along the positive Z axis,
    positive offset distances will result in an offset towards the inside of the
    polygon.

    The algorithm works also for spatial polygons that do not perfectly fit a plane.

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

        polygon = [
            (0.0, 0.0, 0.0),
            (3.0, 0.0, 1.0),
            (3.0, 3.0, 2.0),
            (1.5, 1.5, 2.0),
            (0.0, 3.0, 1.0),
            (0.0, 0.0, 0.0)
            ]

        distance = 0.5 # constant offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

        distance = [
            (0.1, 0.2),
            (0.2, 0.3),
            (0.3, 0.4),
            (0.4, 0.3),
            (0.3, 0.1)
            ] # variable offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

    """
    normal = normal_polygon(polygon)

    if not is_item_iterable(distance):
        distance = [distance]
    distances = iterable_like(polygon, distance, distance[-1])

    polygon = polygon + polygon[:1]
    segments = offset_segments(polygon, distances, normal)

    offset = []
    for s1, s2 in pairwise(segments[-1:] + segments):
        point = intersect(s1, s2, tol)
        offset.append(point)

    return offset
Пример #10
0
poly = BRepBuilderAPI_MakePolygon()
for point in points:
    poly.Add(point)
poly.Build()
poly.Close()

# ==============================================================================
# BRep Filling
# ==============================================================================

edges = list(TopologyExplorer(poly.Wire()).edges())

nsided = BRepFill_Filling()
for edge in edges:
    nsided.Add(edge, GeomAbs_C0)
nsided.Add(gp_Pnt(*(polygon.centroid + normal_polygon(polygon))))
nsided.Build()

# ==============================================================================
# Surface from BRep Filling Face
# ==============================================================================

face = nsided.Face()
surface = OCCNurbsSurface.from_face(face)

# ==============================================================================
# BRep
# ==============================================================================

brep = BRep()
brep.shape = face
Пример #11
0
def conforming(patch_decomposition,
               delaunay_mesh,
               medial_branches,
               boundary_polylines,
               edges_to_polyline,
               feature_points=[],
               feature_polylines=[]):
    # convert tri faces [a, b, c] into quad faces [a, b, c, c]

    # collect pole locations
    poles = []
    poles += [
        geometric_key([float(x), float(y), float(z)])
        for x, y, z in feature_points
    ]
    for polyline in feature_polylines:
        start = [float(i) for i in polyline[0]]
        end = [float(i) for i in polyline[-1]]
        poles += [geometric_key(start), geometric_key(end)]

    # modify tri faces into quad faces with a double vertex as pole point
    for fkey in patch_decomposition.faces():
        face_vertices = patch_decomposition.face_vertices(fkey)
        if len(face_vertices) == 3:
            # find pole location
            pole = None
            for vkey in face_vertices:
                geom_key = geometric_key(
                    patch_decomposition.vertex_coordinates(vkey))
                if geom_key in poles:
                    pole = vkey
                    break
            # modify face
            if pole is not None:
                new_face_vertices = face_vertices[:]
                idx = new_face_vertices.index(vkey)
                new_face_vertices.insert(idx, vkey)
                patch_decomposition.delete_face(fkey)
                patch_decomposition.add_face(new_face_vertices, fkey)

    # remove remaining tri faces that are not pseudo quads
    # loop over boundary vertices
    boundary_vertices = patch_decomposition.vertices_on_boundary()
    for vkey in boundary_vertices:
        vertex_faces = patch_decomposition.vertex_faces(vkey, ordered=True)
        vertex_neighbours = patch_decomposition.vertex_neighbors(vkey,
                                                                 ordered=True)
        for fkey in vertex_faces:
            # apply changes if there is an adjacent tri face (pseudo-quads are already transformed)
            if len(patch_decomposition.face_vertices(fkey)) == 3:
                # remove quad faces at each extremity
                tri_faces = vertex_faces[1:-1]
                vertex_left = vertex_neighbours[-1]
                vertex_right = vertex_neighbours[0]
                new_vertices = []
                n = len(tri_faces)
                m = int(floor((n + 1) / 2))
                # add new vertices on the adjacent boundary edges depending on the number of triangles to modify
                polyline_left = edges_to_polyline[(vertex_left, vkey)]
                point_left = polyline_point(polyline_left,
                                            t=.9,
                                            snap_to_point=True)
                if point_left == polyline_left[-1]:
                    # assuming there is at least 3 points
                    point_left = polyline_left[-2]
                #if geometric_key(point_left) == geometric_key(patch_decomposition.vertex_coordinates(vkey)):
                #    point_left = patch_decomposition.edge_point(vertex_left, vkey, t = .9)
                vertices_left = [
                    line_point([
                        point_left,
                        patch_decomposition.vertex_coordinates(vkey)
                    ],
                               t=float(i) / float(m)) for i in range(m)
                ]
                #vertices_left = [patch_decomposition.edge_point(vertex_left, vkey, t = .9 + float(i) / float(m) * .1) for i in range(m)]
                vertices_left = [
                    patch_decomposition.add_vertex(attr_dict={
                        'x': x,
                        'y': y,
                        'z': z
                    }) for x, y, z in vertices_left
                ]
                polyline_right = edges_to_polyline[(vertex_right, vkey)]
                point_right = polyline_point(polyline_right,
                                             t=.9,
                                             snap_to_point=True)
                if point_right == polyline_right[-1]:
                    # assuming there is at least 3 points
                    point_right = polyline_right[-2]
                #if geometric_key(point_right) == geometric_key(patch_decomposition.vertex_coordinates(vkey)):
                #    point_right = patch_decomposition.edge_point(vertex_right, vkey, t = .9)
                vertices_right = [
                    line_point([
                        point_right,
                        patch_decomposition.vertex_coordinates(vkey)
                    ],
                               t=float(i) / float(m)) for i in range(m)
                ]
                #vertices_right = [patch_decomposition.edge_point(vertex_right, vkey, t = .9 + float(i) / float(m) * .1) for i in range(m)]
                vertices_right = [
                    patch_decomposition.add_vertex(attr_dict={
                        'x': x,
                        'y': y,
                        'z': z
                    }) for x, y, z in vertices_right
                ]
                vertex_centre = []
                # add existing vertex if there is an even number of triangles
                if n % 2 == 0:
                    vertex_centre = [vkey]
                vertices = vertices_right + vertex_centre + list(
                    reversed(vertices_left))
                # modfiy the triangle face vertices
                for i, fkey in enumerate(tri_faces):
                    face_vertices = patch_decomposition.face_vertices(fkey)[:]
                    idx = face_vertices.index(vkey)
                    face_vertices.insert(idx, vertices[i + 1])
                    face_vertices.insert(idx, vertices[i])
                    del face_vertices[idx + 2 - len(face_vertices)]
                    # update edges_to_polyline
                    b = face_vertices[idx - 3]
                    c = face_vertices[idx - 2]
                    d = face_vertices[idx - 1]
                    a = face_vertices[idx]
                    for u, v in [[a, b], [a, d], [b, c]]:
                        if (u, v) in edges_to_polyline:
                            del edges_to_polyline[(u, v)]
                        if (v, u) in edges_to_polyline:
                            del edges_to_polyline[(v, u)]
                        edges_to_polyline[(u, v)] = [
                            patch_decomposition.vertex_coordinates(u),
                            patch_decomposition.vertex_coordinates(v)
                        ]
                        edges_to_polyline[(v, u)] = [
                            patch_decomposition.vertex_coordinates(v),
                            patch_decomposition.vertex_coordinates(u)
                        ]
                    # update faces
                    patch_decomposition.delete_face(fkey)
                    patch_decomposition.add_face(face_vertices, fkey)
                # update quad face on the left
                fkey_left = vertex_faces[-1]
                face_vertices = patch_decomposition.face_vertices(fkey_left)[:]
                idx = face_vertices.index(vkey)
                face_vertices[idx] = vertices[-1]
                patch_decomposition.delete_face(fkey_left)
                patch_decomposition.add_face(face_vertices, fkey_left)
                del edges_to_polyline[(vertex_left, vkey)]
                del edges_to_polyline[(vkey, vertex_left)]
                idx = polyline_left.index(point_left)
                edges_to_polyline[(vertex_left,
                                   vertices[-1])] = polyline_left[:idx + 1]
                edges_to_polyline[(vertices[-1], vertex_left)] = list(
                    reversed(polyline_left[:idx + 1]))
                # update quad face on the right
                fkey_right = vertex_faces[0]
                face_vertices = patch_decomposition.face_vertices(
                    fkey_right)[:]
                idx = face_vertices.index(vkey)
                face_vertices[idx] = vertices[0]
                patch_decomposition.delete_face(fkey_right)
                patch_decomposition.add_face(face_vertices, fkey_right)
                del edges_to_polyline[(vertex_right, vkey)]
                del edges_to_polyline[(vkey, vertex_right)]
                idx = polyline_right.index(point_right)
                edges_to_polyline[(vertex_right,
                                   vertices[0])] = polyline_right[:idx + 1]
                edges_to_polyline[(vertices[0], vertex_right)] = list(
                    reversed(polyline_right[:idx + 1]))
                break

    # subidive low quality faces using reference to initial edge polyline
    faces = list(patch_decomposition.faces())
    while len(faces) > 0:
        fkey = faces.pop()
        # face values
        face_normal = patch_decomposition.face_normal(fkey)
        face_area = patch_decomposition.face_area(fkey)
        face_vertices = patch_decomposition.face_vertices(fkey)
        # collect initial polylines
        polylines = []
        for i in range(len(face_vertices)):
            # exception for pseudo-quads with poles
            if face_vertices[i - 1] != face_vertices[i]:
                polylines.append(edges_to_polyline[(face_vertices[i - 1],
                                                    face_vertices[i])])
        # patch values
        polygon = []
        for polyline in polylines:
            polygon += polyline[:-1]
        patch_area = area_polygon(polygon)
        patch_normal = normal_polygon(polygon)
        signed_face_area = dot_vectors(face_normal, patch_normal) / abs(
            dot_vectors(face_normal, patch_normal)) * face_area
        # if degenerated face compared to patch, modify
        if signed_face_area < 0.1 * patch_area:
            for u, v in patch_decomposition.face_halfedges(fkey):
                # collect vertices
                if patch_decomposition.is_edge_on_boundary(u, v):
                    w = patch_decomposition.face_vertex_descendant(fkey, v)
                    x = patch_decomposition.face_vertex_descendant(fkey, w)
                    fkey_bis = patch_decomposition.halfedge[x][w]
                    if fkey_bis in faces:
                        faces.remove(fkey_bis)
                    z = patch_decomposition.face_vertex_descendant(fkey_bis, w)
                    y = patch_decomposition.face_vertex_descendant(fkey_bis, z)
                    # add new vertices on polylines
                    xa, ya, za = polyline_point(edges_to_polyline[(u, v)],
                                                t=.5,
                                                snap_to_point=True)
                    a = patch_decomposition.add_vertex(attr_dict={
                        'x': xa,
                        'y': ya,
                        'z': za
                    })
                    xb, yb, zb = polyline_point(edges_to_polyline[(w, x)],
                                                t=.5,
                                                snap_to_point=True)
                    b = patch_decomposition.add_vertex(attr_dict={
                        'x': xb,
                        'y': yb,
                        'z': zb
                    })
                    xc, yc, zc = polyline_point(edges_to_polyline[(z, y)],
                                                t=.5,
                                                snap_to_point=True)
                    c = patch_decomposition.add_vertex(attr_dict={
                        'x': xc,
                        'y': yc,
                        'z': zc
                    })
                    # update edges to polylines
                    # uv -> ua + av (and flipped)
                    polyline_uv = edges_to_polyline[(u, v)]
                    del edges_to_polyline[(u, v)]
                    del edges_to_polyline[(v, u)]
                    idx_a = polyline_uv.index([xa, ya, za])
                    edges_to_polyline[(u, a)] = polyline_uv[:idx_a + 1]
                    edges_to_polyline[(a, u)] = list(
                        reversed(polyline_uv[:idx_a + 1]))
                    edges_to_polyline[(a, v)] = polyline_uv[idx_a:]
                    edges_to_polyline[(v, a)] = list(
                        reversed(polyline_uv[idx_a:]))
                    # wx -> wb + bx (and flipped)
                    polyline_wx = edges_to_polyline[(w, x)]
                    del edges_to_polyline[(w, x)]
                    del edges_to_polyline[(x, w)]
                    idx_b = polyline_wx.index([xb, yb, zb])
                    edges_to_polyline[(w, b)] = polyline_wx[:idx_b + 1]
                    edges_to_polyline[(b, w)] = list(
                        reversed(polyline_wx[:idx_b + 1]))
                    edges_to_polyline[(b, x)] = polyline_wx[idx_b:]
                    edges_to_polyline[(x, b)] = list(
                        reversed(polyline_wx[idx_b:]))
                    # zy -> zc + yc (and flipped)
                    polyline_zy = edges_to_polyline[(z, y)]
                    del edges_to_polyline[(z, y)]
                    del edges_to_polyline[(y, z)]
                    idx_c = polyline_zy.index([xc, yc, zc])
                    edges_to_polyline[(z, c)] = polyline_zy[:idx_c + 1]
                    edges_to_polyline[(c, z)] = list(
                        reversed(polyline_zy[:idx_c + 1]))
                    edges_to_polyline[(c, y)] = polyline_zy[idx_c:]
                    edges_to_polyline[(y, c)] = list(
                        reversed(polyline_zy[idx_c:]))
                    # + ab + bc (and flipped)
                    edges_to_polyline[(a, b)] = [
                        patch_decomposition.vertex_coordinates(a),
                        patch_decomposition.vertex_coordinates(b)
                    ]
                    edges_to_polyline[(b, a)] = [
                        patch_decomposition.vertex_coordinates(b),
                        patch_decomposition.vertex_coordinates(a)
                    ]
                    edges_to_polyline[(b, c)] = [
                        patch_decomposition.vertex_coordinates(b),
                        patch_decomposition.vertex_coordinates(c)
                    ]
                    edges_to_polyline[(c, b)] = [
                        patch_decomposition.vertex_coordinates(c),
                        patch_decomposition.vertex_coordinates(b)
                    ]
                    # delete faces
                    patch_decomposition.delete_face(fkey)
                    patch_decomposition.delete_face(fkey_bis)
                    # add new faces
                    face_1 = patch_decomposition.add_face([u, a, b, x])
                    face_2 = patch_decomposition.add_face([a, v, w, b])
                    face_3 = patch_decomposition.add_face([b, w, z, c])
                    face_4 = patch_decomposition.add_face([b, c, y, x])
                    faces += [face_1, face_2, face_3, face_4]
                    break

    initial_vertices = list(patch_decomposition.vertices())

    # propagate across curve features
    if feature_polylines is not None:
        # store vertex keys on the polyline feature using the map of geometric keys
        feature_map = [
            geometric_key([float(x), float(y), float(z)])
            for polyline in feature_polylines for x, y, z in polyline
        ]
        vertices_on_feature = [
            vkey for vkey in patch_decomposition.vertices() if geometric_key(
                patch_decomposition.vertex_coordinates(vkey)) in feature_map
        ]

        # dictionary mapping vertex geometric keys to vertex indices
        vertex_map = {
            geometric_key(patch_decomposition.vertex_coordinates(vkey)): vkey
            for vkey in patch_decomposition.vertices()
        }

        count = patch_decomposition.number_of_faces() * 100

        while count > 0 and not patch_decomposition.is_quadmesh():
            count -= 1
            for fkey in patch_decomposition.faces():
                face_vertices = patch_decomposition.face_vertices(fkey)
                if len(face_vertices) > 4:
                    regular_vertices = []
                    for i in range(len(face_vertices)):
                        a = face_vertices[i - 2]
                        b = face_vertices[i - 1]
                        c = face_vertices[i]
                        if b in initial_vertices:
                            if b not in vertices_on_feature or a not in vertices_on_feature or c not in vertices_on_feature:
                                regular_vertices.append(b)
                    face_propagation(patch_decomposition, fkey,
                                     regular_vertices)
                    break

    return patch_decomposition

    # propagate across curve features
    if feature_polylines is not None:
        # store vertex keys on the polyline feature using the map of geometric keys
        feature_map = [
            geometric_key([float(x), float(y), float(z)])
            for polyline in feature_polylines for x, y, z in polyline
        ]
        vertices_on_feature = [
            vkey for vkey in patch_decomposition.vertices() if geometric_key(
                patch_decomposition.vertex_coordinates(vkey)) in feature_map
        ]

        # dictionary mapping vertex geometric keys to vertex indices
        vertex_map = {
            geometric_key(patch_decomposition.vertex_coordinates(vkey)): vkey
            for vkey in patch_decomposition.vertices()
        }

        # list of edges on curve features
        polyline_keys = [[
            geometric_key([float(x), float(y), float(z)])
            for x, y, z in polyline
        ] for polyline in feature_polylines]
        feature_edges = []
        for u, v in patch_decomposition.edges():
            u_key = geometric_key(patch_decomposition.vertex_coordinates(u))
            v_key = geometric_key(patch_decomposition.vertex_coordinates(v))
            for polyline in polyline_keys:
                if u_key in polyline and v_key in polyline:
                    feature_edges.append((u, v))
                    break

        # store face keys along the polyline
        faces_along_feature = []
        for vkey in vertices_on_feature:
            for fkey in patch_decomposition.vertex_faces(vkey):
                if fkey not in faces_along_feature:
                    faces_along_feature.append(fkey)

        for fkey in faces_along_feature:
            # check if face has not been deleted in-between
            if fkey not in list(patch_decomposition.faces()):
                continue
            face_vertices = patch_decomposition.face_vertices(fkey)
            # check if not quad patch
            if len(face_vertices) > 4:
                print 'to split'
                for u, v in patch_decomposition.face_halfedges(fkey):
                    # check where to make the split
                    if u not in vertices_on_feature and v in vertices_on_feature:
                        vkey = patch_decomposition.face_vertex_descendant(
                            fkey, v)
                        wkey = poly_poly_1(patch_decomposition, fkey, vkey)
                        faces_along_feature.append(
                            patch_decomposition.halfedge[wkey][vkey])
                        # update feature_edges
                        b = patch_decomposition.face_vertex_descendant(
                            patch_decomposition.halfedge[vkey][wkey], wkey)
                        c = patch_decomposition.face_vertex_ancestor(
                            patch_decomposition.halfedge[wkey][vkey], wkey)
                        if (b, c) in feature_edges or (c, b) in feature_edges:
                            if (b, c) in feature_edges:
                                feature_edges.remove((b, c))
                            else:
                                feature_edges.remove((c, b))
                            feature_edges.append((b, wkey))
                            feature_edges.append((wkey, c))
                        # propagate until boundary or closed loop
                        count = patch_decomposition.number_of_faces()
                        while count > 0:
                            count -= 1
                            next_fkey = patch_decomposition.halfedge[vkey][
                                wkey]
                            ukey = patch_decomposition.face_vertex_descendant(
                                next_fkey, wkey)
                            if wkey in patch_decomposition.halfedge[
                                    ukey] and patch_decomposition.halfedge[
                                        ukey][wkey] is not None:
                                next_fkey = patch_decomposition.halfedge[ukey][
                                    wkey]
                                print next_fkey
                                if len(
                                        patch_decomposition.face_vertices(
                                            next_fkey)) == 5:
                                    vkey = wkey
                                    old_neighbours = patch_decomposition.vertex_neighbors(
                                        vkey)
                                    wkey = penta_quad_1(
                                        patch_decomposition, next_fkey, wkey)
                                    print next_fkey
                                    original_vertices = patch_decomposition.face_vertices(
                                        next_fkey)
                                    original_vertices.remove(vkey)
                                    face_propagation(patch_decomposition,
                                                     next_fkey,
                                                     original_vertices)
                                    new_neighbours = patch_decomposition.vertex_neighbors(
                                        vkey)
                                    for nbr in new_neighbours:
                                        if nbr not in old_neighbours:
                                            wkey = nbr
                                            break
                                    # update feature_edges
                                    b = patch_decomposition.face_vertex_descendant(
                                        patch_decomposition.halfedge[vkey]
                                        [wkey], wkey)
                                    c = patch_decomposition.face_vertex_ancestor(
                                        patch_decomposition.halfedge[wkey]
                                        [vkey], wkey)
                                    if (b, c) in feature_edges or (
                                            c, b) in feature_edges:
                                        if (b, c) in feature_edges:
                                            feature_edges.remove((b, c))
                                        else:
                                            feature_edges.remove((c, b))
                                        feature_edges.append((b, wkey))
                                        feature_edges.append((wkey, c))
                                    # add to faces along feature to check
                                    faces_along_feature.append(
                                        patch_decomposition.halfedge[vkey]
                                        [wkey])
                                    faces_along_feature.append(
                                        patch_decomposition.halfedge[wkey]
                                        [vkey])
                                    continue
                                elif len(
                                        patch_decomposition.face_vertices(
                                            next_fkey)) == 6:
                                    vkey = wkey
                                    face_vertices = patch_decomposition.face_vertices(
                                        next_fkey)
                                    idx = face_vertices.index(vkey)
                                    wkey = face_vertices[idx - 3]
                                    wkey = hexa_quad_1(patch_decomposition,
                                                       next_fkey, wkey)
                                    original_vertices = patch_decomposition.face_vertices(
                                        next_fkey)
                                    original_vertices.remove(vkey)
                                    original_vertices.remove(wkey)
                                    face_propagation(patch_decomposition,
                                                     next_fkey,
                                                     original_vertices)
                                    # add to faces along feature to check
                                    faces_along_feature.append(
                                        patch_decomposition.halfedge[vkey]
                                        [wkey])
                                    faces_along_feature.append(
                                        patch_decomposition.halfedge[wkey]
                                        [vkey])
                                    break
                                #elif len(patch_decomposition.face_vertices(next_fkey)) == 4:
                                #        vkey = wkey
                                #        wkey = quad_tri_1(patch_decomposition, next_fkey, wkey)
                                #        # add to faces along feature to check
                                #        faces_along_feature.append(patch_decomposition.halfedge[vkey][wkey])
                                #        faces_along_feature.append(patch_decomposition.halfedge[wkey][vkey])
                                #        break
                            break

    return patch_decomposition
Пример #12
0
def offset_polygon(polygon, distance):
    """Offset a polygon (closed) by a distance.

    Parameters
    ----------
    polygon : list of point
        The XYZ coordinates of the corners of the polygon.
        The first and last coordinates must not be identical.
    distance : float or list of float
        The offset distance as float.
        A single value determines a constant offset globally.
        Alternatively, pairs of local offset values per line segment can be used to create variable offsets.
        Distance > 0: offset to the outside, distance < 0: offset to the inside.

    Returns
    -------
    offset polygon : list of point
        The XYZ coordinates of the corners of the offset polygon.
        The first and last coordinates are identical.

    Notes
    -----
    The offset direction is determined by the normal of the polygon.
    If the polygon is in the XY plane and the normal is along the positive Z axis,
    positive offset distances will result in an offset towards the inside of the
    polygon.

    The algorithm works also for spatial polygons that do not perfectly fit a plane.

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

        polygon = [
            (0.0, 0.0, 0.0),
            (3.0, 0.0, 1.0),
            (3.0, 3.0, 2.0),
            (1.5, 1.5, 2.0),
            (0.0, 3.0, 1.0),
            (0.0, 0.0, 0.0)
            ]

        distance = 0.5 # constant offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

        distance = [
            (0.1, 0.2),
            (0.2, 0.3),
            (0.3, 0.4),
            (0.4, 0.3),
            (0.3, 0.1)
            ] # variable offset
        polygon_offset = offset_polygon(polygon, distance)
        print(polygon_offset)

    """
    p = len(polygon)

    if isinstance(distance, (list, tuple)):
        distances = distance
    else:
        distances = [distance] * p

    d = len(distances)
    if d < p:
        distances.extend(distances[-1:] * (p - d))

    normal = normal_polygon(polygon)

    offset = []
    for line, distance in zip(pairwise(polygon + polygon[:1]), distances):
        offset.append(offset_line(line, distance, normal))

    points = []
    for l1, l2 in pairwise(offset[-1:] + offset):
        x1, x2 = intersection_line_line(l1, l2)
        if x1 and x2:
            points.append(centroid_points([x1, x2]))
        else:
            points.append(x1)

    return points