Beispiel #1
0
def mesh_and_extract_largest_connected_surface(volume, level_set):
    vertices, faces = marching_cubes(volume, level_set)
    mesh = Trimesh()
    mesh.vertices = vertices
    mesh.faces = faces
    meshes = mesh.split(only_watertight=False)
    sorted_meshes = sorted(meshes, key=lambda x: len(x.vertices))
    return sorted_meshes[-1]
Beispiel #2
0
def voxelize(mesh: Trimesh, dims:int = 14) -> ndarray:
    workdir = mkdtemp()
    TMP_FILE_NAME = workdir + '/voxelization'
    TMP_STL_FILE_NAME = TMP_FILE_NAME + '.stl'
    TMP_BINVOX_FILE_NAME = TMP_FILE_NAME + '.binvox'
    mesh.export(TMP_STL_FILE_NAME, 'stl')
    cmd_std = sh(dirname(realpath(__file__)) + "/binvox", '-d' , str(dims) , TMP_STL_FILE_NAME)
    vox_matrix = read_as_3d_array(open(TMP_BINVOX_FILE_NAME, 'rb'), fix_coords=True)
    return vox_matrix
Beispiel #3
0
 def __init__(self, faces=None, vertices=None, **kwargs):
     """
     SuperClass for Revitinterface option
     """
     RevitInterface.__init__(self, **kwargs)
     Trimesh.__init__(self, vertices=vertices, faces=faces)
     self._reps = {}
     self._facet_centroids = None
     self._convex_comps = None
     self._current_rep = 'mesh'
     self._axis = []
Beispiel #4
0
 def __init__(self, faces=None, vertices=None, **kwargs):
     """
     Arbitrary thing assumed to be a line-based geometry
     """
     CadInterface.__init__(self, **kwargs)
     Trimesh.__init__(self, vertices=vertices, faces=faces)
     self._reps = {}
     self._facet_centroids = None
     self._current_rep = 'mesh'
     self._convex_comps = None
     # axis is two facet_box indices
     self._axis = []
Beispiel #5
0
def average_properties(vertices: np.ndarray,
                       faces: np.ndarray,
                       properties: np.ndarray,
                       norm: bool = False) -> Union[float, np.ndarray]:
    """
    Average property across an isosurface.

    Args:
        vertices: A (n, 3) float array of the vertices in the isosurface.
        faces: A (m, 3) int array of the faces of the isosurface.
        properties: A (m, ...) array of the face properties as scalars or vectors.
        norm: Whether to average the norm of the properties (vector properties only).

    Returns:
        The averaged property.
    """
    from trimesh import Trimesh

    mesh = Trimesh(vertices=vertices, faces=faces)

    if norm and properties.ndim > 1:
        properties = np.linalg.norm(properties, axis=1)

    face_areas = mesh.area_faces

    # face_areas has to have same number of dimensions as property
    face_areas = face_areas.reshape(face_areas.shape + (1, ) *
                                    (properties.ndim - 1))

    return np.sum(properties * face_areas, axis=0) / mesh.area
Beispiel #6
0
def ptcld_as_isosurf(pts, out_obj, res=128, center=False):
    """Visualizes point cloud as isosurface of its TDF.

    Args:
        pts (array_like): Cartesian coordinates in object space, of shape
            N-by-3.
        out_obj (str): The output path of the surface .obj.
        res (int, optional): Resolution of the TDF.
        center (bool, optional): Whether to center these points around object
            space origin.

    Writes
        - The .obj file of the isosurface.
    """
    from skimage.measure import marching_cubes_lewiner
    from trimesh import Trimesh
    from trimesh.io.export import export_mesh
    from ..geometry.ptcld import ptcld2tdf

    # Point cloud to TDF
    tdf = ptcld2tdf(pts, res=res, center=center)

    # Isosurface of TDF
    vs, fs, ns, _ = marching_cubes_lewiner(tdf,
                                           0.999 / res,
                                           spacing=(1 / res, 1 / res, 1 / res))

    mesh = Trimesh(vertices=vs, faces=fs, normals=ns)
    export_mesh(mesh, out_obj)
