Source code for gustaf.create.faces

"""gustaf/create/faces.py
Routines to create faces.
"""

import numpy as np

from gustaf import create, settings, utils
from gustaf.faces import Faces


[docs] def box( bounds=[[0, 0], [1, 1]], resolutions=[2, 2], simplex=False, backslash=False ): """Create structured quadrangle or triangle block mesh. Parameters ----------- bounds: (2, 2) array Minimum and maximum coordinates. resolutions: (2) array Vertex count in each dimension. simplex: boolean If true, Mesh will be triangular (simplex). Returns -------- face_mesh: Volumes """ if np.array(bounds).shape != (2, 2): raise ValueError("Bounds must have a dimension of (2, 2).") if len(resolutions) != 2: raise ValueError("Resolutions must have two entries.") if not np.greater(resolutions, 1).all(): raise ValueError("All resolution values must be at least 2.") if simplex: # create quad mesh as basis quad_mesh = box(bounds=bounds, resolutions=resolutions) # turn into triangles face_mesh = to_simplex(quad_mesh, backslash) else: vertex_mesh = create.vertices.raster(bounds, resolutions) connectivity = utils.connec.make_quad_faces(resolutions) face_mesh = Faces(vertex_mesh.vertices, connectivity) return face_mesh
[docs] def to_simplex(quad, alternate=False): """Given quad faces, diagonalize them to turn them into triangles. If quad is counterclockwise (CCW), triangle will also be CCW and vice versa. Will return a tri-mesh, if input is triangular. Default diagonalization looks like this: .. code-block:: (3) *---* (2) | /| | / | |/ | (0) *---* (1) resembling 'slash'. .. code-block:: (3) *---* (2) |\\ | | \\ | | \\| (0) *---* (1) resembling 'backslash'. If you want to alternate the `slash`-direction, set `alternate`-variable. Parameters ---------- quad: Faces Faces representation which is to be converted from a cubic mesh into a simplex mesh. alternate: bool Alternate between forward and back-slash to avoid "favored" meshing direction (important in some analysis problem). Returns -------- tri: Faces Simplexifyed mesh. """ if not isinstance(quad, Faces): raise ValueError( "Input to to_simplex needs to be of type Faces, but it's " + type(quad) ) if quad.whatami.startswith("quad"): # split variants split_slash = [[0, 1, 2], [2, 3, 0]] split_backslash = [[0, 1, 3], [3, 1, 2]] quad_faces = quad.faces tf_half = int(quad_faces.shape[0]) tri_faces = np.full((tf_half * 2, 3), -1, dtype=settings.INT_DTYPE) split = split_backslash if alternate else split_slash # If backslash assign every other with backslash else only forward tri_faces[0:tf_half:2] = quad_faces[0::2, split_slash[0]] tri_faces[1:tf_half:2] = quad_faces[1::2, split[0]] tri_faces[tf_half::2] = quad_faces[0::2, split_slash[1]] tri_faces[(tf_half + 1) :: 2] = quad_faces[1::2, split[1]] tri = Faces( vertices=quad.vertices.copy(), faces=tri_faces, ) else: tri = quad utils.log.debug( "Non quadrilateral mesh provided, return original" " mesh." ) return tri
[docs] def to_quad(tri): """ In case current mesh is triangle surface mesh, it splits triangle faces into three quad faces by inserting another vertices in the middle of each triangle face. Warning: mesh quality could be bad! ``(new) Quad Face`` .. code-block:: Ref: (node_ind), face_ind (2) / \ / 2 \ (5)/\\ /\\(4) / \\ / \ / 0 |(6) \ /_____|___1_\ (0) (3) (1) face_ind | node_ind ---------|---------- 0 | 0 3 6 5 1 | 1 4 6 3 2 | 2 5 6 4 Parameters ----------- None Returns -------- quad_mesh: Mesh Only if current mesh is triangle surface mesh. Otherwise, None. """ if tri.elements is None: return None if not tri.whatami.startswith("tri"): return None # Form new vertices: 1. mid edge vertices; 2. center vertices. edge_mids = tri.to_edges(unique=True).centers() # New vertices - current vertices & mid edge vertices & center vertices vertices = np.vstack( ( tri.const_vertices, edge_mids, tri.centers(), ) ) em_offset = len(tri.vertices) # edge mid offset fc_offset = len(tri.vertices) + len(edge_mids) # faces center offset # New faces - current faces * 3, as each triangle face should produce # 3 quad faces faces = np.empty((tri.faces.shape[0] * 3, 4), dtype=settings.INT_DTYPE) # Assign face ind # First col. faces[:, 0] = tri.faces.ravel() # Second col. edge_mid_column = tri.unique_edges().inverse + em_offset faces[:, 1] = edge_mid_column # Third col. faces[:, 2] = np.repeat(np.arange(len(tri.faces)) + fc_offset, 3) # Fourth col. faces[:, 3] = edge_mid_column.reshape(-1, 3)[:, [2, 0, 1]].ravel() return Faces(vertices=vertices, faces=faces)