Пример #1
0
    def singularity_polyedges(self):
        """Collect the polyedges connected to singularities.

        Returns
        -------
        list
            The polyedges connected to singularities.

        """

        poles = set(self.poles())
        # keep only polyedges connected to singularities or along the boundary
        polyedges = [
            polyedge for key, polyedge in self.polyedges(data=True)
            if (self.is_vertex_singular(polyedge[0])
                and not self.is_pole(polyedge[0])) or (self.is_vertex_singular(
                    polyedge[-1]) and not self.is_pole(polyedge[-1]))
            or self.is_edge_on_boundary(polyedge[0], polyedge[1])
        ]

        # get intersections between polyedges for split
        vertices = [vkey for polyedge in polyedges for vkey in set(polyedge)]
        split_vertices = [
            vkey for vkey in self.vertices() if vertices.count(vkey) > 1
        ]

        # split singularity polyedges
        return [
            split_polyedge for polyedge in polyedges
            for split_polyedge in list_split(polyedge, [
                polyedge.index(vkey)
                for vkey in split_vertices if vkey in polyedge
            ])
        ]
def quadrangulate_face(mesh, fkey, sources):

	face_vertices = mesh.face_vertices(fkey)[:]

	# differentiate sources and non sources
	sources = [vkey for vkey in face_vertices if vkey in sources]
	non_sources = [vkey for vkey in face_vertices if vkey not in sources]
	new_sources = []

	if len(non_sources) == 4:
		a, b, c, d = non_sources
		ab, bc, cd, da = list_split(face_vertices + face_vertices[:1], [face_vertices.index(vkey) for vkey in non_sources])
		# add missing vertices
		for i, edges in enumerate([[ab, cd], [bc, da]]):
			uv, wx = edges
			# all cases
			
			if len(uv) == len(wx):
				# no subdivision needed
				continue
			
			elif len(uv) == 2 and len(wx) != 2:
				# subdivide uv
				n = len(wx) - len(uv) + 1
				new_points = [mesh.edge_point(uv[0], uv[1], float(k) / float(n)) for k in range(n + 1)][1 : -1]
				new_vertices = [mesh.add_vertex(attr_dict={xyz: value for xyz, value in zip(['x', 'y', 'z'], point)}) for point in new_points]
				new_sources += new_vertices
				if i == 0:
					ab = [uv[0]] + new_vertices + [uv[-1]]
				elif i == 1:
					bc = [uv[0]] + new_vertices + [uv[-1]]
				update_adjacent_face(mesh, uv[1], uv[0], list(reversed(new_vertices)))
			elif len(uv) != 2 and len(wx) == 2:
				# subdivide wx
				n = len(uv) - len(wx) + 1
				new_points = [mesh.edge_point(wx[0], wx[1], float(k) / float(n)) for k in range(n + 1)][1 : -1]
				new_vertices = [mesh.add_vertex(attr_dict={xyz: value for xyz, value in zip(['x', 'y', 'z'], point)}) for point in new_points]
				new_sources += new_vertices
				if i == 0:
					cd = [wx[0]] + new_vertices + [wx[-1]]
				elif i == 1:
					da = [wx[0]] + new_vertices + [wx[-1]]
				# update adjacent faces
				update_adjacent_face(mesh, wx[1], wx[0], list(reversed(new_vertices)))
			elif len(uv) != 2 and len(wx) != 2 and len(uv) != len(wx):
				pass
				# apply Takayama's work
				#print('not implemented yet')

		mesh.delete_face(fkey)

		discrete_coons_patch_mesh(mesh, ab, bc, list(reversed(cd)), list(reversed(da)))

	else:
		pass
		#print('not generalised yet')

	return new_sources
    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 branches_boundary(self):
        """Get new branch polylines from the Delaunay mesh boundaries split at the corner and plit vertices. Not part of the topological skeleton.

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

		"""

        boundaries = [bdry + bdry[0:] for bdry in self.boundaries()]
        splits = self.corner_vertices() + self.split_vertices()
        split_boundaries = [
            split_boundary for boundary in boundaries
            for split_boundary in list_split(boundary, [
                boundary.index(split) for split in splits if split in boundary
            ])
        ]
        return [[self.vertex_coordinates(vkey) for vkey in boundary]
                for boundary in split_boundaries]