Beispiel #7
0
    def __getitem__(self, idx):
        """ Returns an item of the dataset.

        Args:
            idx (int): ID of datasets point
        """
        data_path = self.data[idx]
        np_data = np.load(data_path, allow_pickle=True)

        to_ret = {
            'can_vertices': np_data['can_vertices'].astype(np.float32),
        }

        # sample points
        to_ret.update(
            self.sample_points(Trimesh(to_ret['can_vertices'], self.faces),
                               self.n_points_can,
                               prefix='can_'))

        # proxy skinning weights
        to_ret['can_points_sk_weights'] = self.compute_sk_weights(
            to_ret['can_vertices'], to_ret['can_points'],
            np_data['gender'].item())

        return to_ret
Beispiel #8
0
    def add_data_files(self, np_data, to_ret):
        # sample training points
        to_ret.update(
            self.sample_points(Trimesh(to_ret['posed_vertices'], self.faces),
                               self.n_points_posed,
                               compute_occupancy=True))

        to_ret.update(
            self.sample_points(Trimesh(to_ret['can_vertices'], self.faces),
                               self.n_points_can,
                               prefix='can_',
                               compute_occupancy=True))

        to_ret['can_points_sk_weights'] = self.compute_sk_weights(
            to_ret['can_vertices'], to_ret['can_points'],
            np_data['gender'].item())
Beispiel #9
0
def ptcld_as_isosurf(pts, out_obj, res=128, center=False):
    """
    Visualize point cloud as isosurface of its TDF

    Args:
        pts: Cartesian coordinates in object space
            n-by-3 array_like of floats
        out_obj: The output path of the surface .obj
            String
        res: Resolution of the TDF
            Integer
            Optional; defaults to 128
        center: Whether to center these points around object space origin
            Boolean
            Optional; defaults to False
    """
    from skimage.measure import marching_cubes_lewiner
    from trimesh import Trimesh
    from trimesh.io.export import export_mesh
    from xiuminglib import geometry as xgeo

    # Point cloud to TDF
    tdf = xgeo.ptcld2tdf(pts, res=res, center=center)

    # Isosurface of TDF
    vs, fs, ns, _ = marching_cubes_lewiner(tdf,
                                           0.999 / res,
                                           spacing=(1 / res, 1 / res, 1 / res))

    mesh = Trimesh(vertices=vs, faces=fs, normals=ns)
    export_mesh(mesh, out_obj)
Beispiel #10
0
def main(args):
    if args.epoch is None:
        epochs = Path(f"lightning_logs/version_{args.version}/checkpoints/"
                      ).glob('*.ckpt')
        epochs = list(
            map(lambda x: int(re.match(r"epoch=([0-9]+)", x.stem).group(1)),
                epochs))
        print(epochs)
        epoch = max(epochs)
    else:
        epoch = args.epoch

    model = SALD.load_from_checkpoint(
        f"lightning_logs/version_{args.version}/checkpoints/epoch={epoch}.ckpt"
    )

    if args.object is not None:
        objId = int(args.object)
    else:
        objId = np.random.randint(0, model.embedding.num_embeddings)

    grid = model.voxelize(objId, args.res).detach().numpy()
    verts, faces, normals, values = measure.marching_cubes(grid, 0)
    mesh = Trimesh(vertices=verts, faces=faces)
    scene = Scene([mesh])
    viewer = SceneViewer(scene)
Beispiel #11
0
    def get_fermi_slice(
        self, plane_normal: Tuple[int, int, int], distance: float = 0
    ) -> FermiSlice:
        """
        Get a slice through the Fermi surface, defined by the intersection of a plane
        with the fermi surface.

        Args:
            plane_normal: The plane normal in fractional indices. E.g., ``(1, 0, 0)``.
            distance: The distance from the center of the Brillouin zone (the Gamma
                point).

        Returns:
            The Fermi slice.

        """
        cart_normal = np.dot(plane_normal, self.reciprocal_space.reciprocal_lattice)
        cart_origin = cart_normal * distance

        slices = {}
        for spin, spin_isosurfaces in self.isosurfaces.items():
            spin_slices = []

            for verts, faces in spin_isosurfaces:
                mesh = Trimesh(vertices=verts, faces=faces)
                lines = mesh_multiplane(mesh, cart_origin, cart_normal, [0])[0][0]
                spin_slices.append(lines)

            slices[spin] = spin_slices

        reciprocal_slice = self.reciprocal_space.get_reciprocal_slice(
            plane_normal, distance
        )

        return FermiSlice(slices, reciprocal_slice, self.structure)
