def branches_splitting_flipped_faces(self):
        """Add new branches to fix the problem of polyline patches that would form flipped faces in the decomposition mesh.

		Returns
		-------
		new_branches : list
			List of polylines as list of point XYZ-coordinates.

		"""

        new_branches = []
        centre_to_fkey = {
            geometric_key(trimesh_face_circle(self, fkey)[0]): fkey
            for fkey in self.faces()
        }

        # compute total rotation of polyline
        for polyline in self.branches_singularity_to_singularity():
            angles = [
                angle_vectors_signed(subtract_vectors(v, u),
                                     subtract_vectors(w, v), [0., 0., 1.])
                for u, v, w in window(polyline, n=3)
            ]
            # subdivide once per angle limit in rotation
            if abs(sum(angles)) > self.flip_angle_limit:
                # the step between subdivision points in polylines (+ 2 for the extremities, which will be discarded)
                alone = len(self.compas_singular_faces()) == 0
                n = floor(abs(sum(angles)) / self.flip_angle_limit) + 1
                step = int(floor(len(polyline) / n))
                # add new branches from corresponding face in Delaunay mesh
                seams = polyline[::step]
                if polyline[-1] != seams[-1]:
                    if len(seams) == n + 1:
                        del seams[-1]
                    seams.append(polyline[-1])
                if alone:
                    seams = seams[0:-1]
                else:
                    seams = seams[1:-1]
                for point in seams:
                    fkey = centre_to_fkey[geometric_key(point)]
                    for edge in self.face_halfedges(fkey):
                        if not self.is_edge_on_boundary(*edge):
                            new_branches += [[
                                trimesh_face_circle(self, fkey)[0],
                                self.vertex_coordinates(vkey)
                            ] for vkey in edge]
                            break

        return new_branches
    def lines(self):
        """Get the lines forming the topological skeleton, i.e. the lines connecting the circumcentres of adjacent faces.

		Returns
		-------
		list
			List of lines as tuples of pairs XYZ-coordinates.

		"""

        return [(trimesh_face_circle(self,
                                     fkey)[0], trimesh_face_circle(self,
                                                                   nbr)[0])
                for fkey in self.faces() for nbr in self.face_neighbors(fkey)
                if fkey < nbr
                and geometric_key(trimesh_face_circle(self, fkey)[0]) !=
                geometric_key(trimesh_face_circle(self, nbr)[0])]
Beispiel #3
0
	def branches_singularity_to_boundary(self):
		"""Get new branch polylines between singularities and boundaries, at the location fo the split vertices. Not part of the topological skeleton.

		Returns
		-------
		list
			List of polylines as list of point XYZ-coordinates.

		"""

		return [[trimesh_face_circle(self, fkey)[0], self.vertex_coordinates(vkey)] for fkey in self.compas_singular_faces() for vkey in self.face_vertices(fkey)]
def boundary_triangulation(outer_boundary, inner_boundaries, polyline_features = [], point_features = [], src='numpy_rpc'):
	"""Generate Delaunay triangulation between a planar outer boundary and planar inner boundaries. All vertices lie the boundaries.

	Parameters
	----------
	outer_boundary : list
		Planar outer boundary as list of vertex coordinates.
	inner_boundaries : list
		List of planar inner boundaries as lists of vertex coordinates.
	polyline_features : list
		List of planar polyline_features as lists of vertex coordinates.
	point_features : list
		List of planar point_features as lists of vertex coordinates.
	src : str
		Source of Delaunay triangulation. Default is NumPy via RPC.

	Returns
	-------
	delaunay_mesh : Mesh
		The Delaunay mesh.

	"""

	# generate planar Delaunay triangulation
	vertices = [pt for boundary in [outer_boundary] + inner_boundaries + polyline_features for pt in boundary] + point_features
	if src == 'numpy_rpc':
		faces = delaunay_numpy_rpc(vertices)
	elif src == 'numpy':
		faces = delaunay_numpy(vertices)
	else:
		delaunay_compas(vertices)
	
	delaunay_mesh = Mesh.from_vertices_and_faces(vertices, faces)
	
	# delete false faces with aligned vertices
	for fkey in list(delaunay_mesh.faces()):
		a, b, c = [delaunay_mesh.vertex_coordinates(vkey) for vkey in delaunay_mesh.face_vertices(fkey)]
		ab = subtract_vectors(b, a)
		ac = subtract_vectors(c, a)
		if length_vector(cross_vectors(ab, ac)) == 0:
			delaunay_mesh.delete_face(fkey)

	# delete faces outisde the borders
	for fkey in list(delaunay_mesh.faces()):
		centre = trimesh_face_circle(delaunay_mesh, fkey)[0]
		if not is_point_in_polygon_xy(centre, outer_boundary) or any([is_point_in_polygon_xy(centre, inner_boundary) for inner_boundary in inner_boundaries]):
			delaunay_mesh.delete_face(fkey)

	# topological cut along the feature polylines through unwelding
	vertex_map = {geometric_key(delaunay_mesh.vertex_coordinates(vkey)): vkey for vkey in delaunay_mesh.vertices()}
	edges = [edge for polyline in polyline_features for edge in pairwise([vertex_map[geometric_key(point)] for point in polyline])]
	mesh_unweld_edges(delaunay_mesh, edges)

	return delaunay_mesh
