Example #1
0
def gh_surface_decomposition(surface_guid, accuracy_value, point_guids, curve_guids):

	if point_guids == [None]:
		point_guids = []
	if curve_guids == [None]:
		curve_guids = []

	outer_boundary, inner_boundaries, polyline_features, point_features = surface_discrete_mapping(surface_guid, accuracy_value, crv_guids = curve_guids, pt_guids = point_guids)
	tri_mesh = boundary_triangulation(outer_boundary, inner_boundaries, polyline_features, point_features)
	decomposition = SkeletonDecomposition.from_mesh(tri_mesh)
	quad_mesh = decomposition.decomposition_mesh(point_features)
	RhinoSurface.from_guid(surface_guid).mesh_uv_to_xyz(quad_mesh)
	return quad_mesh
Example #2
0
def surface_discrete_mapping(srf_guid, discretisation, minimum_discretisation = 5, crv_guids = [], pt_guids = []):
	"""Map the boundaries of a Rhino NURBS surface to planar poylines dicretised within some discretisation using the surface UV parameterisation.
	Curve and point feautres on the surface can be included.
	Parameters
	----------
	srf_guid : guid
		A surface guid.
	crv_guids : list
		List of guids of curves on the surface.
	pt_guids : list
		List of guids of points on the surface.
	discretisation : float
		The discretisation of the surface boundaries.
	minimum_discretisation : int
		The minimum discretisation of the surface boundaries.
	Returns
	-------
	tuple
		Tuple of the mapped objects: outer boundary, inner boundaries, polyline_features, point_features.
	"""

	srf = RhinoSurface.from_guid(srf_guid)

	# a boundary may be made of multiple boundary components and therefore checking for closeness and joining are necessary
	mapped_borders = []

	for i in [1, 2]:
		mapped_border = []

		for border_guid in srf.borders(type = i):
			points = [list(srf.point_xyz_to_uv(pt)) + [0.0] for pt in rs.DivideCurve(border_guid, max(int(rs.CurveLength(border_guid) / discretisation) + 1, minimum_discretisation))]
			
			if rs.IsCurveClosed(border_guid):
				points.append(points[0])
			
			mapped_border.append(points)
			rs.DeleteObject(border_guid)
		mapped_borders.append(mapped_border)

	outer_boundaries, inner_boundaries = [network_polylines(Network.from_lines([(u, v) for border in mapped_borders[i] for u, v in pairwise(border)])) for i in [0, 1]]
	
	# mapping of the curve features on the surface
	mapped_curves = []

	for crv_guid in crv_guids:

		curve = RhinoCurve.from_guid(crv_guid)
		points = [list(srf.point_xyz_to_uv(pt)) + [0.0] for pt in curve.divide(max(int(curve.length() / discretisation) + 1, minimum_discretisation))]
		
		if curve.is_closed():
			points.append(points[0])
		
		mapped_curves.append(points)

	polyline_features = network_polylines(Network.from_lines([(u, v) for curve in mapped_curves for u, v in pairwise(curve)]))

	# mapping of the point features onthe surface
	point_features = [list(srf.point_xyz_to_uv(rs.PointCoordinates(pt_guid))) + [0.0] for pt_guid in pt_guids]

	return outer_boundaries[0], inner_boundaries, polyline_features, point_features