Beispiel #12
0
def calculate_scaling(local_neighborhood, local_positions,
                      corresponding_positions, iteration, max_iterations):
    # scale oriented bounding box to be same size
    # use trimesh for min OBBs
    local_trimesh = Trimesh([local_positions[v] for v in local_neighborhood])
    local_extents = local_trimesh.bounding_box_oriented.primitive.extents.copy(
    )
    local_extents.sort()
    corresponding_trimesh = Trimesh([corresponding_positions.values()])
    corresponding_extents = corresponding_trimesh.bounding_box_oriented.primitive.extents.copy(
    )
    corresponding_extents.sort()
    scaling_factor = iteration / max_iterations
    scaling = (local_extents + (corresponding_extents - local_extents) *
               scaling_factor) / local_extents
    return np.matrix(np.diag(np.append(
        scaling, 1)))  # matlib's diag() still makes arrays
Beispiel #13
0
def _to_unit_cube(mesh: trimesh.Trimesh):

    bounds = mesh.extents
    if bounds.min() == 0.0:
        return

    # translate to origin
    translation = (mesh.bounds[0] + mesh.bounds[1]) * 0.5
    translation = trimesh.transformations.translation_matrix(direction=-translation)
    mesh.apply_transform(translation)

    # scale to unit cube
    scale = 1.0/bounds.max()
    scale_trafo = trimesh.transformations.scale_matrix(factor=scale)
    mesh.apply_transform(scale_trafo)

    return mesh
Beispiel #14
0
 def _as_box2(self):
     b = Trimesh(vertices=self.vertices).convex_hull.bounding_box_oriented
     bx = self.__class__(vertices=b.vertices,
                         faces=b.faces,
                         **self.base_args)
     bx._reps[self._current_rep] = self
     bx._current_rep = 'box'
     return bx
Beispiel #15
0
def repair_mesh(mesh: Trimesh) -> Trimesh:
    """
    Repair the given mesh using pymeshfix.
    """
    mf = pymeshfix.MeshFix(mesh.vertices, mesh.faces)
    mf.repair()

    return Trimesh(mf.v, mf.f)
Beispiel #16
0
def smooth_laplacian(vertices, faces, **kwargs):
    """Smooth vertices and faces using a Laplacian filter"""
    from trimesh.smoothing import filter_humphrey
    from trimesh import Trimesh

    kwargs.setdefault("iterations", 2)
    mesh = Trimesh(vertices, faces)
    filter_humphrey(mesh, **kwargs)
    return mesh.vertices, mesh.faces
Beispiel #17
0
def connected_subsurfaces(
        vertices: np.ndarray,
        faces: np.ndarray) -> List[Tuple[np.ndarray, np.ndarray]]:
    """
    Find connected sub-surfaces (those that share edges).

    Args:
        vertices: A (n, 3) float array of the vertices in the isosurface.
        faces: A (m, 3) int array of the faces of the isosurface.

    Returns:
        A list of of (vertices, faces) for each sub-surface.
    """
    from trimesh import Trimesh

    mesh = Trimesh(vertices=vertices, faces=faces)
    connected_meshes = mesh.split(only_watertight=False)
    return [(m.vertices, m.faces) for m in connected_meshes]
Beispiel #18
0
 def _get_points_near_surface(mesh: trimesh.Trimesh, num_query_pts_close, patch_radius, rng):
     samples, face_id = mesh.sample(num_query_pts_close, return_index=True)
     offset_factor = (rng.random(size=(num_query_pts_close,)) - 0.5) * 2.0 * patch_radius
     sample_normals = mesh.face_normals[face_id]
     sample_normals_len = np.sqrt(np.linalg.norm(sample_normals, axis=1))
     sample_normals_len_broadcast = np.broadcast_to(np.expand_dims(sample_normals_len, axis=1), sample_normals.shape)
     sample_normals_normalized = sample_normals / sample_normals_len_broadcast
     offset_factor_broadcast = np.broadcast_to(np.expand_dims(offset_factor, axis=1), sample_normals.shape)
     noisy_samples = samples + offset_factor_broadcast * sample_normals_normalized
     return noisy_samples
