def mesh_from_rhino(mesh, layer): # get objects by layer rh_objs = sc.doc.Objects.FindByLayer(layer) # iterate over all objects on layer coords = {} mesh_data = None index = None index_u, index_v = None, None for i, rh_obj in enumerate(rh_objs): # check if curve object object_type = rh_obj.ObjectType if object_type == Rhino.DocObjects.ObjectType.Curve: # get start and end points of line curve = rh_obj.Geometry start = curve.PointAtStart end = curve.PointAtEnd # get name name = rh_obj.Attributes.Name # check if name exists and is valid if name: data = name.split('_') if len(data) == 3: u,v = int(data[1]), int(data[2]) coords[u] = start coords[v] = end # read in mesh data from user string if mesh_data == None: mesh_data = rh_obj.Attributes.GetUserString('mesh_data') if mesh_data: index = i index_u, index_v = u, v if index == None and not mesh: return None verboseprint('Index at which mesh_data UserString was found: ' + str(index)) verboseprint('u and v where mesh_data UserString was found: ' + str((index_u, index_v))) if not mesh_data: verboseprint('No geometry found. Mesh solely constructed from sticky variable.') if not mesh and mesh_data: verboseprint('No mesh object found. Mesh constructed from unpickled data.') mesh_data = pickle.loads(mesh_data) mesh = Mesh() mesh.data = mesh_data for key, attr in mesh.vertices(True): if key in coords: x, y, z = coords[key] attr['x'] = x attr['y'] = y attr['z'] = z return mesh
def collect_data_density(self): """Collect the existing density mesh in the density layer. Parameters ---------- Returns ------- """ objects = rs.ObjectsByLayer('density') if objects is not None: if len(objects) == 1: if rs.ObjectType(objects[0]) == 32: vertices, faces = RhinoGeometry.from_guid( objects[0]).get_vertices_and_faces() self.density_mesh = Mesh.from_vertices_and_faces( vertices, faces) else: print 'the object in the density layer is not a mesh' elif len(objects) > 1: print 'too many objects in the density layer'
def unjoin_mesh_parts(mesh, parts): """Explode the parts of a mesh. Parameters ---------- mesh : Mesh A mesh. parts : list List of lists of face keys. Returns ------- meshes : list The unjoined meshes. """ meshes = [] for part in parts: vertices_keys = list(set([vkey for fkey in part for vkey in mesh.face_vertices(fkey)])) vertices = [mesh.vertex_coordinates(vkey) for vkey in vertices_keys] key_to_index = {vkey: i for i, vkey in enumerate(vertices_keys)} faces = [ [key_to_index[vkey] for vkey in mesh.face_vertices(fkey)] for fkey in part] meshes.append(Mesh.from_vertices_and_faces(vertices, faces)) return meshes
def load_model(self, xdraw_function=None): """Load the geometry (meshes) of the robot. Args: xdraw_function (function, ): The function to draw the meshes in the respective CAD environment. Defaults to None. """ path = self.get_model_path() # the links loaded as meshes m0 = Mesh.from_obj(os.path.join(path, 'base_and_shoulder.obj')) m1 = Mesh.from_obj(os.path.join(path, 'upperarm.obj')) m2 = Mesh.from_obj(os.path.join(path, 'forearm.obj')) m3 = Mesh.from_obj(os.path.join(path, 'wrist1.obj')) m4 = Mesh.from_obj(os.path.join(path, 'wrist2.obj')) m5 = Mesh.from_obj(os.path.join(path, 'wrist3.obj')) # draw the geometry in the respective CAD environment if xdraw_function: m0 = xdraw_function(m0) m1 = xdraw_function(m1) m2 = xdraw_function(m2) m3 = xdraw_function(m3) m4 = xdraw_function(m4) m5 = xdraw_function(m5) self.model = [m0, m1, m2, m3, m4, m5]
def mesh_from_bmesh(bmesh): """ Create a Mesh datastructure from a Blender mesh. Parameters: bmesh (obj): Blender mesh object. Returns: obj: Mesh object. """ vertices, _, faces = bmesh_data(bmesh) mesh = Mesh.from_vertices_and_faces(vertices, faces) mesh.add_edges_from_faces() return mesh
def to_mesh_2(self): vertices = [self.vertex_coordinates(vkey) for vkey in self.vertices()] face_vertices = [] # remove consecutive duplicates in pseudo quad faces for fkey in self.faces(): non_pseudo_face = [] pseudo_face = self.face_vertices(fkey) for i, vkey in enumerate(pseudo_face): if vkey != pseudo_face[i - 1]: non_pseudo_face.append(vkey) face_vertices.append(non_pseudo_face) mesh = Mesh.from_vertices_and_faces(vertices, face_vertices) return mesh
def conway_gyro(mesh): """Generates the gyro mesh from a seed mesh. Parameters ---------- mesh : Mesh A seed mesh Returns ------- mesh The gyro mesh. References ---------- .. [1] Wikipedia. *Conway polyhedron notation*. Available at: https://en.wikipedia.org/wiki/Conway_polyhedron_notation. .. [2] Hart, George. *Conway Notation for Polyhedron*. Available at: http://www.georgehart.com/virtual-polyhedra/conway_notation.html. """ vertices = [mesh.vertex_coordinates(vkey) for vkey in mesh.vertices() ] + [mesh.face_centroid(fkey) for fkey in mesh.faces()] + [ mesh.edge_point(u, v, t=.33) for u in mesh.vertices() for v in mesh.halfedge[u] ] old_vertices_to_new_vertices = { vkey: i for i, vkey in enumerate(mesh.vertices()) } old_faces_to_new_vertices = { fkey: i + mesh.number_of_vertices() for i, fkey in enumerate(mesh.faces()) } old_halfedges_to_new_vertices = { halfedge: i + mesh.number_of_vertices() + mesh.number_of_faces() for i, halfedge in enumerate([(u, v) for u in mesh.vertices() for v in mesh.halfedge[u]]) } faces = [[ old_halfedges_to_new_vertices[(u, v)], old_halfedges_to_new_vertices[(v, u)], old_vertices_to_new_vertices[v], old_halfedges_to_new_vertices[(v, mesh.face_vertex_descendant(fkey, v))], old_faces_to_new_vertices[mesh.halfedge[u][v]] ] for fkey in mesh.faces() for u, v in mesh.face_halfedges(fkey)] return Mesh.from_vertices_and_faces(vertices, faces)
def mesh_from_guid(guid, **kwargs): """Creates an instance of a compAS mesh class from an identifier in Rhino/Grasshopper. This function is almost identical to ``mesh_from_guid`` in the core framework, but there were some import issues when used from within Grasshopper, but eventually, it should be migrated into the core. """ trimesh = ghcomp.Triangulate(rs.coercemesh(guid))[0] vertices = [map(float, vertex) for vertex in rs.MeshVertices(trimesh)] faces = map(list, rs.MeshFaceVertices(trimesh)) faces = [face[:-1] if face[-2] == face[-1] else face for face in faces] mesh = Mesh.from_vertices_and_faces(vertices, faces) mesh.attributes.update(kwargs) return mesh
def to_mesh(self): vertices = [self.vertex_coordinates(vkey) for vkey in self.vertices()] vertex_remap = list(self.vertices()) faces = [] for fkey in self.faces(): face_vertices = [] for vkey in self.face_vertices(fkey): vkey_idx = vertex_remap.index(vkey) if vkey_idx not in face_vertices: face_vertices.append(vkey_idx) faces.append(face_vertices) mesh = Mesh.from_vertices_and_faces(vertices, faces) return mesh
def delaunay_from_mesh(mesh): """Return a Delaunay triangulation from a given mesh. Parameters: mesh (compas.datastructures.mesh.Mesh) : The original mesh. Returns: mesh : ... >>> ... """ d = Delaunay(mesh.xy) return Mesh.from_vertices_and_faces(mesh.xyz, d.simplices)
def conway_join(mesh): """Generates the join mesh from a seed mesh. Parameters ---------- mesh : Mesh A seed mesh Returns ------- join_mesh : mesh The join mesh. References ---------- .. [1] Wikipedia. *Conway polyhedron notation*. Available at: https://en.wikipedia.org/wiki/Conway_polyhedron_notation. .. [2] Hart, George. *Conway Notation for Polyhedron*. Available at: http://www.georgehart.com/virtual-polyhedra/conway_notation.html. """ vertices = [mesh.vertex_coordinates(vkey) for vkey in mesh.vertices() ] + [mesh.face_centroid(fkey) for fkey in mesh.faces()] old_vertices_to_new_vertices = { vkey: i for i, vkey in enumerate(mesh.vertices()) } old_faces_to_new_vertices = { fkey: i + mesh.number_of_vertices() for i, fkey in enumerate(mesh.faces()) } faces = [[ old_vertices_to_new_vertices[u], old_faces_to_new_vertices[mesh.halfedge[v][u]], old_vertices_to_new_vertices[v], old_faces_to_new_vertices[mesh.halfedge[u][v]] ] for u, v in mesh.edges() if not mesh.is_edge_on_boundary(u, v)] join_mesh = Mesh.from_vertices_and_faces(vertices, faces) join_mesh.cull_vertices() return join_mesh
def close_handle_2(mesh, edge_path_1, edge_path_2): # two closed edge paths # unweld unweld_mesh_along_edge_path(mesh, edge_path_1) unweld_mesh_along_edge_path(mesh, edge_path_2) # explode parts = mesh_disjointed_parts(mesh) meshes = unjoin_mesh_parts(mesh, parts) # find parts with the topolog of a strip: two boundary components and an EUler characteristic of 0 # if there are several, select the topologically smallest one (lowest number of faces) index = -1 size = -1 for i, submesh in enumerate(meshes): B = len(mesh_boundaries(mesh)) X = mesh_euler(submesh) if B == 2 and X == 0: n = submesh.number_of_faces() if index < 0 or n < size: index = i size = n # collect the boundaries of the strip, oriented towards the outside of the strip vertices = [] key_to_index = {} for i, vkey in enumerate(mesh.vertices()): vertices.append(mesh.vertex_coordinates(vkey)) key_to_index[vkey] = i faces = [[key_to_index[vkey] for vkey in mesh.face_vertices(fkey)] for fkey in parts[index]] strip_mesh = Mesh.from_vertices_and_faces(vertices, faces) boundaries = mesh_boundaries(strip_mesh) # remove faces of the selected band for fkey in parts[index]: mesh.delete_face(fkey) # close the two boundaries new_fkeys = [] for bdry in boundaries: new_fkeys += close_opening(mesh, list(reversed(bdry))) return new_fkeys
def initiate_mesh(layer): objs = rs.ObjectsByLayer(layer) lines = [(rs.CurveStartPoint(crv), rs.CurveEndPoint(crv)) for crv in objs] rs.DeleteObjects(objs) objs_dict = {} for i, pts in enumerate(lines): cent = centroid_points(pts) objs_dict[geometric_key(cent)] = str(objs[i]) mesh = Mesh.from_lines(lines) for u,v, attr in mesh.edges(True): cent = centroid_points([mesh.vertex_coordinates(u), mesh.vertex_coordinates(v)]) attr['master'] = False attr['color'] = [50, 255, 100] attr['passive'] = False attr['id'] = objs_dict[geometric_key(cent)] name = 'e_' + str(u) + '_' + str(v) return mesh
def get_transformed_model(self, transformations, xtransform_function=None): """Get the transformed meshes of the robot model. Args: transformations (:obj:`list` of :class:`Transformation`): A list of transformations to apply on each of the links xtransform_function (function name, ): the name of the function used to transform the model. Defaults to None. Returns: model (:obj:`list` of :class:`Mesh`): The list of meshes in the respective class of the CAD environment """ tmodel = [] if xtransform_function: for m, T in zip(self.model, transformations): tmodel.append(xtransform_function(m, T, copy=True)) else: for m, T in zip(self.model, transformations): mtxyz = transform_points(m.xyz, T) faces = [m.face_vertices(fkey) for fkey in m.faces()] tmodel.append(Mesh.from_vertices_and_faces(mtxyz, faces)) return tmodel
def conway_dual(mesh): """Generates the dual mesh from a seed mesh. Parameters ---------- mesh : Mesh A seed mesh Returns ------- mesh The dual mesh. References ---------- .. [1] Wikipedia. *Conway polyhedron notation*. Available at: https://en.wikipedia.org/wiki/Conway_polyhedron_notation. .. [2] Hart, George. *Conway Notation for Polyhedron*. Available at: http://www.georgehart.com/virtual-polyhedra/conway_notation.html. """ vertices = [mesh.face_centroid(fkey) for fkey in mesh.faces()] old_faces_to_new_vertices = { fkey: i for i, fkey in enumerate(mesh.faces()) } faces = [[ old_faces_to_new_vertices[fkey] for fkey in reversed(mesh.vertex_faces(vkey, ordered=True)) ] for vkey in mesh.vertices() if not mesh.is_vertex_on_boundary(vkey) and len(mesh.vertex_neighbors(vkey)) != 0] return Mesh.from_vertices_and_faces(vertices, faces)
def close_handle(mesh, fkeys): # remove handle and close openings # fkeys: closed face strip if fkeys[0] == fkeys[-1]: del fkeys[-1] vertices = [] key_to_index = {} for i, vkey in enumerate(mesh.vertices()): vertices.append(mesh.vertex_coordinates(vkey)) key_to_index[vkey] = i faces = [[key_to_index[vkey] for vkey in mesh.face_vertices(fkey)] for fkey in fkeys] strip_mesh = Mesh.from_vertices_and_faces(vertices, faces) boundaries = mesh_boundaries(strip_mesh) for fkey in fkeys: mesh.delete_face(fkey) new_fkeys = [] for bdry in boundaries: new_fkeys += close_opening(mesh, list(reversed(bdry))) return new_fkeys
def load_model(self): """Load the geometry (meshes) of the robot. """ path = self.get_model_path() # the joints loaded as meshes self.m0 = Mesh.from_obj(os.path.join(path, 'base_and_shoulder.obj')) self.m1 = Mesh.from_obj(os.path.join(path, 'upperarm.obj')) self.m2 = Mesh.from_obj(os.path.join(path, 'forearm.obj')) self.m3 = Mesh.from_obj(os.path.join(path, 'wrist1.obj')) self.m4 = Mesh.from_obj(os.path.join(path, 'wrist2.obj')) self.m5 = Mesh.from_obj(os.path.join(path, 'wrist3.obj')) # have a copy of the mesh vertices for later transformation self.m0_xyz = self.m0.xyz self.m1_xyz = self.m1.xyz self.m2_xyz = self.m2.xyz self.m3_xyz = self.m3.xyz self.m4_xyz = self.m4.xyz self.m5_xyz = self.m5.xyz
# ============================================================================== # Debugging # ============================================================================== if __name__ == "__main__": from numpy import random from numpy import hstack from numpy import zeros from compas.visualization.plotters.meshplotter import MeshPlotter points = hstack((10.0 * random.random_sample((20, 2)), zeros( (20, 1)))).tolist() mesh = Mesh.from_vertices_and_faces(points, delaunay_from_points(points)) optimise_trimesh_topology(mesh, 1.0, allow_boundary_split=True) points = [mesh.vertex_coordinates(key) for key in mesh] voronoi, delaunay = voronoi_from_points(points, return_delaunay=True) lines = [] for u, v in voronoi.wireframe(): lines.append({ 'start': voronoi.vertex_coordinates(u, 'xy'), 'end': voronoi.vertex_coordinates(v, 'xy') }) boundary = set(delaunay.vertices_on_boundary())
def start(): from compas.geometry.algorithms.smoothing import mesh_smooth_centroid from compas.geometry.algorithms.smoothing import mesh_smooth_area from compas_pattern.algorithms.smoothing import define_constraints from compas_pattern.algorithms.smoothing import apply_constraints guid = rs.GetObject('get mesh') dense_mesh = RhinoGeometry.from_guid(guid) vertices, faces = dense_mesh.get_vertices_and_faces() dense_mesh = Mesh.from_vertices_and_faces(vertices, faces) #lines = rs.GetObjects('lines', filter = 4) #edges = [[rs.CurveStartPoint(line), rs.CurveEndPoint(line)] for line in lines] #dense_mesh = Mesh.from_lines(edges) #faces = list(dense_mesh.faces()) #for fkey in faces: # if len(dense_mesh.face_vertices(fkey)) > 10: # delete_face(dense_mesh, fkey) # print '-1 face' #dense_mesh = conway_ambo(dense_mesh) #dense_mesh = conway_dual(dense_mesh) #dense_mesh = conway_gyro(dense_mesh) #dense_mesh = conway_dual(dense_mesh) #dense_mesh = conway_gyro(dense_mesh) #dense_mesh = conway_kis(dense_mesh) #rs.EnableRedraw(False) #draw_mesh(dense_mesh) #rs.EnableRedraw(True) #return surface_guid = rs.GetSurfaceObject('surface constraint')[0] smooth_mesh = dense_mesh.copy() smoothing_iterations = rs.GetInteger('number of iterations for smoothing', number=20) damping_value = rs.GetReal('damping value for smoothing', number=.5) rs.EnableRedraw(False) #constraints, surface_boundaries = custom_constraints(smooth_mesh, surface_guid) constraints, surface_boundaries = define_constraints( smooth_mesh, surface_guid) rs.EnableRedraw(False) fixed_vertices = [ vkey for vkey, constraint in constraints.items() if constraint[0] == 'fixed' ] mesh_smooth_area(smooth_mesh, fixed=fixed_vertices, kmax=smoothing_iterations, damping=damping_value, callback=apply_constraints, callback_args=[smooth_mesh, constraints]) smooth_mesh_guid = draw_mesh(smooth_mesh) #layer = 'smooth_mesh' #rs.AddLayer(layer) #rs.ObjectLayer(smooth_mesh_guid, layer = layer) rs.EnableRedraw(True)
# Debugging # ============================================================================== if __name__ == "__main__": import os import compas from compas.datastructures.mesh import Mesh filename = os.path.join( compas.get_data('stanford/bunny/reconstruction/bun_zipper.ply')) filename = os.path.join( compas.get_data('stanford/dragon_recon/dragon_vrip.ply')) filename = os.path.join(compas.get_data('stanford/Armadillo.ply')) reader = PLYreader(filename) reader.read() for line in reader.header: print(line) vertices = [(vertex['x'], vertex['y'], vertex['z']) for vertex in reader.vertices] faces = [face['vertex_indices'] for face in reader.faces] mesh = Mesh.from_vertices_and_faces(vertices, faces) print(mesh)
A mesh object. Notes ----- This function does not care about the directions being unified or not. It just reverses whatever direction it finds. """ mesh.halfedge = {key: {} for key in mesh.vertices()} for fkey in mesh.faces(): mesh.face[fkey][:] = mesh.face[fkey][::-1] for u, v in mesh.face_halfedges(fkey): mesh.halfedge[u][v] = fkey if u not in mesh.halfedge[v]: mesh.halfedge[v][u] = None # ============================================================================== # Main # ============================================================================== if __name__ == "__main__": import compas from compas.datastructures.mesh import Mesh mesh = Mesh.from_obj(compas.get_data('faces_big.obj')) mesh_unify_cycles(mesh)
def polyhedron_from_node(cent, points, scale=1., tolerance=1e-6): """Computes polyhedra from a spatial node. Parameters: cent (sequence of float): XYZ coordinates of the central node vertex points (sequence of sequence of float): XYZ coordinates of the neighboring vertices Returns: points (sequence of sequences of floats): the XYZ coordinates of the vertices of the polyhedra faces (sequence of sequences of integers): the faces of the polyhedra Examples: .. code-block:: python from compas.datastructures.network import Network import rhinoscriptsyntax as rs crvs = rs.GetObjects("Select Edges", 4) lines = [[rs.CurveStartPoint(crv), rs.CurveEndPoint(crv)] for crv in crvs] network = Network.from_lines(lines) keys = [] for key in network.vertices(): if not network.is_vertex_leaf(key): keys.append(key) for key in keys: nbrs = network.neighbours(key) cent = network.vertex_coordinates(key) points = [network.vertex_coordinates(nbr) for nbr in nbrs] points, faces = polyhedron_from_node(cent, points, 1) for face in faces: pts = [points[i] for i in face] poly = rs.AddPolyline(pts+[pts[0]]) rs.AddPlanarSrf(poly) """ pts_hull = [] for pt in points: vec = subtract_vectors(pt, cent) vec = scale_vector(normalize_vector(vec), scale) pt = add_vectors(cent, vec) pts_hull.append(pt) faces = convex_hull(pts_hull) mesh = Mesh.from_vertices_and_faces(pts_hull, faces) planes = {} for key in mesh.vertices(): vec = subtract_vectors(mesh.vertex_coordinates(key), cent) planes[key] = [mesh.vertex_coordinates(key), vec] faces = [] pts = [] for key in mesh.vertices(): nbrs = mesh.vertex_neighbours(key, True) face = [] for i in range(len(nbrs)): pt = intersection_plane_plane_plane(planes[nbrs[i - 1]], planes[nbrs[i]], planes[key]) if not pt: continue dup = False n = len(pts) for j in range(n): if distance_point_point(pt, pts[j]) < tolerance: face.append(j) dup = True break if not dup: face.append(n) pts.append(pt) if face: faces.append(face) return pts, faces
if __name__ == "__main__": # todo: distinguish between vertices of hull and internal vertices import random from compas.visualization.viewers.meshviewer import MeshViewer radius = 5 origin = (0., 0., 0.) count = 0 points = [] while count < 1000: x = (random.random() - 0.5) * radius * 2 y = (random.random() - 0.5) * radius * 2 z = (random.random() - 0.5) * radius * 2 pt = x, y, z if distance_point_point(origin, pt) <= radius: points.append(pt) count += 1 faces = convex_hull(points) mesh = Mesh.from_vertices_and_faces(points, faces) viewer = MeshViewer(mesh) viewer.setup() viewer.show()
def mesh_extrude(structure, guid, layers, thickness, mesh_name='', links_name='', blocks_name='', plot_blocks=False, plot_mesh=False, plot_links=False): """ Extrudes a Rhino mesh and adds/creates elements. Parameters ---------- structure : obj Structure object to update. guid : guid Rhino mesh guid. layers : int Number of layers. thickness : float Layer thickness. blocks_name : str Name of set for solid elements. mesh_name : str Name of set for mesh on final surface. links_name : str Name of set for adding links along extrusion. plot_blocks : bool Plot blocks. plot_mesh : bool Plot outer mesh. plot_links : bool Plot links. Returns ------- None Notes ----- - Extrusion is along the vertex normals. """ mesh = mesh_from_guid(Mesh(), guid) extrude_mesh(structure=structure, mesh=mesh, layers=layers, thickness=thickness, mesh_name=mesh_name, links_name=links_name, blocks_name=blocks_name) block_faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]] xyz = structure.nodes_xyz() rs.EnableRedraw(False) if plot_blocks: rs.CurrentLayer(rs.AddLayer(blocks_name)) rs.DeleteObjects(rs.ObjectsByLayer(blocks_name)) for i in structure.sets[blocks_name]['selection']: nodes = structure.elements[i].nodes xyz = structure.nodes_xyz(nodes) rs.AddMesh(xyz, block_faces) if plot_mesh: rs.CurrentLayer(rs.AddLayer(mesh_name)) rs.DeleteObjects(rs.ObjectsByLayer(mesh_name)) faces = [] for i in structure.sets[mesh_name]['selection']: enodes = structure.elements[i].nodes if len(enodes) == 3: enodes.append(enodes[-1]) faces.append(enodes) rs.AddMesh(xyz, faces) if plot_links: rs.CurrentLayer(rs.AddLayer(links_name)) rs.DeleteObjects(rs.ObjectsByLayer(links_name)) for i in structure.sets[links_name]['selection']: nodes = structure.elements[i].nodes xyz = structure.nodes_xyz(nodes) rs.AddLine(xyz[0], xyz[1]) rs.EnableRedraw(True) rs.CurrentLayer(rs.AddLayer('Default'))
return [ vkey for vkey in self.vertices_on_boundary() if self.is_boundary_vertex_kink(vkey, threshold_angle) ] def vertex_centroid(self): """Calculate the centroid of the mesh vertices. Parameters ---------- Returns ------- list The coordinates of the centroid of the mesh vertices. """ return centroid_points( [self.vertex_coordinates(vkey) for vkey in self.vertices()]) # ============================================================================== # Main # ============================================================================== if __name__ == '__main__': import compas mesh = Mesh.from_obj(compas.get('faces.obj'))
# Debugging # ============================================================================== if __name__ == "__main__": import compas from compas.datastructures.mesh import Mesh from compas.visualization.viewers.viewer import Viewer from compas.visualization.viewers.core.drawing import draw_points from compas.visualization.viewers.core.drawing import draw_lines from compas.visualization.viewers.core.drawing import draw_circle mesh = Mesh.from_obj(compas.get_data('hypar.obj')) for key, attr in mesh.vertices(True): attr['is_fixed'] = mesh.vertex_degree(key) == 2 planarize_mesh_shapeop(mesh, fixed=mesh.vertices_where({'is_fixed': True}), kmax=100) # deviations = [] # for fkey, attr in mesh.faces(True): # points = mesh.face_coordinates(fkey) # base, normal = bestfit_plane_from_points(points) # angles = []
# ============================================================================== # Debugging # ============================================================================== if __name__ == "__main__": import time from compas.datastructures.mesh import Mesh from compas.geometry.elements import Polyhedron from compas_rhino.artists.meshartist import MeshArtist poly = Polyhedron.generate(12) mesh = Mesh.from_vertices_and_faces(poly.vertices, poly.faces) artist = MeshArtist(mesh, layer='MeshArtist') artist.clear_layer() artist.draw_vertices() artist.redraw() time.sleep(2.0) artist.draw_faces() artist.redraw() time.sleep(2.0) artist.draw_edges() artist.redraw()
def voronoi_from_points(points, boundary=None, holes=None, return_delaunay=False): """Construct the Voronoi dual of the triangulation of a set of points. Parameters: points boundary holes return_delaunay Example: .. plot:: :include-source: from numpy import random from numpy import hstack from numpy import zeros from compas.datastructures.mesh import Mesh from compas.datastructures.mesh.algorithms import optimise_trimesh_topology from compas.datastructures.mesh.algorithms import delaunay_from_points from compas.datastructures.mesh.algorithms import voronoi_from_points points = hstack((10.0 * random.random_sample((20, 2)), zeros((20, 1)))).tolist() mesh = Mesh.from_vertices_and_faces(points, delaunay_from_points(points)) optimise_trimesh_topology(mesh, 1.0, allow_boundary_split=True) points = [mesh.vertex_coordinates(key) for key in mesh] voronoi, delaunay = voronoi_from_points(points, return_delaunay=True) lines = [] for u, v in voronoi.edges(): lines.append({ 'start': voronoi.vertex_coordinates(u, 'xy'), 'end' : voronoi.vertex_coordinates(v, 'xy') }) boundary = set(delaunay.vertices_on_boundary()) delaunay.plot( vertexsize=0.075, faces_on=False, edgecolor='#cccccc', vertexcolor={key: '#0092d2' for key in delaunay if key not in boundary}, lines=lines ) """ delaunay = Mesh.from_vertices_and_faces(points, delaunay_from_points(points)) voronoi = construct_dual_mesh(delaunay) for key in voronoi: a, b, c = delaunay.face_coordinates(key) center, radius, normal = circle_from_points_2d(a, b, c) voronoi.vertex[key]['x'] = center[0] voronoi.vertex[key]['y'] = center[1] voronoi.vertex[key]['z'] = center[2] if return_delaunay: return voronoi, delaunay return voronoi
def delaunay_from_points(points): """""" xyz = asarray(points) assert 2 <= xyz.shape[1], "At least xy xoordinates required." d = Delaunay(xyz[:, 0:2]) return Mesh.from_vertices_and_faces(points, d.simplices)
def delaunay_from_points(points, polygon=None, polygons=None): """Computes the delaunay triangulation for a list of points. Parameters: points (sequence of tuple): XYZ coordinates of the original points. polygon (sequence of tuples): list of ordered points describing the outer boundary (optional) polygons (list of sequences of tuples): list of polygons (ordered points describing internal holes (optional) Returns: list of lists: list of faces (face = list of vertex indices as integers) References: Sloan, S. W. (1987) A fast algorithm for constructing Delaunay triangulations in the plane Example: .. plot:: :include-source: import compas from compas.datastructures.mesh import Mesh from compas.datastructures.mesh.algorithms import delaunay_from_points mesh = Mesh.from_obj(compas.get_data('faces.obj')) vertices = [mesh.vertex_coordinates(key) for key in mesh] faces = delaunay_from_points(vertices) delaunay = Mesh.from_vertices_and_faces(vertices, faces) delaunay.plot( vertexsize=0.1 ) """ def super_triangle(coords): centpt = centroid_points(coords) bbpts = bounding_box(coords) dis = distance_point_point(bbpts[0], bbpts[2]) dis = dis * 300 v1 = (0 * dis, 2 * dis, 0) v2 = (1.73205 * dis, -1.0000000000001 * dis, 0 ) # due to numerical issues v3 = (-1.73205 * dis, -1 * dis, 0) pt1 = add_vectors(centpt, v1) pt2 = add_vectors(centpt, v2) pt3 = add_vectors(centpt, v3) return pt1, pt2, pt3 mesh = Mesh() # to avoid numerical issues for perfectly structured point sets tiny = 1e-8 pts = [(point[0] + random.uniform(-tiny, tiny), point[1] + random.uniform(-tiny, tiny), 0.0) for point in points] # create super triangle pt1, pt2, pt3 = super_triangle(points) # add super triangle vertices to mesh n = len(points) super_keys = n, n + 1, n + 2 mesh.add_vertex(super_keys[0], {'x': pt1[0], 'y': pt1[1], 'z': pt1[2]}) mesh.add_vertex(super_keys[1], {'x': pt2[0], 'y': pt2[1], 'z': pt2[2]}) mesh.add_vertex(super_keys[2], {'x': pt3[0], 'y': pt3[1], 'z': pt3[2]}) mesh.add_face(super_keys) # iterate over points for i, pt in enumerate(pts): key = i # check in which triangle this point falls for fkey in list(mesh.faces()): # abc = mesh.face_coordinates(fkey) #This is slower # This is faster: keya, keyb, keyc = mesh.face_vertices(fkey) dicta = mesh.vertex[keya] dictb = mesh.vertex[keyb] dictc = mesh.vertex[keyc] a = [dicta['x'], dicta['y']] b = [dictb['x'], dictb['y']] c = [dictc['x'], dictc['y']] if is_point_in_triangle_2d(pt, [a, b, c]): # generate 3 new triangles (faces) and delete surrounding triangle newtris = mesh.insert_vertex(fkey, key=key, xyz=pt) break while newtris: fkey = newtris.pop() # get opposite_face keys = mesh.face_vertices(fkey) s = list(set(keys) - set([key])) u, v = s[0], s[1] fkey1 = mesh.halfedge[u][v] if fkey1 != fkey: fkey_op, u, v = fkey1, u, v else: fkey_op, u, v = mesh.halfedge[v][u], u, v if fkey_op: keya, keyb, keyc = mesh.face_vertices(fkey_op) dicta = mesh.vertex[keya] a = [dicta['x'], dicta['y']] dictb = mesh.vertex[keyb] b = [dictb['x'], dictb['y']] dictc = mesh.vertex[keyc] c = [dictc['x'], dictc['y']] circle = circle_from_points_2d(a, b, c) if is_point_in_circle_2d(pt, circle): fkey, fkey_op = swap_edge_trimesh(mesh, u, v) newtris.append(fkey) newtris.append(fkey_op) # Delete faces adjacent to supertriangle for key in super_keys: mesh.remove_vertex(key) # Delete faces outside of boundary if polygon: for fkey in list(mesh.faces()): cent = mesh.face_centroid(fkey) if not is_point_in_polygon_2d(cent, polygon): mesh.delete_face(fkey) # Delete faces inside of inside boundaries if polygons: for polygon in polygons: for fkey in list(mesh.faces()): cent = mesh.face_centroid(fkey) if is_point_in_polygon_2d(cent, polygon): mesh.delete_face(fkey) return [[int(key) for key in mesh.face_vertices(fkey, True)] for fkey in mesh.faces()]