def automated_smoothing_surface_constraints(mesh, surface):
	"""Apply automatically surface-related constraints to the vertices of a mesh to smooth: kinks, boundaries and surface.

	Parameters
	----------
	mesh : Mesh
		The mesh to apply the constraints to for smoothing.
	surface : Rhino surface guid
		A Rhino surface guid on which to constrain mesh vertices.

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

	"""

	surface = RhinoSurface.from_guid(surface)
	constraints = {}

	points = [rs.AddPoint(point) for point in surface.kinks()]
	curves = surface.borders(type = 0)

	constraints.update({vkey: surface.guid for vkey in mesh.vertices()})

	for vkey in mesh.vertices_on_boundary():
		xyz = mesh.vertex_coordinates(vkey)
		projections = {curve: distance_point_point(xyz, RhinoCurve.from_guid(curve).closest_point(xyz)) for curve in curves}
		constraints.update({vkey: min(projections, key = projections.get)})

	key_to_index = {i: vkey for i, vkey in enumerate(mesh.vertices_on_boundary())}
	vertex_coordinates = tuple(mesh.vertex_coordinates(vkey) for vkey in mesh.vertices_on_boundary())
	constraints.update({key_to_index[closest_point_in_cloud(rs.PointCoordinates(point), vertex_coordinates)[2]]: point for point in points})
	
	return constraints
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 Rhino curve guids on which to constrain mesh vertices. Default is None.
	surface : Rhino surface guid
		A Rhino surface guid on which to constrain mesh vertices. Default is None.
	mesh2 : Rhino mesh guid
		A Rhino mesh guid 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.

	"""

	if surface:
		surface = RhinoSurface.from_guid(surface)
	if curves:
		curves = [RhinoCurve.from_guid(curve) for curve in curves]
	if mesh2:
		mesh2 = RhinoMesh.from_guid(mesh2)

	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.guid for vkey in mesh.vertices()})

	if surface is not None:
		constraints.update({vkey: surface.guid 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]].guid for i, boundary in enumerate(boundaries) for vkey in boundary})
	
	if points is not None:
		constraints.update(constrained_vertices)

	return constraints
Example #5
0
def gh_surface_skeleton(surface_guid, accuracy_value, point_guids, curve_guids):

	if point_guids == [None]:
		point_guids = []
	if curve_guids == [None]:
		curve_guids = []

	outer_boundary, inner_boundaries, polyline_features, point_features = surface_discrete_mapping(surface_guid, accuracy_value, crv_guids = curve_guids, pt_guids = point_guids)
	tri_mesh = boundary_triangulation(outer_boundary, inner_boundaries, polyline_features, point_features)
	skeleton = Skeleton.from_mesh(tri_mesh)
	branches = skeleton.branches()
	polylines = [rs.AddPolyline(RhinoSurface.from_guid(surface_guid).polyline_uv_to_xyz([point[:2] for point in branch])) for branch in branches]
	return polylines
def customized_smoothing_constraints(mesh, constraints):
    """Add custom 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.
	constraints : dict
		A dictionary of mesh constraints for smoothing as vertex keys pointing to point, curve or surface objects.

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

	"""

    while True:

        guids = display_smoothing_constraints(mesh, constraints)
        vkeys = mesh_select_vertices(mesh)
        if len(vkeys) == 2 and rs.GetString(
                'get all polyedge?', strings=['True', 'False']) == 'True':
            u, v = vkeys
            vkeys = mesh.polyedge(u, v)

        if vkeys is None:
            break

        constraint = rs.GetString(
            'edit smoothing constraints?',
            strings=['point', 'curve', 'surface', 'exit'])

        rs.DeleteObjects(guids)

        if constraint is None or constraint == 'exit':
            break

        elif constraint == 'point':
            point = RhinoPoint.from_selection()
            constraints.update({vkey: point.guid for vkey in vkeys})

        elif constraint == 'curve':
            curve = RhinoCurve.from_selection()
            constraints.update({vkey: curve.guid for vkey in vkeys})

        elif constraint == 'surface':
            surface = RhinoSurface.from_selection()
            constraints.update({vkey: surface.guid for vkey in vkeys})

    return constraints
    def callback(k, args):

        mesh, constraints = args

        for vkey, constraint in constraints.items():
            if constraint is None:
                continue
            elif rs.ObjectType(constraint) == 1:
                x, y, z = RhinoPoint.from_guid(constraint).xyz
            elif rs.ObjectType(constraint) == 4:
                x, y, z = RhinoCurve.from_guid(constraint).closest_point(
                    mesh.vertex_coordinates(vkey))
            elif rs.ObjectType(constraint) == 8:
                x, y, z = RhinoSurface.from_guid(constraint).closest_point(
                    mesh.vertex_coordinates(vkey))
            elif rs.ObjectType(constraint) == 32:
                x, y, z = RhinoMesh.from_guid(constraint).closest_point(
                    mesh.vertex_coordinates(vkey))
            else:
                continue

            mesh.vertex[vkey]['x'] = x
            mesh.vertex[vkey]['y'] = y
            mesh.vertex[vkey]['z'] = z
def RunCommand(is_interactive):
    scene = get_scene()
    if not scene:
        return

    proxy = get_proxy()
    if not proxy:
        return

    delaunay = proxy.function('compas.geometry.delaunay_from_points_numpy')

    # Get input data.
    surf_guid = compas_rhino.select_surface("Select a surface to decompose.")
    if not surf_guid:
        return
    point_guids = compas_rhino.select_points(
        "Select points to include in the decomposition.")
    curve_guids = []

    compas_rhino.rs.HideObjects([surf_guid] + point_guids + curve_guids)

    surface = RhinoSurface.from_guid(surf_guid)
    curves = [RhinoCurve.from_guid(guid) for guid in curve_guids]
    points = [RhinoPoint.from_guid(guid) for guid in point_guids]

    # Compute the feature discretisation length.
    box = compas_rhino.rs.BoundingBox([surf_guid])
    diagonal = compas_rhino.rs.Distance(box[0], box[6])
    D = 0.05 * diagonal

    # Get the target length for the final quad mesh.
    L = compas_rhino.rs.GetReal(
        "Define the target edge length of the pattern.", 1.0)

    # Generate the pattern
    pattern = Pattern.from_surface_and_features(D,
                                                L,
                                                surf_guid,
                                                curve_guids,
                                                point_guids,
                                                delaunay=delaunay)

    scene.clear()
    scene.add(pattern, name='pattern')
    scene.update()

    kmax = 10

    # Constrain mesh components to the feature geometry.
    constraints = automated_smoothing_surface_constraints(pattern, surface)
    constraints.update(
        automated_smoothing_constraints(pattern,
                                        rhinopoints=points,
                                        rhinocurves=curves))

    while True:
        option = compas_rhino.rs.GetString("Smoothen the pattern?", "No",
                                           ["Yes", "No"])
        if not option:
            break
        if option != "Yes":
            break

        constrained_smoothing(pattern,
                              kmax=kmax,
                              damping=0.5,
                              constraints=constraints,
                              algorithm="area")
        scene.update()

    print('Pattern object successfully created. Input object has been hidden.')
Example #9
0
    def from_surface_and_features(cls,
                                  discretisation,
                                  target_edge_length,
                                  surf_guid,
                                  curve_guids=[],
                                  point_guids=[],
                                  delaunay=None):
        """Get a pattern object from a NURBS surface with optional point and curve features on the surface.
        The pattern is aligned to the surface boundaries and curve features.
        The pattern contains a pole singularity at the feature points. Pole singularities are a specific type of singularity.

        Parameters
        ----------
        discretisation : float
            The surface boundary and curve feature discretisation length.
            Values between 1% and 5% of the length of the diagonal of the bounding box are recommended.
        target_edge_length : float
            The edge target length for densification.
        surf_guid : str
            A Rhino surface guid.
        curves : list of str, optional
            A list of Rhino curve guids.
        points : list of str, optional
            A list of Rhino point guids.

        Returns
        -------
        Pattern
            A Pattern object.

        References
        ----------
        Based on [1]_ and [2]_.

        .. [1] Oval et al. *Feature-based topology finding of patterns for shell structures*. Automation in Construction, 2019.
               Available at: https://www.researchgate.net/publication/331064073_Feature-based_Topology_Finding_of_Patterns_for_Shell_Structures.
        .. [2] Oval. *Topology finding of patterns for structural design*. PhD thesis, Unversite Paris-Est, 2019.
               Available at: https://www.researchgate.net/publication/340096530_Topology_Finding_of_Patterns_for_Structural_Design.

        """
        from compas_singular.rhino import RhinoSurface

        AddInterpCrvOnSrfUV = compas_rhino.rs.AddInterpCrvOnSrfUV
        compas_rhino.rs.EnableRedraw(False)
        surface = RhinoSurface.from_guid(surf_guid)
        result = surface.discrete_mapping(discretisation,
                                          crv_guids=curve_guids,
                                          pt_guids=point_guids)
        outer_boundary, inner_boundaries, polyline_features, point_features = result
        trimesh = boundary_triangulation(*result, delaunay=delaunay)
        decomposition = SkeletonDecomposition.from_mesh(trimesh)
        coarsemesh = decomposition.decomposition_mesh(point_features)
        gkey_vertex = {
            geometric_key(coarsemesh.vertex_coordinates(vertex)): vertex
            for vertex in coarsemesh.vertices()
        }
        edge_curve = {}
        for polyline in decomposition.polylines:
            a = geometric_key(polyline[0])
            b = geometric_key(polyline[-1])
            u = gkey_vertex[a]
            v = gkey_vertex[b]
            points = [point[:2] for point in polyline]
            curve = AddInterpCrvOnSrfUV(surf_guid, points)
            edge_curve[u, v] = curve
        coarsemesh.collect_strips()
        coarsemesh.set_strips_density_target(target_edge_length)
        coarsemesh.densification(edges_to_curves=edge_curve)
        compas_rhino.delete_objects(edge_curve.values(), purge=True)
        densemesh = coarsemesh.get_quad_mesh()
        compas_rhino.rs.EnableRedraw(True)
        compas_rhino.rs.Redraw()
        return cls.from_vertices_and_faces(*densemesh.to_vertices_and_faces())