Beispiel #19
0
def export_mesh_as_threejs(vertices, triangles):

  vertices = vertices.astype('float')

  mesh = Trimesh(vertices = vertices, faces = triangles)
  mesh.fix_normals()

  #add column with zeros
  s = mesh.faces.shape
  faces = np.zeros(shape= (s[0], s[1]+1) )
  faces[:,1:4] = mesh.faces

  data = {
    "metadata": { "formatVersion" : 3 },    
    "vertices": list(mesh.vertices.reshape(-1)),
    "normals": list(mesh.vertex_normals.reshape(-1)),
    "faces": list(faces.reshape(-1))
    }

  
  return data
Beispiel #20
0
    def __init__(self, vertices=None, mesh=None, debug=False, **kwargs):
        if mesh is None and vertices is not None:
            mesh = Trimesh(vertices=vertices).convex_hull.bounding_box_oriented

        Trimesh.__init__(self, vertices=mesh.vertices, faces=mesh.faces)
        vert_face = self.vertices[self.faces[self.facets]]

        # facet centroids np.shape([6, 3])
        self._facet_centers = vert_face.reshape(self.facets.shape[0], -1,
                                                3).mean(axis=1)

        fct_norm = self.facets_normal
        mn1, mn2 = np.where(
            np.isclose(spatial.distance.cdist(fct_norm, -fct_norm), 0.))

        # pairs of axis points of obb : [ 3, 2]
        self._pairs = np.unique([sorted(v) for v in zip(mn1, mn2)], axis=0)
        lines = []
        for n1, n2 in zip(self.axes_vertices[:, 0, :],
                          self.axes_vertices[:, 1, :]):
            lines.append(lib.geo.Line(lib.geo.Point(n1), lib.geo.Point(n2)))
        self._axis_skel = AxisSkeleton(lines)
Beispiel #21
0
def main():
    parser = create_parser()
    args = parser.parse_args()
    print 'fname:', args.fname
    g = fio.read_geometry(args.fname)
    m = Trimesh(g[0], g[1])
    if args.outname is None:
        # (name, ext) = os.path.splitext(args.fname)
        outname = '%s.stl' % args.fname
    else:
        outname = args.outname
    print 'outname:', outname
    export_mesh(m, outname)
Beispiel #22
0
    def isosurface(self, isovalue=0.0):
        from trimesh import Trimesh
        from chmpy.mc import marching_cubes

        vol = self.data.reshape((self.nx, self.ny, self.nz))
        seps = (
            np.linalg.norm(self.x_basis),
            np.linalg.norm(self.y_basis),
            np.linalg.norm(self.z_basis),
        )
        verts, faces, normals, _ = marching_cubes(vol,
                                                  level=isovalue,
                                                  spacing=seps)
        return Trimesh(vertices=verts, faces=faces, normals=normals)
Beispiel #23
0
def isosurface_dimensionality(
        fractional_vertices: np.ndarray,
        faces: np.ndarray) -> Tuple[str, Tuple[int, int, int]]:
    """
    Calculate isosurface properties a single isosurface (fully connected).

    The vertices must cover a 3x3x3 supercell and must not have been trimmed to fit
    inside the reciprocal lattice.

    Note: This function expects the vertices to only belong to a single connected
    mesh, and the vertices should cover a 3x3x3 supercell, where the coordinates
    from -0.5 to 0.5 indicate the center image.

    Args:
        fractional_vertices: A (n, 3) float array of the vertices in the isosurface
            in fractional coordinates.
        faces: A (m, 3) int array of the faces of the isosurface.

    Returns:
        The dimensionality and (n, 3) int array orientation of the isosurface.
    """
    from trimesh import Trimesh

    if len(connected_subsurfaces(fractional_vertices, faces)) != 1:
        raise ValueError("isosurface contains multiple subsurfaces")

    images = connected_images(fractional_vertices)

    rank = np.linalg.matrix_rank(images)
    orientation = None

    if rank == 1:
        orientation = line_orientation(images)
        dimensionality = "2D"
    elif rank == 2:
        orientation = plane_orientation(images)

        # use euler number to decide if mesh is a plane or multiple tubes
        euler_number = Trimesh(vertices=fractional_vertices,
                               faces=faces).euler_number
        if euler_number == 1:
            dimensionality = "1D"
        else:
            dimensionality = "quasi-2D"
    elif rank == 0:
        dimensionality = "3D"
    else:
        dimensionality = "quasi-3D"

    return dimensionality, orientation
    def __init__(self, files):
        if isinstance(files, tuple):
            white = read_geometry(files[0])
            pial = read_geometry(files[1])
            vertices = (pial[0] - white[0]) / 2
            faces = pial[1]
            
        else:
            mid = read_geometry(files)
            vertices = mid[0]
            faces = mid[1]

        self.vertices = vertices
        self.faces = faces
        self.mesh = Trimesh(vertices=self.vertices, faces=self.faces)