Beispiel #5
0
	def branches_singularity_to_singularity(self):
		"""Get the branch polylines of the topological skeleton between singularities only, not corners.

		Returns
		-------
		list
			List of polylines as list of point XYZ-coordinates.

		"""

		map_corners = [geometric_key(trimesh_face_circle(self, corner)[0]) for corner in self.corner_faces()]
		return [branch for branch in self.branches() if geometric_key(branch[0]) not in map_corners and geometric_key(branch[-1]) not in map_corners]
    def branches_splitting_collapsed_boundaries(self):
        """Add new branches to fix the problem of boundaries with less than three splits that would be collapsed in the decomposition mesh.

		Returns
		-------
		new_branches : list
			List of polylines as list of point XYZ-coordinates.

		"""

        new_branches = []

        all_splits = set(
            list(self.corner_vertices()) + list(self.split_vertices()))

        for polyedge in [bdry + bdry[:1] for bdry in self.boundaries()]:

            splits = set([vkey for vkey in polyedge if vkey in all_splits])
            new_splits = []

            if len(splits) == 0:
                new_splits += [
                    vkey for vkey in list(
                        itemgetter(0, int(floor(len(polyedge) / 3)),
                                   int(floor(len(polyedge) * 2 /
                                             3)))(polyedge))
                ]

            elif len(splits) == 1:
                i = polyedge.index(splits[0])
                new_splits += list(
                    itemgetter(i - int(floor(len(polyedge) * 2 / 3)),
                               i - int(floor(len(polyedge) / 3)))(polyedge))

            elif len(splits) == 2:
                one, two = list_split(
                    polyedge, [polyedge.index(vkey) for vkey in splits])
                half = one if len(one) > len(two) else two
                new_splits.append(half[int(floor(len(half) / 2))])

            for vkey in new_splits:
                fkey = list(self.vertex_faces(vkey))[0]
                for edge in self.face_halfedges(fkey):
                    if vkey in edge and not self.is_edge_on_boundary(*edge):
                        new_branches += [[
                            trimesh_face_circle(self, fkey)[0],
                            self.vertex_coordinates(vkey_2)
                        ] for vkey_2 in edge]
                        all_splits.update(edge)
                        break

        return new_branches
    def compas_singular_points(self):
        """Get the XYZ-coordinates of the compas_singular points of the topological skeleton, i.e. the face circumcentre of the compas_singular faces.

		Returns
		-------
		list
			List of point XYZ-coordinates.

		"""

        return [
            trimesh_face_circle(self, fkey)[0]
            for fkey in self.compas_singular_faces()
        ]
    def branches_splitting_boundary_kinks(self):
        """Add new branches to fix the problem of boundary kinks not marked by the skeleton
		Due to a low density that did not spot the change of curvature at the kink.
		Does not modify the singularites on the contrarty to increasing the density.

		Returns
		-------
		new_branches : list
			List of polylines as list of point XYZ-coordinates.

		"""

        new_branches = []

        compas_singular_faces = set(self.compas_singular_faces())
        for boundary in self.boundaries():
            angles = {(u, v, w): angle_vectors(
                subtract_vectors(self.vertex_coordinates(v),
                                 self.vertex_coordinates(u)),
                subtract_vectors(self.vertex_coordinates(w),
                                 self.vertex_coordinates(v)))
                      for u, v, w in window(boundary + boundary[:2], n=3)}
            for u, v, w, x, y in list(window(boundary + boundary[:4], n=5)):

                # check if not a corner
                if self.vertex_degree(w) == 2:
                    continue

                angle = angles[(v, w, x)]
                adjacent_angles = (angles[(u, v, w)] + angles[(w, x, y)]) / 2

                if angle - adjacent_angles > self.relative_kink_angle_limit:
                    # check if not already marked via an adjacent compas_singular face
                    if all([
                            fkey not in compas_singular_faces
                            for fkey in self.vertex_faces(w)
                    ]):
                        fkeys = list(self.vertex_faces(w, ordered=True))
                        fkey = fkeys[int(floor(len(fkeys) / 2))]
                        for edge in self.face_halfedges(fkey):
                            if w in edge and not self.is_edge_on_boundary(
                                    *edge):
                                new_branches += [[
                                    trimesh_face_circle(self, fkey)[0],
                                    self.vertex_coordinates(vkey)
                                ] for vkey in edge]
                                break

        return new_branches