|
| 1 | +from typing import Optional |
| 2 | + |
| 3 | +import rhinoscriptsyntax as rs # type: ignore |
| 4 | +from compas_skeleton.datastructures import Skeleton |
| 5 | +from compas_triangle.delaunay import conforming_delaunay_triangulation |
| 6 | +from compas_triangle.rhino import discretise_boundary |
| 7 | +from compas_triangle.rhino import discretise_constraints |
| 8 | + |
| 9 | +import compas_rhino |
| 10 | +import compas_rhino.conversions |
| 11 | +import compas_rhino.objects |
| 12 | +from compas.geometry import NurbsCurve |
| 13 | +from compas.geometry import Point |
| 14 | +from compas_rv.datastructures import Pattern |
| 15 | + |
| 16 | + |
| 17 | +def make_pattern_from_rhinolines() -> Optional[Pattern]: |
| 18 | + guids = compas_rhino.objects.select_lines("Select lines") |
| 19 | + if not guids: |
| 20 | + return |
| 21 | + |
| 22 | + lines = compas_rhino.objects.get_line_coordinates(guids) |
| 23 | + if not lines: |
| 24 | + return |
| 25 | + |
| 26 | + pattern: Pattern = Pattern.from_lines(lines, delete_boundary_face=True) # type: ignore |
| 27 | + |
| 28 | + rs.HideObjects(guids) |
| 29 | + |
| 30 | + return pattern |
| 31 | + |
| 32 | + |
| 33 | +def make_pattern_from_rhinomesh() -> Optional[Pattern]: |
| 34 | + guid = compas_rhino.objects.select_mesh("Select a mesh") |
| 35 | + if not guid: |
| 36 | + return |
| 37 | + |
| 38 | + obj = compas_rhino.objects.find_object(guid) |
| 39 | + pattern: Pattern = compas_rhino.conversions.mesh_to_compas(obj.Geometry, cls=Pattern) # type: ignore |
| 40 | + |
| 41 | + rs.HideObject(guid) |
| 42 | + |
| 43 | + return pattern |
| 44 | + |
| 45 | + |
| 46 | +def make_pattern_from_rhinosurface() -> Optional[Pattern]: |
| 47 | + guid = compas_rhino.objects.select_surface("Select a surface") |
| 48 | + if not guid: |
| 49 | + return |
| 50 | + |
| 51 | + U = rs.GetInteger(message="U faces", number=16, minimum=2, maximum=64) |
| 52 | + if not U: |
| 53 | + return |
| 54 | + |
| 55 | + V = rs.GetInteger(message="V faces", number=4, minimum=2, maximum=64) |
| 56 | + if not V: |
| 57 | + return |
| 58 | + |
| 59 | + obj = compas_rhino.objects.find_object(guid) |
| 60 | + brep = obj.Geometry |
| 61 | + surface = brep.Surfaces[0] |
| 62 | + pattern: Pattern = compas_rhino.conversions.surface_to_compas_mesh(surface, nu=U, nv=V, weld=True, cls=Pattern) # type: ignore |
| 63 | + |
| 64 | + rs.HideObject(guid) |
| 65 | + |
| 66 | + return pattern |
| 67 | + |
| 68 | + |
| 69 | +def make_pattern_from_meshgrid() -> Optional[Pattern]: |
| 70 | + DX = rs.GetInteger(message="X Size", number=10) |
| 71 | + if not DX: |
| 72 | + return |
| 73 | + |
| 74 | + DY = rs.GetInteger(message="Y Size", number=DX) |
| 75 | + if not DY: |
| 76 | + return |
| 77 | + |
| 78 | + NX = rs.GetInteger(message="Number of faces in X", number=10) |
| 79 | + if not NX: |
| 80 | + return |
| 81 | + |
| 82 | + NY = rs.GetInteger(message="Number of faces in Y", number=NX) |
| 83 | + if not NY: |
| 84 | + return |
| 85 | + |
| 86 | + pattern: Pattern = Pattern.from_meshgrid(dx=DX, nx=NX, dy=DY, ny=NY) # type: ignore |
| 87 | + return pattern |
| 88 | + |
| 89 | + |
| 90 | +def make_pattern_from_triangulation() -> Optional[Pattern]: |
| 91 | + boundary_guids = compas_rhino.objects.select_curves("Select outer boundary.") |
| 92 | + if not boundary_guids: |
| 93 | + return |
| 94 | + |
| 95 | + rs.UnselectAllObjects() |
| 96 | + hole_guids = compas_rhino.objects.select_curves("Select inner boundaries.") |
| 97 | + |
| 98 | + rs.UnselectAllObjects() |
| 99 | + segments_guids = compas_rhino.objects.select_curves("Select constraint curves.") |
| 100 | + |
| 101 | + rs.UnselectAllObjects() |
| 102 | + |
| 103 | + target_length = rs.GetReal("Specifiy target edge length.", 1.0) |
| 104 | + if not target_length: |
| 105 | + return |
| 106 | + |
| 107 | + boundary = discretise_boundary(boundary_guids, target_length) |
| 108 | + holes = None |
| 109 | + segments = None |
| 110 | + curves = None # type: ignore |
| 111 | + |
| 112 | + if hole_guids: |
| 113 | + holes = discretise_constraints(hole_guids, target_length) |
| 114 | + |
| 115 | + if segments_guids: |
| 116 | + segments = discretise_constraints(segments_guids, target_length) |
| 117 | + curves: list[NurbsCurve] = [NurbsCurve.from_interpolation(segment) for segment in segments] |
| 118 | + |
| 119 | + points, triangles = conforming_delaunay_triangulation( |
| 120 | + boundary, |
| 121 | + polylines=segments, |
| 122 | + polygons=holes, |
| 123 | + area=target_length**2 / 2, |
| 124 | + ) |
| 125 | + pattern = Pattern.from_vertices_and_faces(points, triangles) |
| 126 | + |
| 127 | + fixed = [vertex for boundary in pattern.vertices_on_boundaries() for vertex in boundary] |
| 128 | + if curves: |
| 129 | + for index, point in enumerate(points): |
| 130 | + for curve in curves: |
| 131 | + closest: Point = curve.closest_point(point) |
| 132 | + if closest.distance_to_point(point) < 0.1 * target_length: |
| 133 | + fixed.append(index) |
| 134 | + |
| 135 | + pattern.smooth_area(fixed=fixed) |
| 136 | + |
| 137 | + |
| 138 | +def make_pattern_from_skeleton() -> Optional[Pattern]: |
| 139 | + guids = compas_rhino.objects.select_lines("Select skeleton lines.") |
| 140 | + if not guids: |
| 141 | + return |
| 142 | + |
| 143 | + rs.UnselectAllObjects() |
| 144 | + |
| 145 | + width = rs.GetReal("Specifiy skeleton width.", 1.0) |
| 146 | + if not width: |
| 147 | + return |
| 148 | + |
| 149 | + angle = rs.GetReal("Specifiy skeleton leaf angle (degrees).", 30) |
| 150 | + if not angle: |
| 151 | + return |
| 152 | + |
| 153 | + density = rs.GetInteger("Specifiy skeleton density.", 2) |
| 154 | + if not density: |
| 155 | + return |
| 156 | + |
| 157 | + objects = [compas_rhino.objects.find_object(guid) for guid in guids] |
| 158 | + curves = [obj.Geometry for obj in objects] |
| 159 | + lines = [compas_rhino.conversions.curve_to_compas_line(curve) for curve in curves] |
| 160 | + |
| 161 | + skeleton = Skeleton(lines) |
| 162 | + skeleton.node_width = width |
| 163 | + skeleton.leaf_angle = angle |
| 164 | + skeleton.density = density |
| 165 | + pattern = skeleton.pattern.copy(cls=Pattern) |
| 166 | + |
| 167 | + return pattern |
0 commit comments