Beispiel #25
0
def isosurface_area(vertices: np.ndarray, faces: np.ndarray) -> float:
    """
    Calculate the area of an isosurface.

    Args:
        vertices: A (n, 3) float array of the vertices in the isosurface.
        faces: A (m, 3) int array of the faces of the isosurface.

    Returns:
        The area of the isosurface, in Å^-2.
    """
    from trimesh import Trimesh

    mesh = Trimesh(vertices=vertices, faces=faces)
    return mesh.area
def create_trimesh_from_obj(obj):
  vertices, faces = get_vertices_and_faces(obj)

  tmesh = Trimesh(vertices=vertices, faces=faces)

  if tmesh.is_empty:
    raise ValueError("Mesh is empty!")
  if not tmesh.is_watertight:
    raise ValueError("Mesh is not watertight (has holes)!")
  if not tmesh.is_winding_consistent:
    raise ValueError("Mesh is not winding consistent!")
  if tmesh.body_count > 1:
    raise ValueError("Mesh consists of more than one connected component (bodies)!")

  return tmesh
Beispiel #27
0
def gen_intersecting_mesh(base_mesh, bodies):
    """Generates mesh of tows that are intersecting with ray offset

    
    Parameters
    ----------
    base_mesh : Trimesh
        Mesh of exisiting tows already laid down
    bodies: set(int)
        Indexes of bodies intersecting with the new tow
    
    Returns
    -------
    Trimesh
        Subset of base_mesh, containing only the tows from bodies
        
    """

    # Create copy of mesh so to not change any face data
    mesh_copy = base_mesh
    # Body count should be equivalent to the number of tows - make sure not to merge vertices
    body_count = mesh_copy.body_count
    # Split mesh modies into individual tow meshes
    mesh_bodies = mesh_copy.split(only_watertight=False)
    if (len(bodies) is 0):
        return Trimesh()

    # Based on interesting bodies, create new mesh with only those bodies
    intersecting = Trimesh()
    for i in bodies:
        if intersecting.is_empty:
            intersecting = mesh_bodies[i - 1]
        else:
            intersecting = intersecting.__add__(mesh_bodies[i - 1])

    return intersecting
def make_mesh(norms: ndarray, vertices: ndarray) -> Trimesh:
    # Convert to Mesh coordinates
    faces = []
    verts = []

    for idx in range(0, len(norms)):
        norm_x, norm_y, norm_z = norms[idx]
        x1, y1, z1, x2, y2, z2, x3, y3, z3 = vertices[idx]
        faces += [[norm_x, norm_y, norm_z]]
        verts += [[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]]

    # Convert to Mesh
    return Trimesh(vertices=array(verts),
                   faces=arange(int(len(faces) * 3)).reshape((-1, 3)),
                   face_normals=array(faces))
Beispiel #29
0
    def cut_by_plane(self, projection=SAGITTAL, ras=ORIGIN):
        """
        :param projection:
        :param ras:
        :return: Y_array, X_array
        """
        mesh = Trimesh(self.vertices, self.triangles)
        contours = intersections.mesh_plane(
            mesh, PLANE_NORMALS[projection], self._get_plane_origin(ras))
        x_array = [0] * len(contours)
        y_array = [0] * len(contours)

        for s in range(len(contours)):
            x_array[s] = contours[s][:, X_Y_INDEX[projection][0]]
            y_array[s] = contours[s][:, X_Y_INDEX[projection][1]]

        return x_array, y_array
