def sort_pts(sets_pts): # sorts point sets for coons patch # sort point sets in a "continous chain" end_pt = sets_pts[0][-1] new_sets_pts = [sets_pts[0]] sets_pts.pop(0) while True: flag = True for i, set_pts in enumerate(sets_pts): if geometric_key(set_pts[0]) == geometric_key(end_pt): end_pt = set_pts[-1] new_sets_pts.append(set_pts) sets_pts.pop(i) flag = False elif geometric_key(set_pts[-1]) == geometric_key(end_pt): end_pt = set_pts[0] set_pts.reverse() new_sets_pts.append(set_pts) sets_pts.pop(i) flag = False if flag: break #coons patch sorting new_sets_pts[2].reverse() new_sets_pts[3].reverse() return new_sets_pts
def create_networks(): networks = {} descendent_tree = {} for u in joints: global_local = {} lines = [] nbrs = network_global.neighbors(u) start_pt = network_global.node_coordinates(u) for v in nbrs: end_pt = network_global.edge_point(u, v, t=joint_length) lines.append([start_pt, end_pt]) network_local = Network.from_lines(lines) key_local = list( set(list(network_local.nodes())) - set(network_local.leaves()))[0] global_local.update({u: key_local}) gkeys_global_network = [geometric_key(line[1]) for line in lines] gkeys_local_network = [ geometric_key(network_local.node_coordinates(key)) for key in network_local.leaves() ] for i, key_global in enumerate(nbrs): gkey_global = gkeys_global_network[i] index_local = gkeys_local_network.index(gkey_global) key_local = network_local.leaves()[index_local] global_local.update({key_global: key_local}) descendent_tree.update({u: global_local}) networks.update({u: network_local}) return networks, descendent_tree
def from_polylines(cls, boundary_polylines, other_polylines): """Construct mesh from polylines. Based on construction from_lines, with removal of vertices that are not polyline extremities and of faces that represent boundaries. This specific method is useful to get the mesh connectivity from a set of (discretised) curves, that could overlap and yield a wrong connectivity if using from_lines based on the polyline extremities only. Parameters ---------- boundary_polylines : list List of polylines representing boundaries as lists of vertex coordinates. other_polylines : list List of the other polylines as lists of vertex coordinates. Returns ------- Mesh A mesh object. """ corner_vertices = [geometric_key(xyz) for polyline in boundary_polylines + other_polylines for xyz in [polyline[0], polyline[-1]]] boundary_vertices = [geometric_key(xyz) for polyline in boundary_polylines for xyz in polyline] mesh = cls.from_lines([(u, v) for polyline in boundary_polylines + other_polylines for u, v in pairwise(polyline)]) # remove the vertices that are not from the polyline extremities and the faces with all their vertices on the boundary vertex_keys = [vkey for vkey in mesh.vertices() if geometric_key(mesh.vertex_coordinates(vkey)) in corner_vertices] vertex_map = {vkey: i for i, vkey in enumerate(vertex_keys)} vertices = [mesh.vertex_coordinates(vkey) for vkey in vertex_keys] faces = [] for fkey in mesh.faces(): if sum([geometric_key(mesh.vertex_coordinates(vkey)) not in boundary_vertices for vkey in mesh.face_vertices(fkey)]): faces.append([vertex_map[vkey] for vkey in mesh.face_vertices(fkey) if geometric_key(mesh.vertex_coordinates(vkey)) in corner_vertices]) mesh.cull_vertices() return cls.from_vertices_and_faces(vertices, faces)
def brep_to_compas(self, cls=None): if not self.geometry.HasBrepForm: return success, brep = self.geometry.TryConvertBrep() if not success: return gkey_xyz = {} faces = [] for loop in brep.Loops: curve = loop.To3dCurve() segments = curve.Explode() face = [] sp = segments[0].PointAtStart ep = segments[0].PointAtEnd sp_gkey = geometric_key(sp) ep_gkey = geometric_key(ep) gkey_xyz[sp_gkey] = sp gkey_xyz[ep_gkey] = ep face.append(sp_gkey) face.append(ep_gkey) for segment in segments[1:-1]: ep = segment.PointAtEnd ep_gkey = geometric_key(ep) face.append(ep_gkey) gkey_xyz[ep_gkey] = ep faces.append(face) gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz)} vertices = [list(xyz) for gkey, xyz in gkey_xyz.items()] faces = [[gkey_index[gkey] for gkey in f] for f in faces] cls = cls or Mesh return cls.from_vertices_and_faces(vertices, faces)
def quadrangulate_polygonal_faces(self): # WIP: problem not all faces should have the same source for propagation supermesh = self.mesh delaunay_vertex_map = tuple(geometric_key(self.vertex_coordinates(vkey)) for vkey in self.vertices()) #newly added vertices in mesh that were not in the Delaunay are missing... edges_to_unweld = [edge for edge in supermesh.edges() if sum([geometric_key(supermesh.vertex_coordinates(i)) in delaunay_vertex_map for i in edge]) == 2] mesh_unweld_edges(supermesh, edges_to_unweld) meshes = mesh_explode(supermesh) for mesh in meshes: candidate_map = {geometric_key(mesh.vertex_coordinates(vkey)): [] for vkey in mesh.vertices()} for vkey in mesh.vertices_on_boundary(): candidate_map[geometric_key(mesh.vertex_coordinates(vkey))].append(mesh.vertex_degree(vkey)) source_map = tuple([geom_key for geom_key, valencies in candidate_map.items() if len(list(set(valencies))) > 1]) self.mesh = mesh_weld(mesh) mesh = self.mesh sources = [vkey for vkey in mesh.vertices() if geometric_key(mesh.vertex_coordinates(vkey)) in source_map] quadrangulate_mesh(mesh, sources)
def sort_pts(sets_pts): # sorts point sets for coons patch # sort point sets in a "continous chain" start_pt = sets_pts[0][-1] new_sets_pts = [sets_pts[0]] sets_pts.pop(0) count = 0 while sets_pts: for i, set_pts in enumerate(sets_pts): #alternative for a more "forgiving" point comparison #geometric_key(set_pts[0]) == geometric_key(start_pt) if geometric_key(set_pts[0]) == geometric_key(start_pt): start_pt = set_pts[-1] new_sets_pts.append(set_pts) sets_pts.pop(i) elif geometric_key(set_pts[-1]) == geometric_key(start_pt): start_pt = set_pts[0] set_pts.reverse() new_sets_pts.append(set_pts) sets_pts.pop(i) if count > 100: break count += 1 #coons patch sorting new_sets_pts[2].reverse() new_sets_pts[3].reverse() return new_sets_pts
def decomposition_polysurface(self, point_features): """Output the remapped decomposition polysurface. Parameters ---------- point_features : list The point features for pole locations. Returns ------- A Rhino surface guid. The remapped decomposition polysurface. """ mesh = self.decomposition_mesh() nurbs_curves = {(geometric_key(polyline[i]), geometric_key(polyline[-i - 1])): rs.AddInterpCrvOnSrfUV(self.srf_guid, [pt[:2] for pt in polyline]) for polyline in self.decomposition_polylines() for i in [0, -1]} polysurface = rs.JoinSurfaces([ rs.AddEdgeSrf([ nurbs_curves[(geometric_key(mesh.vertex_coordinates(u)), geometric_key(mesh.vertex_coordinates(v)))] for u, v in mesh.face_halfedges(fkey) ]) for fkey in mesh.faces() ], delete_input=True) rs.DeleteObjects(list(nurbs_curves.values())) return polysurface
def meshes_join_and_weld(meshes, precision=None, cls=None): """Join and and weld meshes within some precision distance. Parameters ---------- meshes : list A list of meshes. precision: str Tolerance distance for welding. Returns ------- mesh The joined and welded mesh. """ if cls is None: cls = type(meshes[0]) # create vertex map based on geometric keys in dictionary without duplicates vertex_map = {geometric_key(mesh.vertex_coordinates(vkey), precision): vkey for mesh in meshes for vkey in mesh.vertices()} # list vertices with coordinates vertices = [reverse_geometric_key(geom_key) for geom_key in vertex_map.keys()] # reorder vertex keys in vertex map vertex_map = {geom_key: i for i, geom_key in enumerate(vertex_map.keys())} # modify vertex indices in the faces faces = [ [vertex_map[geometric_key(mesh.vertex_coordinates(vkey), precision)] for vkey in mesh.face_vertices(fkey)] for mesh in meshes for fkey in mesh.faces()] return cls.from_vertices_and_faces(vertices, faces)
def decomposition_mesh(self, poles): """Return a quad mesh based on the decomposition polylines. Some fixes are added to convert the mesh formed by the decomposition polylines into a (coarse) quad mesh. Returns ------- mesh A coarse quad mesh based on the topological skeleton from a Delaunay mesh. """ polylines = self.decomposition_polylines() boundary_keys = set([ geometric_key(self.vertex_coordinates(vkey)) for vkey in self.vertices_on_boundary() ]) boundary_polylines = [ polyline for polyline in polylines if geometric_key(polyline[0]) in boundary_keys and geometric_key(polyline[1]) in boundary_keys ] other_polylines = [ polyline for polyline in polylines if geometric_key(polyline[0]) not in boundary_keys or geometric_key(polyline[1]) not in boundary_keys ] self.mesh = CoarsePseudoQuadMesh.from_polylines( boundary_polylines, other_polylines) self.solve_triangular_faces() self.quadrangulate_polygonal_faces() self.split_quads_with_poles(poles) self.store_pole_data(poles) return self.mesh
def sort_pts(sets_pts): # sorts point sets for coons patch # sort point sets in a "continous chain" start_pt = sets_pts[0][-1] new_sets_pts = [sets_pts[0]] sets_pts.pop(0) count = 0 while sets_pts: for i, set_pts in enumerate(sets_pts): if geometric_key(set_pts[0]) == geometric_key(start_pt): start_pt = set_pts[-1] new_sets_pts.append(set_pts) sets_pts.pop(i) elif geometric_key(set_pts[-1]) == geometric_key(start_pt): start_pt = set_pts[0] set_pts.reverse() new_sets_pts.append(set_pts) sets_pts.pop(i) if count > 100: break count += 1 return new_sets_pts
def join_and_weld_meshes(meshes, tolerance = '3f'): """Join and and weld meshes within some tolerance distance. Parameters ---------- meshes : list A list of meshes. tolerance: str Tolerance distance for welding. Returns ------- vertices : list The vertices of the new mesh. faces : list The faces of the new mesh. """ # create vertex map based on geometric keys in dictionary without duplicates vertex_map = {geometric_key(mesh.vertex_coordinates(vkey), tolerance): vkey for mesh in meshes for vkey in mesh.vertices()} # list vertices with coordinates vertices = [reverse_geometric_key(geom_key) for geom_key in vertex_map.keys()] # reorder vertex keys in vertex map vertex_map = {geom_key: i for i, geom_key in enumerate(vertex_map.keys())} # modify vertex indices in the faces faces = [ [vertex_map[geometric_key(mesh.vertex_coordinates(vkey), tolerance)] for vkey in mesh.face_vertices(fkey)] for mesh in meshes for fkey in mesh.faces()] return vertices, faces
def volmesh_from_polysurfaces(cls, guids): """Construct a volumetric mesh from given polysurfaces. Essentially, this function does the following: * find each of the polysurfaces and check if they have a boundary representation (b-rep) * convert to b-rep and extract the edge loops * make a face of each loop by referring to vertices using their geometric keys * add a cell per brep * and add the faces of a brep to the cell * create a volmesh from the found vertices and cells Parameters: cls (compas.datastructures.volmesh.VolMesh): The class of volmesh. guids (sequence of str or System.Guid): The *globally unique identifiers* of the polysurfaces. Returns: compas.datastructures.volmesh.Volmesh: The volumetric mesh object. """ gkey_xyz = {} cells = [] for guid in guids: cell = [] obj = sc.doc.Objects.Find(guid) if not obj.Geometry.HasBrepForm: continue brep = Rhino.Geometry.Brep.TryConvertBrep(obj.Geometry) for loop in brep.Loops: curve = loop.To3dCurve() segments = curve.Explode() face = [] sp = segments[0].PointAtStart ep = segments[0].PointAtEnd sp_gkey = geometric_key(sp) ep_gkey = geometric_key(ep) gkey_xyz[sp_gkey] = sp gkey_xyz[ep_gkey] = ep face.append(sp_gkey) face.append(ep_gkey) for segment in segments[1:-1]: ep = segment.PointAtEnd ep_gkey = geometric_key(ep) face.append(ep_gkey) gkey_xyz[ep_gkey] = ep cell.append(face) cells.append(cell) gkey_index = dict((gkey, index) for index, gkey in enumerate(gkey_xyz)) vertices = [list(xyz) for gkey, xyz in gkey_xyz.items()] cells = [[[gkey_index[gkey] for gkey in face] for face in cell] for cell in cells] return cls.from_vertices_and_cells(vertices, cells)
def mesh_identify_vertices(mesh, points, precision=None): keys = [] gkey_key = {geometric_key(mesh.vertex_coordinates(key), precision): key for key in mesh.vertices()} for xyz in points: gkey = geometric_key(xyz, precision) if gkey in gkey_key: key = gkey_key[gkey] keys.append(key) return keys
def is_point_on_curve(curve_guid, point_xyz): geom_key = geometric_key(point_xyz) t = rs.CurveClosestPoint(curve_guid, point_xyz) pt_on_crv = rs.EvaluateCurve(curve_guid, t) geom_key_pt_on_crv = geometric_key(pt_on_crv) if geom_key == geom_key_pt_on_crv: return True else: return False
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
def get_initial_mesh(precision): crvs = rs.GetObjects("Select boundary curves", 4, group=True, preselect=False, select=False, objects=None, minimum_count=3, maximum_count=0) lines = get_line_coordinates(crvs) geo_lines = [(geometric_key(pt_u, precision), geometric_key(pt_v, precision)) for pt_u, pt_v in lines] network = Network.from_lines(lines, precision) if network.leaves(): return None adjacency = { key: network.vertex_neighbors(key) for key in network.vertices() } root = network.get_any_vertex() ordering, predecessors, paths = depth_first_tree(adjacency, root) if len(ordering) != network.number_of_vertices(): return None mesh = Mesh.from_lines(lines, delete_boundary_face=True, precision=precision) for u, v, attr in mesh.edges(True): pt_u, pt_v = mesh.edge_coordinates(u, v) geo_u, geo_v = geometric_key(pt_u, precision), geometric_key( pt_v, precision) for i, geo_l_uv in enumerate(geo_lines): geo_l_u, geo_l_v = geo_l_uv[0], geo_l_uv[1] if (geo_l_u == geo_u) and (geo_l_v == geo_v): attr['dir'] = True elif (geo_l_u == geo_v) and (geo_l_v == geo_u): attr['dir'] = False else: continue attr['guid'] = str(crvs[i]) attr['length'] = rs.CurveLength(crvs[i]) # initiate flag for corners for fkey, attr in mesh.faces(True): mesh.set_face_attribute(fkey, 'corner', 0) mesh.set_face_attribute(fkey, 'opening', 0) return mesh
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 mesh_from_surface(cls, guid): """Construct a mesh from a Rhino surface. Parameters ---------- cls : Mesh A mesh type. guid : str The GUID of the Rhino surface. Returns ------- Mesh A mesh object. """ gkey_xyz = {} faces = [] obj = sc.doc.Objects.Find(guid) if not obj.Geometry.HasBrepForm: return brep = Rhino.Geometry.Brep.TryConvertBrep(obj.Geometry) for loop in brep.Loops: curve = loop.To3dCurve() segments = curve.Explode() face = [] sp = segments[0].PointAtStart ep = segments[0].PointAtEnd sp_gkey = geometric_key(sp) ep_gkey = geometric_key(ep) gkey_xyz[sp_gkey] = sp gkey_xyz[ep_gkey] = ep face.append(sp_gkey) face.append(ep_gkey) for segment in segments[1:-1]: ep = segment.PointAtEnd ep_gkey = geometric_key(ep) face.append(ep_gkey) gkey_xyz[ep_gkey] = ep faces.append(face) gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz)} vertices = [list(xyz) for gkey, xyz in gkey_xyz.items()] faces = [[gkey_index[gkey] for gkey in f] for f in faces] mesh = cls.from_vertices_and_faces(vertices, faces) return mesh
def split_quads_with_poles(self, poles): mesh = self.mesh pole_map = tuple([geometric_key(pole) for pole in poles]) faces = list(mesh.faces()) for fkey in faces: if len(mesh.face_vertices(fkey)) == 4: for vkey in mesh.face_vertices(fkey): if geometric_key( mesh.vertex_coordinates(vkey)) in pole_map: split_quad_in_pseudo_quads(mesh, fkey, vkey) break
def to_compas(self, cls=None): """Convert the surface b-rep loops to a COMPAS mesh. Parameters ---------- cls : :class:`compas.datastructures.Mesh`, optional The type of COMPAS mesh. Returns ------- :class:`compas.datastructures.Mesh` The resulting mesh. """ if not self.geometry.HasBrepForm: return brep = Rhino.Geometry.Brep.TryConvertBrep(self.geometry) gkey_xyz = {} faces = [] for loop in brep.Loops: curve = loop.To3dCurve() segments = curve.Explode() face = [] sp = segments[0].PointAtStart ep = segments[0].PointAtEnd sp_gkey = geometric_key(sp) ep_gkey = geometric_key(ep) gkey_xyz[sp_gkey] = sp gkey_xyz[ep_gkey] = ep face.append(sp_gkey) face.append(ep_gkey) for segment in segments[1:-1]: ep = segment.PointAtEnd ep_gkey = geometric_key(ep) face.append(ep_gkey) gkey_xyz[ep_gkey] = ep faces.append(face) gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz)} vertices = [list(xyz) for gkey, xyz in gkey_xyz.items()] faces = [[gkey_index[gkey] for gkey in f] for f in faces] polygons = [] for temp in faces: face = [] for vertex in temp: if vertex not in face: face.append(vertex) polygons.append(face) cls = cls or Mesh mesh = cls.from_vertices_and_faces(vertices, polygons) mesh.name = self.name return mesh
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 from_lines(cls, lines, precision=None): """Construct a network from a set of lines represented by their start and end point coordinates. Parameters ---------- lines : list A list of pairs of point coordinates. precision: str, optional The precision of the geometric map that is used to connect the lines. Returns ------- Network A network object. Examples -------- .. code-block:: python import json import compas from compas.datastructures import Network with open(compas.get('lines.json'), 'r') as fo: lines = json.load(fo) network = Network.from_lines(lines) """ network = cls() edges = [] vertex = {} for line in lines: sp = line[0] ep = line[1] a = geometric_key(sp, precision) b = geometric_key(ep, precision) vertex[a] = sp vertex[b] = ep edges.append((a, b)) key_index = dict((k, i) for i, k in enumerate(iter(vertex))) for key, xyz in iter(vertex.items()): i = key_index[key] network.add_vertex(i, x=xyz[0], y=xyz[1], z=xyz[2]) for u, v in edges: i = key_index[u] j = key_index[v] network.add_edge(i, j) return network
def from_vertices_and_faces_with_poles(cls, vertices, faces, poles=[]): pole_map = tuple([geometric_key(pole) for pole in poles]) mesh = cls.from_vertices_and_faces(vertices, faces) for fkey in mesh.faces(): face_vertices = mesh.face_vertices(fkey) if len(face_vertices) == 3: mesh.data['attributes']['face_pole'][fkey] = face_vertices[0] for vkey in face_vertices: if geometric_key( mesh.vertex_coordinates(vkey)) in pole_map: mesh.data['attributes']['face_pole'].update( {fkey: vkey}) break return mesh
def from_lines(cls, lines, boundary_face=False, precision='3f'): """""" from compas.datastructures.network.algorithms.duality import _sort_neighbours from compas.datastructures.network.algorithms.duality import _find_first_neighbour from compas.datastructures.network.algorithms.duality import _find_edge_face mesh = cls() edges = [] vertex = {} for line in lines: sp = line[0] ep = line[1] a = geometric_key(sp, precision) b = geometric_key(ep, precision) vertex[a] = sp vertex[b] = ep edges.append((a, b)) key_index = dict((k, i) for i, k in enumerate(iter(vertex))) for key, xyz in iter(vertex.items()): i = key_index[key] mesh.add_vertex(i, x=xyz[0], y=xyz[1], z=xyz[2]) edges_uv = [] for u, v in edges: i = key_index[u] j = key_index[v] edges_uv.append((i, j)) # the clear commands below are from the network equivalent. Needed? # network.clear_facedict() # network.clear_halfedgedict() mesh.halfedge = dict((key, {}) for key in mesh.vertex) for u, v in edges_uv: mesh.halfedge[u][v] = None mesh.halfedge[v][u] = None _sort_neighbours(mesh) u = sorted(mesh.vertices(True), key=lambda x: (x[1]['y'], x[1]['x']))[0][0] v = _find_first_neighbour(u, mesh) key_boundary_face = _find_edge_face(u, v, mesh) print(key_boundary_face) for u, v in mesh.edges(): if mesh.halfedge[u][v] is None: _find_edge_face(u, v, mesh) if mesh.halfedge[v][u] is None: _find_edge_face(v, u, mesh) if not boundary_face: mesh.delete_face(key_boundary_face) return mesh
def update_network_from_points(network, guids): points = rhino.get_point_coordinates(guids) names = rhino.get_object_names(guids) gkey_key = {geometric_key(network.vertex_coordinates(key)): key for key in network} for i, xyz in enumerate(points): name = names[i] try: attr = ast.literal_eval(name) except ValueError: pass else: gkey = geometric_key(xyz) if gkey in gkey_key: key = gkey_key[gkey] network.vertex[key].update(attr)
def check_element_exists(self, nodes, xyz=None): """ Check if an element already exists based on the nodes it connects to or its centroid. Parameters ---------- nodes : list Node numbers the element is connected to. xyz : list Direct co-ordinates of the element centroid to check. Returns ------- int The element index if the element already exists, None if not. Notes ----- - Geometric key check is made according to self.tol [m] tolerance. """ if not xyz: xyz = centroid_points([self.node_xyz(node) for node in nodes]) gkey = geometric_key(xyz, '{0}f'.format(self.tol)) return self.element_index.get(gkey, None)
def from_polygons(cls, polygons, precision=None): """Construct a mesh from a series of polygons. Parameters ---------- polygons : list A list of polygons, with each polygon defined as an ordered list of XYZ coordinates of its corners. precision: str, optional The precision of the geometric map that is used to connect the lines. Returns ------- Mesh A mesh object. """ faces = [] gkey_xyz = {} for points in polygons: face = [] for xyz in points: gkey = geometric_key(xyz, precision=precision) gkey_xyz[gkey] = xyz face.append(gkey) faces.append(face) gkey_index = {gkey: index for index, gkey in enumerate(gkey_xyz)} vertices = gkey_xyz.values() faces[:] = [[gkey_index[gkey] for gkey in face] for face in faces] return cls.from_vertices_and_faces(vertices, faces)
def add_element_to_element_index(self, key, nodes, virtual=False): """ Adds the element to the element_index dictionary. Parameters ---------- key : int Prescribed element key. nodes : list Node numbers the element is connected to. virtual: bool If true, adds element to the virtual_element_index dictionary. Returns ------- None """ centroid = centroid_points([self.node_xyz(node) for node in nodes]) gkey = geometric_key(centroid, '{0}f'.format(self.tol)) if virtual: self.virtual_element_index[gkey] = key else: self.element_index[gkey] = key
def check_element_exists(self, nodes=None, xyz=None, virtual=False): """ Check if an element already exists based on nodes or centroid. Parameters ---------- nodes : list Node numbers the element is connected to. xyz : list Direct co-ordinates of the element centroid to check. virtual: bool Is the element to be checked a virtual element. Returns ------- int The element index if the element already exists, None if not. Notes ----- - Geometric key check is made according to self.tol [m] tolerance. """ if not xyz: xyz = centroid_points([self.node_xyz(node) for node in nodes]) gkey = geometric_key(xyz, '{0}f'.format(self.tol)) if virtual: return self.virtual_element_index.get(gkey, None) else: return self.element_index.get(gkey, None)
def intersection_polyline_box_xy(polyline, box, tol=1e-6): """Compute the intersection between a polyline and a box in the XY plane. Parameters ---------- polyline : list of points or :class:`compas.geometry.Polyline` box : list of 4 points tol : float, optional A tolerance value for point comparison. Default is ``1e-6``. Returns ------- list A list of intersection points. """ precision = compas.PRECISION compas.set_precision(tol) points = [] for side in pairwise(box + box[:1]): for segment in pairwise(polyline): x = intersection_segment_segment_xy(side, segment, tol=tol) if x: points.append(x) points = {geometric_key(point): point for point in points} compas.PRECISION = precision return list(points.values())