Пример #5
0
def automated_smoothing_constraints(mesh,
                                    points=None,
                                    curves=None,
                                    surface=None,
                                    mesh2=None):
    """Apply automatically point, curve and surface constraints to the vertices of a mesh to smooth.

	Parameters
	----------
	mesh : Mesh
		The mesh to apply the constraints to for smoothing.
	points : list
		List of XYZ coordinates on which to constrain mesh vertices. Default is None.
	curves : list
		List of RhinoCurve objects on which to constrain mesh vertices. Default is None.
	surface : RhinoSurface
		A RhinoSurface object on which to constrain mesh vertices. Default is None.
	mesh2 : RhinoMesh
		A RhinoMesh object on which to constrain mesh vertices. Default is None.

	Returns
	-------
	constraints : dict
		A dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects.

	"""

    constraints = {}
    constrained_vertices = {}

    vertices = list(mesh.vertices())
    vertex_coordinates = [
        mesh.vertex_coordinates(vkey) for vkey in mesh.vertices()
    ]

    if points is not None and len(points) != 0:
        constrained_vertices.update({
            vertices[closest_point_in_cloud(rs.PointCoordinates(point),
                                            vertex_coordinates)[2]]: point
            for point in points
        })

    if mesh2 is not None:
        constraints.update({vkey: mesh2 for vkey in mesh.vertices()})

    if surface is not None:
        constraints.update({vkey: surface for vkey in mesh.vertices()})

    if curves is not None and len(curves) != 0:
        boundaries = [
            split_boundary for boundary in mesh.boundaries()
            for split_boundary in list_split(boundary, [
                boundary.index(vkey)
                for vkey in constrained_vertices.keys() if vkey in boundary
            ])
        ]
        boundary_midpoints = [
            Polyline([mesh.vertex_coordinates(vkey)
                      for vkey in boundary]).point(t=.5)
            for boundary in boundaries
        ]
        curve_midpoints = [
            rs.EvaluateCurve(curve, rs.CurveParameter(curve, .5))
            for curve in curves
        ]
        midpoint_map = {
            i: closest_point_in_cloud(boundary_midpoint, curve_midpoints)[2]
            for i, boundary_midpoint in enumerate(boundary_midpoints)
        }
        constraints.update({
            vkey: curves[midpoint_map[i]]
            for i, boundary in enumerate(boundaries) for vkey in boundary
        })

    if points is not None:
        constraints.update(constrained_vertices)

    return constraints
Пример #6
0
    def singularity_polyedge_decomposition(self):
        """Returns a quad patch decomposition of the mesh based on the singularity polyedges, including boundaries and additionnal splits on the boundaries.

		Returns
		-------
		list
			The polyedges forming the decomposition.

		"""
        if self.data['attributes']['polyedges'] == {}:
            self.collect_polyedges()

        polyedges = [
            polyedge for key, polyedge in self.polyedges(data=True)
            if (self.is_vertex_singular(polyedge[0])
                or self.is_vertex_singular(polyedge[-1]))
            and not self.is_edge_on_boundary(polyedge[0], polyedge[1])
        ]

        # split boundaries
        all_splits = list(
            set([vkey for polyedge in polyedges
                 for vkey in polyedge] + self.singularities()))

        for boundary in self.boundaries():
            splits = [vkey for vkey in boundary if vkey in all_splits]
            new_splits = []

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

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

            elif len(splits) == 2:
                one, two = list_split(
                    boundary + boundary[:1],
                    [boundary.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:
                for nbr in self.vertex_neighbors(vkey):
                    if not self.is_edge_on_boundary(vkey, nbr):
                        new_polyedge = self.collect_polyedge(vkey, nbr)
                        polyedges.append(new_polyedge)
                        all_splits = list(set(all_splits + new_polyedge))
                        break

        # add boundaries
        polyedges += [
            polyedge for key, polyedge in self.polyedges(data=True)
            if self.is_edge_on_boundary(polyedge[0], polyedge[1])
        ]

        # get intersections between polyedges for split
        vertices = [vkey for polyedge in polyedges for vkey in set(polyedge)]
        split_vertices = [
            vkey for vkey in self.vertices() if vertices.count(vkey) > 1
        ]

        # split singularity polyedges
        return [
            split_polyedge for polyedge in polyedges
            for split_polyedge in list_split(polyedge, [
                polyedge.index(vkey)
                for vkey in split_vertices if vkey in polyedge
            ])
        ]
def func_1(mesh, fix_xyz, kmax, damping):
    # geometrical processing: smooth to widen the strip with constraints at
    # kinks and along boundaries

    def callback(k, args):

        mesh, fixed, split_boundaries, split_boundaries_geom = args

        for vkey in mesh.vertices_on_boundary():
            if vkey not in fixed:
                for i, boundary in enumerate(split_boundaries):
                    if vkey in boundary:
                        xyz, dist = closest_point_on_polyline(
                            split_boundaries_geom[i],
                            mesh.vertex_coordinates(vkey))
                        attr = mesh.vertex[vkey]
                        attr['x'], attr['y'], attr['z'] = xyz
                        break

    fix_map = {geometric_key(xyz): [] for xyz in fix_xyz}
    for vkey in mesh.vertices():
        geom_key = geometric_key(mesh.vertex_coordinates(vkey))
        if geom_key in fix_map:
            fix_map[geom_key].append(vkey)

    fixed = []
    for vertices in fix_map.values():
        boundary_vertices = [
            vkey for vkey in vertices if mesh.is_vertex_on_boundary(vkey)
        ]
        if len(boundary_vertices) == 0:
            print('not adapted to fixed non-boundary vertices')
        elif len(boundary_vertices) == 1:
            fixed += boundary_vertices
        else:
            corner_vertices = [
                vkey for vkey in boundary_vertices
                if mesh.vertex_degree(vkey) == 2
            ]
            if len(corner_vertices) == 1:
                fixed += corner_vertices
            else:
                pass
                #print('not generalised yet')

    split_boundaries = []
    for boundary in mesh.boundaries():
        boundary.append(boundary[0])
        indices = [boundary.index(vkey) for vkey in fixed if vkey in boundary]
        split_boundaries += list_split(boundary, indices)
    split_boundaries_geom = {
        i: [mesh.vertex_coordinates(vkey) for vkey in boundary]
        for i, boundary in enumerate(split_boundaries)
    }

    callback_args = mesh, fixed, split_boundaries, split_boundaries_geom
    mesh_smooth_centroid(mesh,
                         fixed,
                         kmax=kmax,
                         damping=damping,
                         callback=callback,
                         callback_args=callback_args)