Beispiel #30
0
def vtk2trimesh(mesh):
    """
    Convert ``vtkplotter.Mesh`` to ``Trimesh.Mesh`` object.
    """
    if isSequence(mesh):
        tms = []
        for a in mesh:
            tms.append(vtk2trimesh(a))
        return tms

    from trimesh import Trimesh

    lut = mesh.mapper().GetLookupTable()

    tris = mesh.faces()
    carr = mesh.getCellArray('CellColors')
    ccols = None
    if carr is not None and len(carr) == len(tris):
        ccols = []
        for i in range(len(tris)):
            r, g, b, a = lut.GetTableValue(carr[i])
            ccols.append((r * 255, g * 255, b * 255, a * 255))
        ccols = np.array(ccols, dtype=np.int16)

    points = mesh.points()
    varr = mesh.getPointArray('VertexColors')
    vcols = None
    if varr is not None and len(varr) == len(points):
        vcols = []
        for i in range(len(points)):
            r, g, b, a = lut.GetTableValue(varr[i])
            vcols.append((r * 255, g * 255, b * 255, a * 255))
        vcols = np.array(vcols, dtype=np.int16)

    if len(tris) == 0:
        tris = None

    return Trimesh(vertices=points,
                   faces=tris,
                   face_colors=ccols,
                   vertex_colors=vcols)
Beispiel #31
0
def vtk2trimesh(actor):
    """
    Convert vtk ``Actor`` to ``Trimesh`` object.
    """
    if isSequence(actor):
        tms = []
        for a in actor:
            tms.append(vtk2trimesh(a))
        return tms

    from trimesh import Trimesh

    lut = actor.mapper().GetLookupTable()

    tris = actor.faces()
    carr = actor.scalars('CellColors', datatype='cell')
    ccols = None
    if carr is not None and len(carr) == len(tris):
        ccols = []
        for i in range(len(tris)):
            r, g, b, a = lut.GetTableValue(carr[i])
            ccols.append((r * 255, g * 255, b * 255, a * 255))
        ccols = np.array(ccols, dtype=np.int16)

    points = actor.coordinates()
    varr = actor.scalars('VertexColors', datatype='point')
    vcols = None
    if varr is not None and len(varr) == len(points):
        vcols = []
        for i in range(len(points)):
            r, g, b, a = lut.GetTableValue(varr[i])
            vcols.append((r * 255, g * 255, b * 255, a * 255))
        vcols = np.array(vcols, dtype=np.int16)

    if len(tris) == 0:
        tris = None

    return Trimesh(vertices=points,
                   faces=tris,
                   face_colors=ccols,
                   vertex_colors=vcols)
Beispiel #32
0
def box_from_bounds(mn, mx):
    """
    in a right-hand system :
                  3-------7
                 /|      /|
                2-------6 |
                | 1-----|-5
                |/      |/
                0-------4
    OBB returns points thusly:
        0 (self.max[0], self.max[1], self.min[2])),
        1 (self.min[0], self.max[1], self.min[2])),
        2 (self.min[0], self.max[1], self.max[2])),
        3 (self.max),
        4 (self.min),
        5 self.max[0], self.min[1], self.min[2]),
        6 self.max[0], self.min[1], self.max[2]),
        7 self.min[0], self.min[1], self.max[2])
    """
    vs = [
        mn, [mn[0], mx[1], mn[2]], [mn[0], mn[1], mx[2]],
        [mn[0], mx[1], mx[2]], [mx[0], mn[1], mn[2]], [mx[0], mx[1], mn[2]],
        [mx[0], mn[1], mx[2]], mx
    ]

    fcs = np.asarray([
        [0, 1, 2],
        [1, 2, 3],
        [0, 1, 4],
        [1, 4, 5],
        [0, 2, 4],
        [2, 4, 6],
        [2, 3, 6],
        [2, 6, 7],
        [4, 5, 6],
        [5, 6, 7],
        [3, 5, 7],
        [1, 3, 5],
    ])
    return Trimesh(vertices=vs, faces=fcs, process=True).bounding_box