Skip to content

Commit

Permalink
feat: allow meshes to be exported
Browse files Browse the repository at this point in the history
  • Loading branch information
xgui3783 committed Nov 22, 2023
1 parent 5c433a6 commit c78ab0a
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ nilearn
typing-extensions; python_version < "3.8"
filelock
ebrains-drive >= 0.6.0
trimesh
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ def find_version():
'typing-extensions; python_version < "3.8"',
"filelock",
"ebrains-drive >= 0.6.0",
"trimesh",
],
)
3 changes: 3 additions & 0 deletions siibra/commons.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# limitations under the License.
"""Constants, functions, and classes used commonly across siibra."""

from .surface import wrap_return_surface

import os
import re
from enum import Enum
Expand Down Expand Up @@ -677,6 +679,7 @@ def is_mesh(structure: Union[list, dict]):
return False


@wrap_return_surface()
def merge_meshes(meshes: list, labels: list = None):
# merge a list of meshes into one
# if meshes have no labels, a list of labels of the
Expand Down
1 change: 1 addition & 0 deletions siibra/surface/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .common import Surface, wrap_return_surface
63 changes: 63 additions & 0 deletions siibra/surface/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from typing import List, Union, IO
import numpy as np
import trimesh
from io import BytesIO
from functools import wraps

class Surface:
def __init__(self, vertices: List[List[float]]=None,
faces: List[List[int]]=None,
vertices_labels: List[List[Union[float, int]]]=None,
**kwargs) -> None:
"""Describes a common interface to surface, where vertices
faces are defined, and optionally, vertices labels, face labels
can be defined.
Args:
vertices (List[List[float]] or ndarray): verticies triplet
faces: (List[List[int]] or ndarray): faces triplet
vertices_labels: (Labels)"""

self.vertices = np.array(kwargs.get("verts", []) if vertices is None else vertices)
self.faces = np.array([] if faces is None else faces, dtype=np.uint64)

vertices_labels = kwargs.get("labels", []) if vertices_labels is None else vertices_labels
self.vertices_labels = np.array(vertices_labels)

def __contains__(self, spec):
self.faces
if spec in ("verts", "faces"):
return True
if spec == "labels":
return len(self.vertices_labels) > 0
return False

def __getitem__(self, spec: str):
if spec == "verts":
return self.vertices
if spec == "faces":
return self.faces
if spec == "labels":
if len(self.vertices_labels) > 0:
return self.vertices_labels
raise IndexError(f"spec {spec!r} not found in class surface")

def export(self, export_dest: Union[str, IO]):
mesh = trimesh.Trimesh(self.vertices, self.faces)
mesh.export(export_dest)

def to_bytes(self):
io = BytesIO()
mesh = trimesh.Trimesh(self.vertices, self.faces)
mesh.export(io, file_obj="obj")
io.seek(0)
return io.read()

def wrap_return_surface():
def outer(fn):
@wraps(fn)
def inner(*args, **kwargs):
return_val = fn(*args, **kwargs)
return Surface(**return_val)
return inner
return outer
2 changes: 2 additions & 0 deletions siibra/volumes/providers/neuroglancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ...commons import logger, MapType, merge_meshes
from ...retrieval import requests, cache
from ...locations import boundingbox as _boundingbox
from ...surface import wrap_return_surface

from neuroglancer_scripts.precomputed_io import get_IO_for_existing_dataset
from neuroglancer_scripts.accessor import get_accessor_for_url
Expand Down Expand Up @@ -552,6 +553,7 @@ def _get_fragment_info(self, meshindex: int) -> Dict[str, Tuple[str, ]]:

return result

@wrap_return_surface()
def _fetch_fragment(self, url: str, transform_nm: np.ndarray):
r = requests.HttpRequest(url, func=lambda b: BytesIO(b))
(vertices_vox, triangles_vox) = read_precomputed_mesh(r.data)
Expand Down

0 comments on commit c78ab0a

Please sign in to comment.