Source code for plugins.isosurface

#
##
##  SPDX-FileCopyrightText: © 2007-2023 Benedict Verhegghe <bverheg@gmail.com>
##  SPDX-License-Identifier: GPL-3.0-or-later
##
##  This file is part of pyFormex 3.4  (Thu Nov 16 18:07:39 CET 2023)
##  pyFormex is a tool for generating, manipulating and transforming 3D
##  geometrical models by sequences of mathematical operations.
##  Home page: https://pyformex.org
##  Project page: https://savannah.nongnu.org/projects/pyformex/
##  Development: https://gitlab.com/bverheg/pyformex
##  Distributed under the GNU General Public License version 3 or later.
##
##  This program is free software: you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see http://www.gnu.org/licenses/.
##
#
"""Isosurface: surface reconstruction algorithms

This module contains

"""
import numpy as np

from pyformex.lib import misc
from pyformex.multi import multitask, cpu_count, splitar


[docs]def isosurface(data, level, nproc=-1, tet=0): """Create an isosurface through data at given level. Parameters ---------- data: :term:`array_like` An (nx,ny,nz) shaped float array of data values at points with coordinates equal to their indices. This defines a 3D volume [0,nx-1], [0,ny-1], [0,nz-1]. level: float The data value for which the isosurface is to be constructed. nproc: int The number of parallel processes to use. On multiprocessor machines this may be used to speed up the processing. If <= 0 , the number of processes will be set equal to the number of available processors, to achieve a maximal speedup. tet: int If zero (default), a marching cubes algiorithm is used. If nonzero, a marching tetrahedrons algorithm is used. The latter is slower and produces a lot more triangles, but results in a smoother surface. The tetraeders algorithm is currently only available in the compiled pyFormex library. Returns ------- array: An (ntr,3,3) float array defining the triangles of the isosurface. The result may be empty (if level is outside the data range). Notes ----- Currently only a marching cubes algorithm is used. Marching tetraeders is not implemented yet. """ if nproc is None: nproc = -1 if nproc < 1: nproc = cpu_count() if nproc == 1: # Perform single process isosurface (accelerated) data = data.astype(np.float32) level = np.float32(level) tri = misc.isosurface(data, level, tet) else: # Perform parallel isosurface # 1. Split in blocks (and remember shift) datablocks = splitar(data, nproc, close=True) shift = (np.array([d.shape[0] for d in datablocks]) - 1).cumsum() # 2. Solve blocks independently tasks = [(isosurface, (d, level, 1, tet)) for d in datablocks] tri = multitask(tasks, nproc) # 3. Shift and merge blocks for t, s in zip(tri[1:], shift[:-1]): t[:, :, 2] += s tri = np.concatenate(tri, axis=0) return tri
[docs]def isoline(data, level, nproc=-1): """Create an isocontour through data at given level. Parameters ---------- data: :term:`array_like` An (nx,ny) shaped array of data values at points with coordinates equal to their indices. This defines a 2D area [0,nx-1], [0,ny-1]. level: float The data value for which the isocontour is to be constructed. nproc: int The number of parallel processes to use. On multiprocessor machines this may be used to speed up the processing. If <= 0 , the number of processes will be set equal to the number of available processors, to achieve a maximal speedup. Returns ------- array: An (nseg,2,2) float array defining the 2D coordinates of the segments of the isocontour. The result may be empty (if level is outside the data range). """ if nproc is None: nproc = -1 if nproc < 1: nproc = cpu_count() if nproc == 1: # Perform single process isoline (accelerated) data = data.astype(np.float32) level = np.float32(level) seg = misc.isoline(data, level) else: # Perform parallel isoline # 1. Split in blocks (and remember shift) datablocks = splitar(data, nproc, close=True) shift = (np.array([d.shape[0] for d in datablocks]) - 1).cumsum() # 2. Solve blocks independently tasks = [(isoline, (d, level, 1)) for d in datablocks] seg = multitask(tasks, nproc) # 3. Shift and merge blocks for t, s in zip(seg[1:], shift[:-1]): t[:, :, 1] += s seg = np.concatenate(seg, axis=0) return seg
# End