Repository: AljazBozic/NeuralGraph
Branch: main
Commit: 5ac74b668ef4
Files: 372
Total size: 5.0 MB
Directory structure:
gitextract_wl6wrwv6/
├── .gitignore
├── LICENSE
├── README.md
├── build_external.sh
├── config.py
├── dataset/
│ ├── dataset.py
│ └── generate_dataset.py
├── external/
│ ├── PyMarchingCubes/
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── LICENSE
│ │ ├── MANIFEST.in
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── .gitignore
│ │ │ └── spheres.py
│ │ ├── marching_cubes/
│ │ │ ├── __init__.py
│ │ │ ├── exporter.py
│ │ │ ├── numpy_smoothing.py
│ │ │ ├── smoothing.py
│ │ │ └── src/
│ │ │ ├── _mcubes.pyx
│ │ │ ├── marchingcubes.cpp
│ │ │ ├── marchingcubes.h
│ │ │ ├── pyarray_symbol.h
│ │ │ ├── pyarraymodule.h
│ │ │ ├── pywrapper.cpp
│ │ │ └── pywrapper.h
│ │ ├── requirements.txt
│ │ ├── setup.py
│ │ ├── test_mcubes.py
│ │ └── test_smoothing.py
│ ├── eigen3/
│ │ └── Eigen/
│ │ ├── Cholesky
│ │ ├── CholmodSupport
│ │ ├── Core
│ │ ├── Dense
│ │ ├── Eigen
│ │ ├── Eigenvalues
│ │ ├── Geometry
│ │ ├── Householder
│ │ ├── IterativeLinearSolvers
│ │ ├── Jacobi
│ │ ├── LU
│ │ ├── MetisSupport
│ │ ├── OrderingMethods
│ │ ├── PaStiXSupport
│ │ ├── PardisoSupport
│ │ ├── QR
│ │ ├── QtAlignedMalloc
│ │ ├── SPQRSupport
│ │ ├── SVD
│ │ ├── Sparse
│ │ ├── SparseCholesky
│ │ ├── SparseCore
│ │ ├── SparseLU
│ │ ├── SparseQR
│ │ ├── StdDeque
│ │ ├── StdList
│ │ ├── StdVector
│ │ ├── SuperLUSupport
│ │ ├── UmfPackSupport
│ │ └── src/
│ │ ├── Cholesky/
│ │ │ ├── LDLT.h
│ │ │ ├── LLT.h
│ │ │ └── LLT_LAPACKE.h
│ │ ├── CholmodSupport/
│ │ │ └── CholmodSupport.h
│ │ ├── Core/
│ │ │ ├── Array.h
│ │ │ ├── ArrayBase.h
│ │ │ ├── ArrayWrapper.h
│ │ │ ├── Assign.h
│ │ │ ├── AssignEvaluator.h
│ │ │ ├── Assign_MKL.h
│ │ │ ├── BandMatrix.h
│ │ │ ├── Block.h
│ │ │ ├── BooleanRedux.h
│ │ │ ├── CommaInitializer.h
│ │ │ ├── ConditionEstimator.h
│ │ │ ├── CoreEvaluators.h
│ │ │ ├── CoreIterators.h
│ │ │ ├── CwiseBinaryOp.h
│ │ │ ├── CwiseNullaryOp.h
│ │ │ ├── CwiseTernaryOp.h
│ │ │ ├── CwiseUnaryOp.h
│ │ │ ├── CwiseUnaryView.h
│ │ │ ├── DenseBase.h
│ │ │ ├── DenseCoeffsBase.h
│ │ │ ├── DenseStorage.h
│ │ │ ├── Diagonal.h
│ │ │ ├── DiagonalMatrix.h
│ │ │ ├── DiagonalProduct.h
│ │ │ ├── Dot.h
│ │ │ ├── EigenBase.h
│ │ │ ├── ForceAlignedAccess.h
│ │ │ ├── Fuzzy.h
│ │ │ ├── GeneralProduct.h
│ │ │ ├── GenericPacketMath.h
│ │ │ ├── GlobalFunctions.h
│ │ │ ├── IO.h
│ │ │ ├── Inverse.h
│ │ │ ├── Map.h
│ │ │ ├── MapBase.h
│ │ │ ├── MathFunctions.h
│ │ │ ├── MathFunctionsImpl.h
│ │ │ ├── Matrix.h
│ │ │ ├── MatrixBase.h
│ │ │ ├── NestByValue.h
│ │ │ ├── NoAlias.h
│ │ │ ├── NumTraits.h
│ │ │ ├── PermutationMatrix.h
│ │ │ ├── PlainObjectBase.h
│ │ │ ├── Product.h
│ │ │ ├── ProductEvaluators.h
│ │ │ ├── Random.h
│ │ │ ├── Redux.h
│ │ │ ├── Ref.h
│ │ │ ├── Replicate.h
│ │ │ ├── ReturnByValue.h
│ │ │ ├── Reverse.h
│ │ │ ├── Select.h
│ │ │ ├── SelfAdjointView.h
│ │ │ ├── SelfCwiseBinaryOp.h
│ │ │ ├── Solve.h
│ │ │ ├── SolveTriangular.h
│ │ │ ├── SolverBase.h
│ │ │ ├── StableNorm.h
│ │ │ ├── Stride.h
│ │ │ ├── Swap.h
│ │ │ ├── Transpose.h
│ │ │ ├── Transpositions.h
│ │ │ ├── TriangularMatrix.h
│ │ │ ├── VectorBlock.h
│ │ │ ├── VectorwiseOp.h
│ │ │ ├── Visitor.h
│ │ │ ├── arch/
│ │ │ │ ├── AVX/
│ │ │ │ │ ├── Complex.h
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ ├── PacketMath.h
│ │ │ │ │ └── TypeCasting.h
│ │ │ │ ├── AVX512/
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ └── PacketMath.h
│ │ │ │ ├── AltiVec/
│ │ │ │ │ ├── Complex.h
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ └── PacketMath.h
│ │ │ │ ├── CUDA/
│ │ │ │ │ ├── Complex.h
│ │ │ │ │ ├── Half.h
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ ├── PacketMath.h
│ │ │ │ │ ├── PacketMathHalf.h
│ │ │ │ │ └── TypeCasting.h
│ │ │ │ ├── Default/
│ │ │ │ │ ├── ConjHelper.h
│ │ │ │ │ └── Settings.h
│ │ │ │ ├── NEON/
│ │ │ │ │ ├── Complex.h
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ └── PacketMath.h
│ │ │ │ ├── SSE/
│ │ │ │ │ ├── Complex.h
│ │ │ │ │ ├── MathFunctions.h
│ │ │ │ │ ├── PacketMath.h
│ │ │ │ │ └── TypeCasting.h
│ │ │ │ └── ZVector/
│ │ │ │ ├── Complex.h
│ │ │ │ ├── MathFunctions.h
│ │ │ │ └── PacketMath.h
│ │ │ ├── functors/
│ │ │ │ ├── AssignmentFunctors.h
│ │ │ │ ├── BinaryFunctors.h
│ │ │ │ ├── NullaryFunctors.h
│ │ │ │ ├── StlFunctors.h
│ │ │ │ ├── TernaryFunctors.h
│ │ │ │ └── UnaryFunctors.h
│ │ │ ├── products/
│ │ │ │ ├── GeneralBlockPanelKernel.h
│ │ │ │ ├── GeneralMatrixMatrix.h
│ │ │ │ ├── GeneralMatrixMatrixTriangular.h
│ │ │ │ ├── GeneralMatrixMatrixTriangular_BLAS.h
│ │ │ │ ├── GeneralMatrixMatrix_BLAS.h
│ │ │ │ ├── GeneralMatrixVector.h
│ │ │ │ ├── GeneralMatrixVector_BLAS.h
│ │ │ │ ├── Parallelizer.h
│ │ │ │ ├── SelfadjointMatrixMatrix.h
│ │ │ │ ├── SelfadjointMatrixMatrix_BLAS.h
│ │ │ │ ├── SelfadjointMatrixVector.h
│ │ │ │ ├── SelfadjointMatrixVector_BLAS.h
│ │ │ │ ├── SelfadjointProduct.h
│ │ │ │ ├── SelfadjointRank2Update.h
│ │ │ │ ├── TriangularMatrixMatrix.h
│ │ │ │ ├── TriangularMatrixMatrix_BLAS.h
│ │ │ │ ├── TriangularMatrixVector.h
│ │ │ │ ├── TriangularMatrixVector_BLAS.h
│ │ │ │ ├── TriangularSolverMatrix.h
│ │ │ │ ├── TriangularSolverMatrix_BLAS.h
│ │ │ │ └── TriangularSolverVector.h
│ │ │ └── util/
│ │ │ ├── BlasUtil.h
│ │ │ ├── Constants.h
│ │ │ ├── DisableStupidWarnings.h
│ │ │ ├── ForwardDeclarations.h
│ │ │ ├── MKL_support.h
│ │ │ ├── Macros.h
│ │ │ ├── Memory.h
│ │ │ ├── Meta.h
│ │ │ ├── NonMPL2.h
│ │ │ ├── ReenableStupidWarnings.h
│ │ │ ├── StaticAssert.h
│ │ │ └── XprHelper.h
│ │ ├── Eigenvalues/
│ │ │ ├── ComplexEigenSolver.h
│ │ │ ├── ComplexSchur.h
│ │ │ ├── ComplexSchur_LAPACKE.h
│ │ │ ├── EigenSolver.h
│ │ │ ├── GeneralizedEigenSolver.h
│ │ │ ├── GeneralizedSelfAdjointEigenSolver.h
│ │ │ ├── HessenbergDecomposition.h
│ │ │ ├── MatrixBaseEigenvalues.h
│ │ │ ├── RealQZ.h
│ │ │ ├── RealSchur.h
│ │ │ ├── RealSchur_LAPACKE.h
│ │ │ ├── SelfAdjointEigenSolver.h
│ │ │ ├── SelfAdjointEigenSolver_LAPACKE.h
│ │ │ └── Tridiagonalization.h
│ │ ├── Geometry/
│ │ │ ├── AlignedBox.h
│ │ │ ├── AngleAxis.h
│ │ │ ├── EulerAngles.h
│ │ │ ├── Homogeneous.h
│ │ │ ├── Hyperplane.h
│ │ │ ├── OrthoMethods.h
│ │ │ ├── ParametrizedLine.h
│ │ │ ├── Quaternion.h
│ │ │ ├── Rotation2D.h
│ │ │ ├── RotationBase.h
│ │ │ ├── Scaling.h
│ │ │ ├── Transform.h
│ │ │ ├── Translation.h
│ │ │ ├── Umeyama.h
│ │ │ └── arch/
│ │ │ └── Geometry_SSE.h
│ │ ├── Householder/
│ │ │ ├── BlockHouseholder.h
│ │ │ ├── Householder.h
│ │ │ └── HouseholderSequence.h
│ │ ├── IterativeLinearSolvers/
│ │ │ ├── BasicPreconditioners.h
│ │ │ ├── BiCGSTAB.h
│ │ │ ├── ConjugateGradient.h
│ │ │ ├── IncompleteCholesky.h
│ │ │ ├── IncompleteLUT.h
│ │ │ ├── IterativeSolverBase.h
│ │ │ ├── LeastSquareConjugateGradient.h
│ │ │ └── SolveWithGuess.h
│ │ ├── Jacobi/
│ │ │ └── Jacobi.h
│ │ ├── LU/
│ │ │ ├── Determinant.h
│ │ │ ├── FullPivLU.h
│ │ │ ├── InverseImpl.h
│ │ │ ├── PartialPivLU.h
│ │ │ ├── PartialPivLU_LAPACKE.h
│ │ │ └── arch/
│ │ │ └── Inverse_SSE.h
│ │ ├── MetisSupport/
│ │ │ └── MetisSupport.h
│ │ ├── OrderingMethods/
│ │ │ ├── Amd.h
│ │ │ ├── Eigen_Colamd.h
│ │ │ └── Ordering.h
│ │ ├── PaStiXSupport/
│ │ │ └── PaStiXSupport.h
│ │ ├── PardisoSupport/
│ │ │ └── PardisoSupport.h
│ │ ├── QR/
│ │ │ ├── ColPivHouseholderQR.h
│ │ │ ├── ColPivHouseholderQR_LAPACKE.h
│ │ │ ├── CompleteOrthogonalDecomposition.h
│ │ │ ├── FullPivHouseholderQR.h
│ │ │ ├── HouseholderQR.h
│ │ │ └── HouseholderQR_LAPACKE.h
│ │ ├── SPQRSupport/
│ │ │ └── SuiteSparseQRSupport.h
│ │ ├── SVD/
│ │ │ ├── BDCSVD.h
│ │ │ ├── JacobiSVD.h
│ │ │ ├── JacobiSVD_LAPACKE.h
│ │ │ ├── SVDBase.h
│ │ │ └── UpperBidiagonalization.h
│ │ ├── SparseCholesky/
│ │ │ ├── SimplicialCholesky.h
│ │ │ └── SimplicialCholesky_impl.h
│ │ ├── SparseCore/
│ │ │ ├── AmbiVector.h
│ │ │ ├── CompressedStorage.h
│ │ │ ├── ConservativeSparseSparseProduct.h
│ │ │ ├── MappedSparseMatrix.h
│ │ │ ├── SparseAssign.h
│ │ │ ├── SparseBlock.h
│ │ │ ├── SparseColEtree.h
│ │ │ ├── SparseCompressedBase.h
│ │ │ ├── SparseCwiseBinaryOp.h
│ │ │ ├── SparseCwiseUnaryOp.h
│ │ │ ├── SparseDenseProduct.h
│ │ │ ├── SparseDiagonalProduct.h
│ │ │ ├── SparseDot.h
│ │ │ ├── SparseFuzzy.h
│ │ │ ├── SparseMap.h
│ │ │ ├── SparseMatrix.h
│ │ │ ├── SparseMatrixBase.h
│ │ │ ├── SparsePermutation.h
│ │ │ ├── SparseProduct.h
│ │ │ ├── SparseRedux.h
│ │ │ ├── SparseRef.h
│ │ │ ├── SparseSelfAdjointView.h
│ │ │ ├── SparseSolverBase.h
│ │ │ ├── SparseSparseProductWithPruning.h
│ │ │ ├── SparseTranspose.h
│ │ │ ├── SparseTriangularView.h
│ │ │ ├── SparseUtil.h
│ │ │ ├── SparseVector.h
│ │ │ ├── SparseView.h
│ │ │ └── TriangularSolver.h
│ │ ├── SparseLU/
│ │ │ ├── SparseLU.h
│ │ │ ├── SparseLUImpl.h
│ │ │ ├── SparseLU_Memory.h
│ │ │ ├── SparseLU_Structs.h
│ │ │ ├── SparseLU_SupernodalMatrix.h
│ │ │ ├── SparseLU_Utils.h
│ │ │ ├── SparseLU_column_bmod.h
│ │ │ ├── SparseLU_column_dfs.h
│ │ │ ├── SparseLU_copy_to_ucol.h
│ │ │ ├── SparseLU_gemm_kernel.h
│ │ │ ├── SparseLU_heap_relax_snode.h
│ │ │ ├── SparseLU_kernel_bmod.h
│ │ │ ├── SparseLU_panel_bmod.h
│ │ │ ├── SparseLU_panel_dfs.h
│ │ │ ├── SparseLU_pivotL.h
│ │ │ ├── SparseLU_pruneL.h
│ │ │ └── SparseLU_relax_snode.h
│ │ ├── SparseQR/
│ │ │ └── SparseQR.h
│ │ ├── StlSupport/
│ │ │ ├── StdDeque.h
│ │ │ ├── StdList.h
│ │ │ ├── StdVector.h
│ │ │ └── details.h
│ │ ├── SuperLUSupport/
│ │ │ └── SuperLUSupport.h
│ │ ├── UmfPackSupport/
│ │ │ └── UmfPackSupport.h
│ │ ├── misc/
│ │ │ ├── Image.h
│ │ │ ├── Kernel.h
│ │ │ ├── RealSvd2x2.h
│ │ │ ├── blas.h
│ │ │ ├── lapack.h
│ │ │ ├── lapacke.h
│ │ │ └── lapacke_mangling.h
│ │ └── plugins/
│ │ ├── ArrayCwiseBinaryOps.h
│ │ ├── ArrayCwiseUnaryOps.h
│ │ ├── BlockMethods.h
│ │ ├── CommonCwiseBinaryOps.h
│ │ ├── CommonCwiseUnaryOps.h
│ │ ├── MatrixCwiseBinaryOps.h
│ │ └── MatrixCwiseUnaryOps.h
│ └── qview/
│ ├── Makefile
│ ├── Occnet.h
│ ├── R3Model.cpp
│ ├── R3Quadric.cpp
│ ├── R3Quadric.h
│ ├── R3QuadricSet.cpp
│ ├── R3QuadricSet.h
│ └── qview.cpp
├── generate_data.sh
├── multi_sdf/
│ ├── evaluate.py
│ ├── loss.py
│ └── model.py
├── nnutils/
│ ├── blocks.py
│ ├── geometry.py
│ ├── metrics.py
│ ├── mlp.py
│ └── node_proc.py
├── node_sampler/
│ ├── evaluate.py
│ ├── loss.py
│ └── model.py
├── resources/
│ ├── env.yml
│ └── requirements.txt
├── scripts/
│ ├── make_watertight.sh
│ ├── process_mesh_local.sh
│ └── screened_poisson.mlx
├── train_graph.py
├── train_graph.sh
├── train_shape.py
├── train_shape.sh
├── utils/
│ ├── __init__.py
│ ├── embedder.py
│ ├── gradient_utils.py
│ ├── line_mesh.py
│ ├── mesh_proc.py
│ ├── parser_utils.py
│ ├── pcd_utils.py
│ ├── query.py
│ ├── sdf_utils.py
│ ├── time_statistics.py
│ └── viz_utils.py
├── viz.py
└── viz.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# VSCode cache
.vscode
# Output folders
/out
# External dependencies
/external/gaps
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Aljaz Bozic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Neural Deformation Graphs
### [Project Page](https://aljazbozic.github.io/neural_deformation_graphs/) | [Paper](https://arxiv.org/abs/2012.01451) | [Video](https://www.youtube.com/watch?v=vyq36eFkdWo)
> Neural Deformation Graphs for Globally-consistent Non-rigid Reconstruction
> [Aljaž Božič](https://aljazbozic.github.io/), [Pablo Palafox](https://pablorpalafox.github.io/), [Michael Zollhöfer](https://zollhoefer.com/), [Justus Thies](https://justusthies.github.io/), [Angela Dai](https://www.3dunderstanding.org/index.html), [Matthias Nießner](https://www.niessnerlab.org/members/matthias_niessner/profile.html)
> CVPR 2021 (Oral Presentation)
This repository contains the code for the CVPR 2021 paper [Neural Deformation Graphs](https://arxiv.org/abs/2012.01451), a novel approach for globally-consistent deformation tracking and 3D reconstruction of non-rigid objects.
Specifically, we implicitly model a deformation graph via a deep neural network and empose per-frame viewpoint consistency as well as inter-frame graph and surface consistency constraints in a self-supervised fashion.
That results in a differentiable construction of a deformation graph that is able to handle deformations present in the whole sequence.
## Install all dependencies
- Download the latest conda [here](https://docs.conda.io/projects/conda/en/latest/user-guide/install/download.html).
- To create a conda environment with all the required packages using conda run the following command:
```
conda env create -f resources/env.yml
```
> The above command creates a conda environment with the name **ndg**.
- Compile external dependencies inside `external` directory by executing:
```
conda activate ndg
./build_external.sh
```
> The external dependencies are **PyMarchingCubes**, **gaps** and **Eigen**.
## Generate data for visualization & training
In our experiments we use depth inputs from 4 camera views. These depth maps were captured with 4 Kinect Azure sensors. For quantitative evaluation we also used synthetic data, where 4 depth views were rendered from ground truth meshes. In both cases, screened Poisson reconstruction (implemented in [MeshLab](https://www.meshlab.net)) was used to obtain meshes for data generation. An example sequence of meshes of a synthetic **doozy** sequence can be downloaded [here](https://drive.google.com/file/d/12DYzj3CR-1dlnDDWO_ZVFnphoAmMT3hX/view?usp=sharing).
To generate training data from these meshes, they need to be put into a directory `out/meshes/doozy`. Then the following code executes data generation, producing generated data samples in `out/dataset/doozy`:
```
./generate_data.sh
```
## Visualize neural deformation graphs using pre-trained models
After data generation you can already check out the neural deformation graph estimation using a [pre-trained model checkpoint](https://drive.google.com/file/d/1d0Rdb3_bwP6BHRGjxG_mdixfxqpza_Ys/view?usp=sharing). You need to place it into the `out/models` directory, and run visualization:
```
./viz.sh
```
Reconstruction visualization can take longer, if you want to check out graphs only, you can uncomment `--viz_only_graph` argument in `viz.sh`.
Within the [Open3D](http://www.open3d.org/) viewer, you can navigate different settings using these keys:
* `N`: toggle graph nodes and edges
* `G`: toggle ground truth
* `D`: show next
* `A`: show previous
* `S`: toggle smooth shading
## Train a model from scratch
You can train a model from scratch using `train_graph.sh` and `train_shape.sh` scripts, in that order. The model checkpoints and tensorboard stats are going to be stored into `out/experiments`.
### Optimize graph
To estimate a neural deformation graph from input observations, you need to specify the dataset to be used (inside `out/dataset`, should be generated before hand), and then training can be started using the following script:
```
./train_graph.sh
```
We ran all our experiments on NVidia 2080Ti GPU, for about 500k iterations. After the model has converged, you can visualize the optimized neural deformation graph using `viz.sh` script.
To check out convergence, you can visualize loss curves with `tensorboard` by running the following inside `out/experiments` directory:
```
tensorboard --logdir=.
```
### Optimize shape
To optimize shape, you need to initialize the graph with a pre-trained graph model. That means that inside `train_shape.sh` you need to specify the `graph_model_path`, which should point to the converged checkpoint of the graph model (graph model usually converges at around 500k iterations). Multi-MLP model can then be optimized to reconstruct shape geometry by running:
```
./train_shape.sh
```
Similar to graph optimization also shape optimization converges in about 500k iterations.
## Citation
If you find our work useful in your research, please consider citing:
@article{bozic2021neuraldeformationgraphs,
title={Neural Deformation Graphs for Globally-consistent Non-rigid Reconstruction},
author={Bo{\v{z}}i{\v{c}}, Alja{\v{z}} and Palafox, Pablo and Zollh{\"o}fer, Michael and Dai, Angela and Thies, Justus and Nie{\ss}ner, Matthias},
journal={CVPR},
year={2021}
}
## Related work
Some other related works on non-rigid reconstruction by our group:
* [Bozic et al. DeepDeform: Learning Non-rigid RGB-D Reconstruction with Semi-supervised Data (2020)](https://niessnerlab.org/projects/bozic2020deepdeform.html)
* [Li et al. Learning to Optimize Non-Rigid Tracking (2020)](https://niessnerlab.org/projects/li2020learning.html)
* [Bozic et al. Neural Non-Rigid Tracking (2020)](https://www.niessnerlab.org/projects/bozic2020nnrt.html)
## License
The code from this repository is released under the MIT license, except where otherwise stated (i.e., `Eigen`).
================================================
FILE: build_external.sh
================================================
#!/bin/bash
###################################################
# INSTALL GAPS
###################################################
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
set -v
# CD inside the external directory
cd external
# This should create a gaps/ folder at external/gaps/
if [[ -d gaps ]]
then
echo "GAPS has already been cloned to external/gaps, skipping."
else
git clone https://github.com/tomfunkhouser/gaps.git
fi
# Necessary dependencies:
# Figure out whether we are on MacOS or Linux:
# if [[ $(uname -s) == Darwin* ]]
# then
# echo "On MacOS, GL dependencies should have shipped and OSMesa support is disabled."
# else
# # On linux, the packages need to be installed.
# sudo apt-get install mesa-common-dev libglu1-mesa-dev libosmesa6-dev libxi-dev libgl1-mesa-dev
# # For some reason on Ubuntu there can be a broken link from /usr/lib/x86_64-linux-gnu/libGL.so
# # to libGL.so.1.2.0 in the same directory, which does not exist. However libgl1-mesa-glx should
# # provide libGL.so.1.2.0. Reinstalling libgl1-mesa-glx results in libGL.so.1.2.0 correctly
# # existing in /usr/lib/x86_64-linux-gnu as it should.
# sudo apt-get install --reinstall libgl1-mesa-glx
# fi
# If the above command(s) fail, get the GL/gl.h and GL/glu.h headers, OSMesa and GL
# static libraries (osmesa on macos), delete the above code, and try again.
# Now apply customizations to GAPS:
# This should make a copy of the qview folder at external/gaps/apps/qview/
if [[ -d gaps/apps/qview ]]
then
echo "qview has already been copied into external/gaps/qview, skipping."
else
cp -R ./qview gaps/apps/
fi
# Everything is local to GAPS from this point:
cd gaps
# Ptsview and qview aren't built by default, adjust the makefile to build them.
# sed commands are for script idempotency
sed -i.bak '/ptsview/d' ./apps/Makefile
sed -i.bak '/qview/d' ./apps/Makefile
echo " cd ptsview; \$(MAKE) \$(TARGET)" >> ./apps/Makefile
echo " cd qview; \$(MAKE) \$(TARGET)" >> ./apps/Makefile
# Make GAPS (assuming 8 threads):
# On MacOS, using OSMesa is more difficult, so we don't
if [[ ! $(uname -s) == Darwin* ]]
then
make mesa -j8
else
make -j8
fi
cd ../..
###################################################
# INSTALL PyMarchingCubes
###################################################
cd external/PyMarchingCubes
python setup.py install
cd ../..
================================================
FILE: config.py
================================================
import os
#####################################################################################################################
# DATA OPTIONS
#####################################################################################################################
data_root_dir = "./out/dataset"
experiments_dir = "./out/experiments"
#####################################################################################################################
# DATA LOADING OPTIONS
#####################################################################################################################
num_worker_threads = 0 # 0 means that the base thread does all the job (that makes sense when hdf5 is already loaded into memory).
num_threads = 4
num_samples_eval = 100
cache_data = True
#####################################################################################################################
# MODEL INFO
#####################################################################################################################
# Pretrained model
initialize_from_other = False
saved_model_path = ""
saved_model_iteration = 0
# Freeze model
freeze_node_encoder = False
freeze_scale_estimator = False
freeze_position_estimator = False
freeze_rotation_estimator = False
freeze_affinity = False
freeze_surface_mlp = False
#####################################################################################################################
# GENERAL OPTIONS
#####################################################################################################################
# Do evaluation
do_evaluation = True
# Shuffle batch
shuffle = True
# Detect anomalies, such as when gradients explode
detect_anomaly = False
#####################################################################################################################
# NODE OPTIONS
#####################################################################################################################
num_nodes = 100
position_length = 3 + 1
scale_length = 3
rotation_length = 3
graph_num_point_samples = 3000
shape_num_point_samples = 1500
interior_point_weight = 10.0
soft_transfer_scale = 100.0
level_set = -0.07
num_neighbors = 2
use_constants = True
scaling_type = "isotropic" # ["isotropic", "anisotropic", "none"]
aggregate_coverage_with_max = False
#####################################################################################################################
# MULTI-SDF OPTIONS
#####################################################################################################################
# SDF settings
truncation = 0.1
# Model settings
num_features = 32
use_tanh = True
# Descriptors
descriptor_dim = 32
#####################################################################################################################
# TRAINING OPTIONS
#####################################################################################################################
graph_batch_size = 16
shape_batch_size = 4
evaluation_frequency = 5000
epochs = 1000000
graph_learning_rate = 5e-5
shape_learning_rate = 5e-4
weight_decay = 0
interval_step = 50000
# Losses
lambda_geometry = 1.0
lambda_sampling_uniform = 1.0
lambda_sampling_near_surface = 0.1
lambda_sampling_node_center = 1.0
lambda_viewpoint_position = 10.0
lambda_viewpoint_scale = 1.0
lambda_viewpoint_constant = 1.0
lambda_viewpoint_rotation = 1e-4
lambda_surface_consistency = 1e-6
lambda_surface_consistency_f = 10.0
lambda_surface_consistency_max = 1000.0
lambda_affinity_rel_dist = 0.1
lambda_affinity_rel_dist_f = 10.0
lambda_affinity_rel_dist_max = 10000.0
lambda_affinity_abs_dist = 0.1
lambda_affinity_abs_dist_f = 10.0
lambda_affinity_abs_dist_max = 1.0
lambda_unique_neighbor = 1e-8
lambda_unique_neighbor_f = 10.0
lambda_unique_neighbor_max = 1e-3
#####################################################################################################################
# PRINT HYPERPARAMS
#####################################################################################################################
def print_hyperparams(data, experiment_name):
print()
print("HYPERPARAMETERS:")
print()
print("\tDATA: ", data)
print("\tEXPERIMENT: ", experiment_name)
print()
print("\tnum_worker_threads ", num_worker_threads)
print("\tnum_threads ", num_threads)
print()
print("################# NODE OPTIONS #######################")
print("\tgraph_num_point_samples ", graph_num_point_samples)
print("\tshape_num_point_samples ", shape_num_point_samples)
print("\tuse_constants ", use_constants)
print("\tscaling_type ", scaling_type)
print()
print("############### TRAINING OPTIONS #####################")
print("\tgraph_batch_size ", graph_batch_size)
print("\tshape_batch_size ", shape_batch_size)
print("\tevaluation_frequency ", evaluation_frequency)
print("\tgraph_learning_rate ", graph_learning_rate)
print("\tshape_learning_rate ", shape_learning_rate)
print()
print("\tlambda_geometry ", lambda_geometry)
print("\tlambda_sampling_uniform ", lambda_sampling_uniform)
print("\tlambda_sampling_near_surface ", lambda_sampling_near_surface)
print("\tlambda_sampling_node_center ", lambda_sampling_node_center)
print("\tlambda_viewpoint_position ", lambda_viewpoint_position)
print("\tlambda_viewpoint_scale ", lambda_viewpoint_scale)
print("\tlambda_viewpoint_constant ", lambda_viewpoint_constant)
print("\tlambda_viewpoint_rotation ", lambda_viewpoint_rotation)
print("\tlambda_surface_cons ", lambda_surface_consistency)
print("\tlambda_surface_cons_f ", lambda_surface_consistency_f)
print("\tlambda_surface_cons_max ", lambda_surface_consistency_max)
print("\tlambda_affinity_rel_dist ", lambda_affinity_rel_dist)
print("\tlambda_affinity_rel_dist_f ", lambda_affinity_rel_dist_f)
print("\tlambda_affinity_rel_dist_max ", lambda_affinity_rel_dist_max)
print("\tlambda_affinity_abs_dist ", lambda_affinity_abs_dist)
print("\tlambda_affinity_abs_dist_f ", lambda_affinity_abs_dist_f)
print("\tlambda_affinity_abs_dist_max ", lambda_affinity_abs_dist_max)
print("\tlambda_unique_neighbor ", lambda_unique_neighbor)
print("\tlambda_unique_neighbor_f ", lambda_unique_neighbor_f)
print("\tlambda_unique_neighbor_max ", lambda_unique_neighbor_max)
================================================
FILE: dataset/dataset.py
================================================
import sys,os
import math
import torch
import numpy as np
from skimage import io, transform
from torch.utils.data import Dataset
import json
import open3d as o3d
import pickle
import random
import struct
from timeit import default_timer as timer
from tqdm import tqdm
class MeshDataset(Dataset):
def __init__(
self,
dataset_dir, num_point_samples,
cache_data=False, use_augmentation=False
):
self.dataset_dir = dataset_dir
self.num_point_samples = num_point_samples
self.cache_data = cache_data
self.use_augmentation = use_augmentation
# Load labels.
self.labels = []
self._load()
# Preload data.
if self.cache_data:
print("Preloading cached data ...")
loading_start = timer()
num_samples = len(self.labels)
assert num_samples > 0
data_dir = self.labels[0]["data_dir"]
sample_data = self._load_data(data_dir)
self.cache = {
'uniform_samples': np.zeros((num_samples,) + sample_data['uniform_samples'].shape, dtype=np.float32),
'surface_samples': np.zeros((num_samples,) + sample_data['surface_samples'].shape, dtype=np.float32),
'near_surface_samples': np.zeros((num_samples,) + sample_data['near_surface_samples'].shape, dtype=np.float32),
'grid': np.zeros((num_samples,) + sample_data['grid'].shape, dtype=np.float32),
'world2grid': np.zeros((num_samples,) + sample_data['world2grid'].shape, dtype=np.float32),
'world2orig': np.zeros((num_samples,) + sample_data['world2orig'].shape, dtype=np.float32),
'bbox_lower': np.zeros((num_samples,) + sample_data['bbox_lower'].shape, dtype=np.float32),
'bbox_upper': np.zeros((num_samples,) + sample_data['bbox_upper'].shape, dtype=np.float32)
}
for index in tqdm(range(len(self.labels))):
data_dir = self.labels[index]["data_dir"]
data = self._load_data(data_dir)
self.cache['uniform_samples'][index] = data['uniform_samples']
self.cache['surface_samples'][index] = data['surface_samples']
self.cache['near_surface_samples'][index] = data['near_surface_samples']
self.cache['grid'][index] = data['grid']
self.cache['world2grid'][index] = data['world2grid']
self.cache['world2orig'][index] = data['world2orig']
self.cache['bbox_lower'][index] = data['bbox_lower']
self.cache['bbox_upper'][index] = data['bbox_upper']
print("Done: {} s".format(timer() - loading_start))
print()
def _load(self):
sample_dirs = sorted([os.path.join(self.dataset_dir, f) for f in os.listdir(self.dataset_dir) if os.path.isdir(os.path.join(self.dataset_dir, f))])
for sample_dir in sample_dirs:
self.labels.append({
"data_dir": sample_dir
})
@staticmethod
def load_pts_file(path):
_, ext = os.path.splitext(path)
assert ext in ['.sdf', '.pts']
l = 4 if ext == '.sdf' else 6
with open(path, 'rb') as f:
points = np.fromfile(f, dtype=np.float32)
points = np.reshape(points, [-1, l])
return points
@staticmethod
def load_grid(path):
with open(path, 'rb') as f:
content = f.read()
res = struct.unpack('iii', content[:4 * 3])
vcount = res[0] * res[1] * res[2]
content = content[4 * 3:]
tx = struct.unpack('f' * 16, content[:4 * 16])
tx = np.array(tx).reshape([4, 4]).astype(np.float32)
content = content[4 * 16:]
grd = struct.unpack('f' * vcount, content[:4 * vcount])
grd = np.array(grd).reshape(res).astype(np.float32)
return grd, tx
def __len__(self):
return len(self.labels)
def unpack(self, x):
# We concatenate the first two dimensions, corresponding to
# batch size and sample size.
n_dims = len(x.shape)
new_shape = (x.shape[0] * x.shape[1], )
for i in range(2, n_dims):
new_shape += (x.shape[i],)
return x.view(new_shape)
def _load_data(self, data_dir):
# Load data from directory.
uniform_samples = MeshDataset.load_pts_file(f'{data_dir}/uniform_points.sdf')
near_surface_samples = MeshDataset.load_pts_file(f'{data_dir}/nss_points.sdf')
surface_samples = MeshDataset.load_pts_file(f'{data_dir}/surface_points.pts')
grid, world2grid = MeshDataset.load_grid(f'{data_dir}/coarse_grid.grd')
orig2world = np.reshape(np.loadtxt(f'{data_dir}/orig_to_gaps.txt'), [4, 4])
world2orig = np.linalg.inv(orig2world)
# Compute bounding box of interior uniform samples.
interior_sample_points = uniform_samples[uniform_samples[:, 3] < 0.0, :3]
bbox_upper = interior_sample_points.max(axis=0)
bbox_lower = interior_sample_points.min(axis=0)
return {
'uniform_samples': uniform_samples,
'surface_samples': surface_samples,
'near_surface_samples': near_surface_samples,
'grid': grid,
'world2grid': world2grid,
'world2orig': world2orig,
'bbox_lower': bbox_lower,
'bbox_upper': bbox_upper
}
def _get_cached_data(self, index):
return {
'uniform_samples': self.cache['uniform_samples'][index],
'surface_samples': self.cache['surface_samples'][index],
'near_surface_samples': self.cache['near_surface_samples'][index],
'grid': self.cache['grid'][index],
'world2grid': self.cache['world2grid'][index],
'world2orig': self.cache['world2orig'][index],
'bbox_lower': self.cache['bbox_lower'][index],
'bbox_upper': self.cache['bbox_upper'][index]
}
def __getitem__(self, index):
data_dir = self.labels[index]["data_dir"]
# Check if data is already cached.
if self.cache_data:
data = self._get_cached_data(index)
else:
data = self._load_data(data_dir)
# Subsample points.
uniform_samples = data['uniform_samples']
if uniform_samples.shape[0] > self.num_point_samples:
uniform_samples_idxs = np.random.permutation(uniform_samples.shape[0])[:self.num_point_samples]
uniform_samples = uniform_samples[uniform_samples_idxs, :]
near_surface_samples = data['near_surface_samples']
if near_surface_samples.shape[0] > self.num_point_samples:
near_surface_samples_idxs = np.random.permutation(near_surface_samples.shape[0])[:self.num_point_samples]
near_surface_samples = near_surface_samples[near_surface_samples_idxs, :]
surface_samples = data['surface_samples']
if surface_samples.shape[0] > self.num_point_samples:
surface_samples_idxs = np.random.permutation(surface_samples.shape[0])[:self.num_point_samples]
surface_samples = surface_samples[surface_samples_idxs, :]
if self.use_augmentation:
# We rotate randomly around y axis.
axis = np.array([0, 1, 0])[:, None]
T_array = []
for i in range(2):
angle = random.uniform(0, 2*math.pi)
axis_angle = axis * angle
R = o3d.geometry.get_rotation_matrix_from_axis_angle(axis_angle)
T = np.eye(4)
T[:3, :3] = R
T_array.append(T)
rotated2gaps0 = T_array[0].astype(np.float32)
rotated2gaps1 = T_array[1].astype(np.float32)
return np.stack([uniform_samples, uniform_samples], axis=0), np.stack([near_surface_samples, near_surface_samples], axis=0), \
np.stack([surface_samples, surface_samples], axis=0), np.stack([data['grid'], data['grid']], axis=0), \
np.stack([data['world2grid'], data['world2grid']], axis=0), np.stack([data['world2orig'], data['world2orig']], axis=0), \
np.stack([rotated2gaps0, rotated2gaps1], axis=0), \
np.stack([data['bbox_lower'], data['bbox_lower']], axis=0), np.stack([data['bbox_upper'], data['bbox_upper']], axis=0), \
np.stack([index, index], axis=0)
else:
rotated2gaps = np.eye(4).astype(np.float32)
return uniform_samples[np.newaxis, ...], near_surface_samples[np.newaxis, ...], \
surface_samples[np.newaxis, ...], data['grid'][np.newaxis, ...], \
data['world2grid'][np.newaxis, ...], data['world2orig'][np.newaxis, ...], \
rotated2gaps[np.newaxis, ...], \
data['bbox_lower'][np.newaxis, ...], data['bbox_upper'][np.newaxis, ...], \
[[index]]
def get_metadata(self, index):
return self.labels[index]
================================================
FILE: dataset/generate_dataset.py
================================================
import os
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import tqdm
from joblib import Parallel, delayed
from absl import flags
from absl import app
import glob
import argparse
import open3d as o3d
import subprocess as sp
def process_one(mesh_path, mesh_directory, dataset_directory, skip_existing):
"""Processes a single mesh, adding it to the dataset."""
name = os.path.basename(mesh_path)
name, extension = os.path.splitext(name)
valid_extensions = ['.ply']
if extension not in valid_extensions:
raise ValueError(f'File with unsupported extension {extension} found: {f}.'
f' Only {valid_extensions} are supported.')
output_dir = f'{dataset_directory}/{name}/'
scripts_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "scripts")
external_root_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "external")
# This is the last file the processing writes, if it already exists the
# example has already been processed.
if not skip_existing or not os.path.isfile(f'{output_dir}/uniform_points.sdf'):
# print(f'{codebase_root_dir}/scripts/process_mesh_local.sh {mesh_path} {dirpath} {external_root_dir}')
sp.check_output(
f'{scripts_dir}/process_mesh_local.sh {mesh_path} {output_dir} {external_root_dir}',
shell=True)
else:
print(f'Skipping shell script processing for {output_dir},'
' the output already exists.')
return output_dir
def generate_meshes(mesh_directory, dataset_directory, mesh_format, skip_existing=True, max_threads=-1):
raw_files = glob.glob(f'{mesh_directory}/*.{mesh_format}')
if not raw_files:
raise ValueError(f"Didn't find any {mesh_format} files in {mesh_directory}")
if mesh_format != "ply":
print(f"Started mesh conversion from '{mesh_format}' to 'ply'")
for input_mesh_path in raw_files:
base_name = os.path.splitext(input_mesh_path)[0]
output_mesh_path = os.path.join(mesh_directory, base_name + ".ply")
mesh = o3d.io.read_triangle_mesh(input_mesh_path)
o3d.io.write_triangle_mesh(output_mesh_path, mesh)
files = glob.glob(f'{mesh_directory}/*.ply')
else:
files = raw_files
# Make the directories first because it's not threadsafe and also might fail.
print('Creating directories...')
if not os.path.isdir(f'{dataset_directory}'):
os.makedirs(f'{dataset_directory}')
print('Making dataset...')
n_jobs = os.cpu_count()
assert max_threads != 0
if max_threads > 0:
n_jobs = max_threads
output_dirs = Parallel(n_jobs=n_jobs)(
delayed(process_one)(f, mesh_directory, dataset_directory,
skip_existing) for f in tqdm.tqdm(files))
print('Done!')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--input_mesh_dir', action='store', dest='input_mesh_dir', required=True, help='Provide input watertight mesh directory')
parser.add_argument('--output_data_dir', action='store', dest='output_data_dir', required=True, help='Provide output directory')
parser.add_argument('--mesh_format', action='store', dest='mesh_format', help='Provide mesh format')
parser.add_argument('--max_threads', action='store', type=int, dest='max_threads', help='Maximum number of threads to be used (uses all available threads by default)')
args = parser.parse_args()
input_mesh_dir = args.input_mesh_dir
output_data_dir = args.output_data_dir
mesh_format = args.mesh_format
max_threads = args.max_threads
if not mesh_format:
mesh_format = "ply"
if not max_threads:
max_threads = -1
generate_meshes(input_mesh_dir, output_data_dir, mesh_format, max_threads=max_threads)
================================================
FILE: external/PyMarchingCubes/.gitignore
================================================
.DS_Store
*.dae
_mcubes.cpp
*.py[cod]
.vscode
.mypy_cache
.vscode
# Created by https://www.gitignore.io/api/osx,linux,python
# Edit at https://www.gitignore.io/?templates=osx,linux,python
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### OSX ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# End of https://www.gitignore.io/api/osx,linux,python
================================================
FILE: external/PyMarchingCubes/.travis.yml
================================================
# vim ft=yaml
# After changing this file, check it on:
# http://yaml-online-parser.appspot.com/
# See doc/travis_notes.txt for some guidelines
language: python
matrix:
include:
- os: linux
dist: trusty
sudo: false
python: '3.6'
- os: linux
dist: xenial
sudo: required
python: '3.7'
# See http://docs.travis-ci.com/user/caching/#pip-cache
cache: pip
before_install:
- sudo apt-get update
- pip install --upgrade pip setuptools
install:
- pip install -r requirements.txt
- pip install nose>=1.3.7 coverage codecov pytest>=3.0.5 pycollada
- python setup.py build
- python setup.py build_ext --inplace
before_script:
- mkdir output
script:
- nosetests -v --exe --with-xunit --with-coverage --cover-package=mcubes
after_success:
- python setup.py install
- codecov # PUBLIC project
# - coverage report && coverage xml
# - python-codacy-coverage -r coverage.xml
================================================
FILE: external/PyMarchingCubes/LICENSE
================================================
Copyright (c) 2012-2015, P. M. Neila (https://github.com/pmneila/PyMCubes)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: external/PyMarchingCubes/MANIFEST.in
================================================
include marching_cubes/*.py
exclude marching_cubes/numpy_smoothing.py
include marching_cubes/src/*.h
include marching_cubes/src/*.cpp
include marching_cubes/src/_mcubes.pyx
exclude marching_cubes/src/_mcubes.cpp
include examples/*.py
include images/binary.jpg
include images/smooth.jpg
include images/smoothing.png
include setup.py
include README.rst
include LICENSE
================================================
FILE: external/PyMarchingCubes/README.md
================================================
# PyMarchingCubes
`PyMarchingCubes` is a fork from `PyMCubes`, with a different implementation of the actual marching function (see 'marching_cubes/src/marchingcubes.h').
It fixes some issues of the original implementation that let to wrong triangulation (visible in triangles that are larger than the actual 'marching cell').

### Color Interpolation
The module also includes a marching cubes with color interpolation:
``` marching_cubes_color ``` and ``` marching_cubes_color_func ```.
Have a look at the 'examples/spheres.py' file.
Basically, it is called with ``` marching_cubes_color(sdf_volume, rgb_volume, iso_level) ``` assuming a 3D grid for the sdf values (dim_x,dim_y,dim_z) and a 4D grid for the colors (dim_x,dim_y,dim_z,3).

The export functions for obj and off files are adapted accordingly to handle the vertex colors.
### Super sampling along the edges
In case you are using a truncated signed distance function, you might miss the correct zero-crossing because of undersampling. Increasing the sample volume grows cubically, instead one can also subsample along the edges of a coarser volume to find a better approximation of the zero-crossing.
This subsampling of the edges is achieved by sampling along the x,y,z axis independently with higher resolution (e.g., you sample (dim_x + (dim_x-1)*edge_sampling, dim_y, dim_z) for the edges along the x axis).
The computational cost grow linear with the number of subsamples (e.g. 10 subsamples result in ~30 times more samples that you have to provide (since you need 10 times more samples per axis)).
A modified marching cubes implementation can be called via ``` marching_cubes_super_sampling(sdf_x, sdf_y, sdf_z, iso_level) ```.
Have a look at the sphere example.

Other than that, this repository is the same as the original (https://github.com/pmneila/PyMCubes).
## Installation
```
git clone https://github.com/JustusThies/PyMarchingCubes.git
cd PyMarchingCubes
git clone https://gitlab.com/libeigen/eigen.git
python setup.py install
```
## Example from the original `PyMCubes`
The following example creates a `NumPy` volume with spherical iso-surfaces and
extracts one of them (i.e., a sphere) with `mcubes.marching_cubes`. The result
is exported to `sphere.dae`:
```Python
>>> import numpy as np
>>> import marching_cubes as mcubes
# Create a data volume (30 x 30 x 30)
>>> X, Y, Z = np.mgrid[:30, :30, :30]
>>> u = (X-15)**2 + (Y-15)**2 + (Z-15)**2 - 8**2
# Extract the 0-isosurface
>>> vertices, triangles = mcubes.marching_cubes(u, 0)
# Export the result to sphere.dae
>>> mcubes.export_mesh(vertices, triangles, "sphere.dae", "MySphere")
```
Alternatively, you can use a Python function to represent the volume instead of
a `NumPy` array:
```Python
>>> import numpy as np
>>> import marching_cubes as mcubes
# Create the volume
>>> f = lambda x, y, z: x**2 + y**2 + z**2
# Extract the 16-isosurface
>>> vertices, triangles = mcubes.marching_cubes_func((-10,-10,-10), (10,10,10),
... 100, 100, 100, f, 16)
# Export the result to sphere.dae (requires PyCollada)
>>> mcubes.export_mesh(vertices, triangles, "sphere.dae", "MySphere")
# Or export to an OBJ file
>>> mcubes.export_obj(vertices, triangles, 'sphere.obj')
```
Note that using a function to represent the volumetric data is **much** slower
than using a `NumPy` array.
## Smoothing binary arrays

Many segmentation methods build binary masks to separate _inside_ and _outside_
areas of the segmented object. When passing these binary mask to the marching
cubes algorithm the resulting mesh looks jagged. The following code shows an
example with a binary array embedding a sphere.
```Python
x, y, z = np.mgrid[:100, :100, :100]
binary_sphere = (x - 50)**2 + (y - 50)**2 + (z - 50)**2 - 25**2 < 0
# Extract the 0.5-levelset since the array is binary
vertices, triangles = mcubes.marching_cubes(binary_sphere, 0.5)
```

`PyMCubes` provides the function `mcubes.smooth` that takes a 2D or 3D binary
embedding function and produces a smooth version of it.
```Python
smoothed_sphere = mcubes.smooth(binary_sphere)
# Extract the 0-levelset (the 0-levelset of the output of mcubes.smooth is the
# smoothed version of the 0.5-levelset of the binary array).
vertices, triangles = mcubes.marching_cubes(smoothed_sphere, 0)
```

`mcubes.smooth` builds a smooth embedding array with negative values in the
areas where the binary embedding array is 0, and positive values in the areas
where it is 1. In this way, `mcubes.smooth` keeps all the information from the
original embedding function, including fine details and thin structures that
are commonly eroded by other standard smoothing methods.
================================================
FILE: external/PyMarchingCubes/examples/.gitignore
================================================
sphere.obj
sphere_color.obj
sphere_color.off
sphere_tsdf_super_res.off
sphere_tsdf_without_super_res.off
================================================
FILE: external/PyMarchingCubes/examples/spheres.py
================================================
import numpy as np
import marching_cubes as mcubes
print("Example 1: Isosurface in NumPy volume...")
#print(mcubes.__dir__())
# Create a data volume (100 x 100 x 100)
X, Y, Z = np.mgrid[:100, :100, :100]
sdf = (X-50)**2 + (Y-50)**2 + (Z-50)**2 - 25**2
# Extract the 0-isosurface
vertices, triangles = mcubes.marching_cubes(sdf, 0)
mcubes.export_obj(vertices, triangles, "sphere.obj")
print("Example 2: Isosurface and color in NumPy volume...")
# Extract isosurface and color
#color = 0.01 * np.concatenate((X[:,:,:,None],X[:,:,:,None],X[:,:,:,None]), axis=3) # color array (grayscale gradient in this example)
color = 0.01 * np.concatenate((X[:,:,:,None],Y[:,:,:,None],Z[:,:,:,None]), axis=3) # color array (positions as color)
vertices_color, triangles_color = mcubes.marching_cubes_color(sdf, color, 0)
mcubes.export_obj(vertices_color, triangles_color, "sphere_color.obj")
mcubes.export_off(vertices_color, triangles_color, "sphere_color.off")
print("Example 3: TSDF isosurface with super resolution...")
dim = 100
# Create a data volume (100 x 100 x 100)
def sphere_tsdf(xyz, x_scale, y_scale, z_scale):
X, Y, Z = xyz
X = X*x_scale
Y = Y*y_scale
Z = Z*z_scale
sdf = (X-0.5)**2 + (Y-0.5)**2 + (Z-0.5)**2 - 0.25**2
truncation = 0.001 # relatively small truncation
return np.clip(sdf, -truncation, truncation)
# Extract the 0-isosurface
sdf = sphere_tsdf(np.mgrid[:dim, :dim, :dim], 1.0/(dim-1.0),1.0/(dim-1.0),1.0/(dim-1.0))
vertices, triangles = mcubes.marching_cubes(sdf, 0)
mcubes.export_off(vertices, triangles, "sphere_tsdf_without_super_res.off")
# Extract the 0-isosurface with super res
edges = dim-1
n_edge_samples = 10
supersamples = dim + edges * n_edge_samples
sdf_x = sphere_tsdf(np.mgrid[:supersamples, :dim, :dim], 1.0/(supersamples-1.0), 1.0/(dim-1.0), 1.0/(dim-1.0)) ## generates 10x more samples in x
sdf_y = sphere_tsdf(np.mgrid[:dim, :supersamples, :dim], 1.0/(dim-1.0), 1.0/(supersamples-1.0), 1.0/(dim-1.0)) ## generates 10x more samples in y
sdf_z = sphere_tsdf(np.mgrid[:dim, :dim, :supersamples], 1.0/(dim-1.0), 1.0/(dim-1.0), 1.0/(supersamples-1.0)) ## generates 10x more samples in z
vertices, triangles = mcubes.marching_cubes_super_sampling(sdf_x, sdf_y, sdf_z, 0)
mcubes.export_off(vertices, triangles, "sphere_tsdf_super_res.off")
# old examples
# Export the result to sphere.dae
#mcubes.export_mesh(vertices1, triangles1, "sphere1.dae", "MySphere")
# print("Done. Result saved in 'sphere1.dae'.")
# print("Example 2: Isosurface in Python function...")
# print("(this might take a while...)")
# # Create the volume
# def f(x, y, z):
# return x**2 + y**2 + z**2
# # Extract the 16-isosurface
# vertices2, triangles2 = mcubes.marching_cubes_func(
# (-10,-10,-10), (10,10,10), # Bounds
# 100, 100, 100, # Number of samples in each dimension
# f, # Implicit function
# 16) # Isosurface value
# # Export the result to sphere2.dae
# mcubes.export_mesh(vertices2, triangles2, "sphere2.dae", "MySphere")
# print("Done. Result saved in 'sphere2.dae'.")
# try:
# print("Plotting mesh...")
# from mayavi import mlab
# mlab.triangular_mesh(
# vertices1[:, 0], vertices1[:, 1], vertices1[:, 2],
# triangles1)
# print("Done.")
# mlab.show()
# except ImportError:
# print("Could not import mayavi. Interactive demo not available.")
================================================
FILE: external/PyMarchingCubes/marching_cubes/__init__.py
================================================
from ._mcubes import marching_cubes, marching_cubes_func, marching_cubes_color, marching_cubes_color_func, marching_cubes_super_sampling
from .exporter import export_mesh, export_obj, export_off
from .smoothing import *
# from .numpy_smoothing import *
================================================
FILE: external/PyMarchingCubes/marching_cubes/exporter.py
================================================
import numpy as np
def export_obj(vertices, triangles, filename):
"""
Exports a mesh in the (.obj) format.
"""
print('export mesh: ', vertices.shape)
with open(filename, 'w') as fh:
if (vertices.shape[1]==6):
for v in vertices:
fh.write("v {} {} {} {} {} {}\n".format(*v))
else:
for v in vertices:
fh.write("v {} {} {}\n".format(*v))
for f in triangles:
fh.write("f {} {} {}\n".format(*(f + 1)))
def export_off(vertices, triangles, filename):
"""
Exports a mesh in the (.off) format.
"""
with open(filename, 'w') as fh:
if (vertices.shape[1]==6):
fh.write('COFF\n')
else:
fh.write('OFF\n')
fh.write('{} {} 0\n'.format(len(vertices), len(triangles)))
if (vertices.shape[1]==6):
for v in vertices:
fh.write("{} {} {} {} {} {}\n".format(*v))
else:
for v in vertices:
fh.write("{} {} {}\n".format(*v))
for f in triangles:
fh.write("3 {} {} {}\n".format(*f))
def export_mesh(vertices, triangles, filename, mesh_name="mcubes_mesh"):
"""
Exports a mesh in the COLLADA (.dae) format.
Needs PyCollada (https://github.com/pycollada/pycollada).
"""
import collada
mesh = collada.Collada()
vert_src = collada.source.FloatSource("verts-array", vertices[:,0:3], ('X','Y','Z'))
geom = collada.geometry.Geometry(mesh, "geometry0", mesh_name, [vert_src])
input_list = collada.source.InputList()
input_list.addInput(0, 'VERTEX', "#verts-array")
triset = geom.createTriangleSet(np.copy(triangles), input_list, "")
geom.primitives.append(triset)
mesh.geometries.append(geom)
geomnode = collada.scene.GeometryNode(geom, [])
node = collada.scene.Node(mesh_name, children=[geomnode])
myscene = collada.scene.Scene("mcubes_scene", [node])
mesh.scenes.append(myscene)
mesh.scene = myscene
mesh.write(filename)
================================================
FILE: external/PyMarchingCubes/marching_cubes/numpy_smoothing.py
================================================
import numpy as np
from scipy import ndimage as ndi
__all__ = [
'numpy_smooth',
]
FILTER = np.array([1, -2, 1], dtype=np.float_)
JACOBI_R_2D = np.array([
[0, 0, 1, 0, 0],
[0, 0, -4, 0, 0],
[1, -4, 0, -4, 1],
[0, 0, -4, 0, 0],
[0, 0, 1, 0, 0]
], dtype=np.float_)
JACOBI_D_2D = 1/12
JACOBI_R_3D = np.array([
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, -4, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 1, 0, 0],
[0, 0, -4, 0, 0],
[1, -4, 0, -4, 1],
[0, 0, -4, 0, 0],
[0, 0, 1, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, -4, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]],
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
], dtype=np.float_)
JACOBI_D_3D = 1/18
def signed_distance_function(binary_arr: np.ndarray) -> np.ndarray:
arr = np.where(binary_arr > 0, 1.0, 0.0)
dist_func = ndi.distance_transform_edt
distance = np.where(
binary_arr,
dist_func(arr) - 0.5,
-dist_func(1 - arr) + 0.5
)
return distance
def energy(arr: np.ndarray) -> np.ndarray:
darr2 = [ndi.convolve1d(arr, FILTER, axis=i)**2 for i in range(arr.ndim)]
return np.sum(darr2) / 2
def solve_jacobi(
arr: np.ndarray,
lower_bound: np.ndarray,
upper_bound: np.ndarray,
max_iters: int = 500,
jacobi_weight: float = 0.5
) -> np.ndarray:
jacobi_d = JACOBI_D_2D if arr.ndim == 2 else JACOBI_D_3D
jacobi_r = JACOBI_R_2D if arr.ndim == 2 else JACOBI_R_3D
for it in range(max_iters):
# energy_it = torch.sum(diff_energy(arr) * arr[2:-2, 2:-2, 2:-2]) / 2
energy_it = energy(arr)
print("Energy in iteration {}: {:.4g}".format(it, energy_it))
r_arr = ndi.convolve(arr, jacobi_r, mode='nearest')
arr_1 = - jacobi_d * r_arr
arr = jacobi_weight * arr_1 + (1 - jacobi_weight) * arr
arr = np.maximum(arr, lower_bound)
arr = np.minimum(arr, upper_bound)
return arr
def numpy_smooth(binary_array: np.ndarray, max_iters: int = 500) -> np.ndarray:
arr = signed_distance_function(binary_array)
upper_bound = np.where(arr < 0, arr, np.inf)
lower_bound = np.where(arr > 0, arr, -np.inf)
upper_bound[np.abs(upper_bound) < 1] = 0
lower_bound[np.abs(lower_bound) < 1] = 0
return solve_jacobi(arr, lower_bound, upper_bound, max_iters)
================================================
FILE: external/PyMarchingCubes/marching_cubes/smoothing.py
================================================
# -*- coding: utf-8 -*-
"""
Utilities for smoothing the 0.5 level-set of binary arrays.
"""
import logging
from typing import Tuple
import numpy as np
from scipy import sparse
from scipy import ndimage as ndi
__all__ = [
'smooth',
'smooth_constrained',
'smooth_gaussian',
'signed_distance_function'
]
def _build_variable_indices(band: np.ndarray) -> np.ndarray:
num_variables = np.count_nonzero(band)
variable_indices = np.full(band.shape, -1, dtype=np.int_)
variable_indices[band] = np.arange(num_variables)
return variable_indices
def _buildq3d(variable_indices: np.ndarray):
"""
Builds the filterq matrix for the given variables.
"""
num_variables = variable_indices.max() + 1
filterq = sparse.lil_matrix((3*num_variables, num_variables))
# Pad variable_indices to simplify out-of-bounds accesses
variable_indices = np.pad(
variable_indices,
[(0, 1), (0, 1), (0, 1)],
mode='constant',
constant_values=-1
)
coords = np.nonzero(variable_indices >= 0)
for count, (i, j, k) in enumerate(zip(*coords)):
assert(variable_indices[i, j, k] == count)
filterq[3*count, count] = -2
neighbor = variable_indices[i-1, j, k]
if neighbor >= 0:
filterq[3*count, neighbor] = 1
else:
filterq[3*count, count] += 1
neighbor = variable_indices[i+1, j, k]
if neighbor >= 0:
filterq[3*count, neighbor] = 1
else:
filterq[3*count, count] += 1
filterq[3*count+1, count] = -2
neighbor = variable_indices[i, j-1, k]
if neighbor >= 0:
filterq[3*count+1, neighbor] = 1
else:
filterq[3*count+1, count] += 1
neighbor = variable_indices[i, j+1, k]
if neighbor >= 0:
filterq[3*count+1, neighbor] = 1
else:
filterq[3*count+1, count] += 1
filterq[3*count+2, count] = -2
neighbor = variable_indices[i, j, k-1]
if neighbor >= 0:
filterq[3*count+2, neighbor] = 1
else:
filterq[3*count+2, count] += 1
neighbor = variable_indices[i, j, k+1]
if neighbor >= 0:
filterq[3*count+2, neighbor] = 1
else:
filterq[3*count+2, count] += 1
filterq = filterq.tocsr()
return filterq.T.dot(filterq)
def _buildq2d(variable_indices: np.ndarray):
"""
Builds the filterq matrix for the given variables.
Version for 2 dimensions.
"""
num_variables = variable_indices.max() + 1
filterq = sparse.lil_matrix((3*num_variables, num_variables))
# Pad variable_indices to simplify out-of-bounds accesses
variable_indices = np.pad(
variable_indices,
[(0, 1), (0, 1)],
mode='constant',
constant_values=-1
)
coords = np.nonzero(variable_indices >= 0)
for count, (i, j) in enumerate(zip(*coords)):
assert(variable_indices[i, j] == count)
filterq[2*count, count] = -2
neighbor = variable_indices[i-1, j]
if neighbor >= 0:
filterq[2*count, neighbor] = 1
else:
filterq[2*count, count] += 1
neighbor = variable_indices[i+1, j]
if neighbor >= 0:
filterq[2*count, neighbor] = 1
else:
filterq[2*count, count] += 1
filterq[2*count+1, count] = -2
neighbor = variable_indices[i, j-1]
if neighbor >= 0:
filterq[2*count+1, neighbor] = 1
else:
filterq[2*count+1, count] += 1
neighbor = variable_indices[i, j+1]
if neighbor >= 0:
filterq[2*count+1, neighbor] = 1
else:
filterq[2*count+1, count] += 1
filterq = filterq.tocsr()
return filterq.T.dot(filterq)
def _jacobi(
filterq,
x0: np.ndarray,
lower_bound: np.ndarray,
upper_bound: np.ndarray,
max_iters: int = 10,
rel_tol: float = 1e-6,
weight: float = 0.5):
"""Jacobi method with constraints."""
jacobi_r = sparse.lil_matrix(filterq)
shp = jacobi_r.shape
jacobi_d = 1.0 / filterq.diagonal()
jacobi_r.setdiag((0,) * shp[0])
jacobi_r = jacobi_r.tocsr()
x = x0
# We check the stopping criterion each 10 iterations
check_each = 10
cum_rel_tol = 1 - (1 - rel_tol)**check_each
energy_now = np.dot(x, filterq.dot(x)) / 2
logging.info("Energy at iter %d: %.6g", 0, energy_now)
for i in range(max_iters):
x_1 = - jacobi_d * jacobi_r.dot(x)
x = weight * x_1 + (1 - weight) * x
# Constraints.
x = np.maximum(x, lower_bound)
x = np.minimum(x, upper_bound)
# Stopping criterion
if (i + 1) % check_each == 0:
# Update energy
energy_before = energy_now
energy_now = np.dot(x, filterq.dot(x)) / 2
logging.info("Energy at iter %d: %.6g", i + 1, energy_now)
# Check stopping criterion
cum_rel_improvement = (energy_before - energy_now) / energy_before
if cum_rel_improvement < cum_rel_tol:
break
return x
def signed_distance_function(
levelset: np.ndarray,
band_radius: int
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
Return the distance to the 0.5 levelset of a function, the mask of the
border (i.e., the nearest cells to the 0.5 level-set) and the mask of the
band (i.e., the cells of the function whose distance to the 0.5 level-set
is less of equal to `band_radius`).
"""
binary_array = np.where(levelset > 0, True, False)
# Compute the band and the border.
dist_func = ndi.distance_transform_edt
distance = np.where(
binary_array,
dist_func(binary_array) - 0.5,
-dist_func(~binary_array) + 0.5
)
border = np.abs(distance) < 1
band = np.abs(distance) <= band_radius
return distance, border, band
def smooth_constrained(
binary_array: np.ndarray,
band_radius: int = 4,
max_iters: int = 250,
rel_tol: float = 1e-6
) -> np.ndarray:
"""
Implementation of the smoothing method from
"Surface Extraction from Binary Volumes with Higher-Order Smoothness"
Victor Lempitsky, CVPR10
"""
# # Compute the distance map, the border and the band.
logging.info("Computing distance transform...")
distance, _, band = signed_distance_function(binary_array, band_radius)
variable_indices = _build_variable_indices(band)
# Compute filterq.
logging.info("Building matrix filterq...")
if binary_array.ndim == 3:
filterq = _buildq3d(variable_indices)
elif binary_array.ndim == 2:
filterq = _buildq2d(variable_indices)
else:
raise ValueError("binary_array.ndim not in [2, 3]")
# Initialize the variables.
res = np.asarray(distance, dtype=np.double)
x = res[band]
upper_bound = np.where(x < 0, x, np.inf)
lower_bound = np.where(x > 0, x, -np.inf)
upper_bound[np.abs(upper_bound) < 1] = 0
lower_bound[np.abs(lower_bound) < 1] = 0
# Solve.
logging.info("Minimizing energy...")
x = _jacobi(
filterq=filterq,
x0=x,
lower_bound=lower_bound,
upper_bound=upper_bound,
max_iters=max_iters,
rel_tol=rel_tol
)
res[band] = x
return res
def smooth_gaussian(binary_array: np.ndarray, sigma: float = 3) -> np.ndarray:
vol = np.float_(binary_array) - 0.5
return ndi.gaussian_filter(vol, sigma=sigma)
def smooth(
binary_array: np.ndarray,
method: str = 'auto',
**kwargs
) -> np.ndarray:
"""
Smooths the 0.5 level-set of a binary array. Returns a floating-point
array with a smoothed version of the original level-set in the 0 isovalue.
This function can apply two different methods:
- A constrained smoothing method which preserves details and fine
structures, but it is slow and requires a large amount of memory. This
method is recommended when the input array is small (smaller than
(500, 500, 500)).
- A Gaussian filter applied over the binary array. This method is fast, but
not very precise, as it can destroy fine details. It is only recommended
when the input array is large and the 0.5 level-set does not contain
thin structures.
Parameters
----------
binary_array : ndarray
Input binary array with the 0.5 level-set to smooth.
method : str, one of ['auto', 'gaussian', 'constrained']
Smoothing method. If 'auto' is given, the method will be automatically
chosen based on the size of `binary_array`.
Parameters for 'gaussian'
-------------------------
sigma : float
Size of the Gaussian filter (default 3).
Parameters for 'constrained'
----------------------------
max_iters : positive integer
Number of iterations of the constrained optimization method
(default 250).
rel_tol: float
Relative tolerance as a stopping criterion (default 1e-6).
Output
------
res : ndarray
Floating-point array with a smoothed 0 level-set.
"""
binary_array = np.asarray(binary_array)
if method == 'auto':
if binary_array.size > 500**3:
method = 'gaussian'
else:
method = 'constrained'
if method == 'gaussian':
return smooth_gaussian(binary_array, **kwargs)
if method == 'constrained':
return smooth_constrained(binary_array, **kwargs)
raise ValueError("Unknown method '{}'".format(method))
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/_mcubes.pyx
================================================
# distutils: language = c++
# cython: embedsignature = True
# from libcpp.vector cimport vector
import numpy as np
# Define PY_ARRAY_UNIQUE_SYMBOL
cdef extern from "pyarray_symbol.h":
pass
cimport numpy as np
np.import_array()
cdef extern from "pywrapper.h":
cdef object c_marching_cubes "marching_cubes"(np.ndarray, double) except +
cdef object c_marching_cubes_func "marching_cubes_func"(tuple, tuple, int, int, int, object, double) except +
cdef object c_marching_cubes_color "marching_cubes_color"(np.ndarray, np.ndarray, double) except +
cdef object c_marching_cubes_color_func "marching_cubes_color_func"(tuple, tuple, int, int, int, object, object, object, object, double) except +
cdef object c_marching_cubes_super_sampling "marching_cubes_super_sampling"(np.ndarray, np.ndarray, np.ndarray, double) except +
def marching_cubes(np.ndarray volume, float isovalue):
verts, faces = c_marching_cubes(volume, isovalue)
verts.shape = (-1, 3)
faces.shape = (-1, 3)
return verts, faces
def marching_cubes_super_sampling(np.ndarray volumeX, np.ndarray volumeY, np.ndarray volumeZ, float isovalue):
verts, faces = c_marching_cubes_super_sampling(volumeX, volumeY, volumeZ, isovalue)
verts.shape = (-1, 3)
faces.shape = (-1, 3)
return verts, faces
def marching_cubes_func(tuple lower, tuple upper, int numx, int numy, int numz, object f, double isovalue):
if any(l_i >= u_i for l_i, u_i in zip(lower, upper)):
raise ValueError("lower coordinates cannot be larger than upper coordinates")
if numx < 2 or numy < 2 or numz < 2:
raise ValueError("numx, numy, numz cannot be smaller than 2")
verts, faces = c_marching_cubes_func(lower, upper, numx, numy, numz, f, isovalue)
verts.shape = (-1, 3)
faces.shape = (-1, 3)
return verts, faces
def marching_cubes_color(np.ndarray volume_sdf, np.ndarray volume_color, float isovalue):
verts, faces = c_marching_cubes_color(volume_sdf, volume_color, isovalue)
verts.shape = (-1, 6)
faces.shape = (-1, 3)
return verts, faces
def marching_cubes_color_func(tuple lower, tuple upper, int numx, int numy, int numz, object f_sdf, object f_color_r, object f_color_g, object f_color_b, double isovalue):
if any(l_i >= u_i for l_i, u_i in zip(lower, upper)):
raise ValueError("lower coordinates cannot be larger than upper coordinates")
if numx < 2 or numy < 2 or numz < 2:
raise ValueError("numx, numy, numz cannot be smaller than 2")
verts, faces = c_marching_cubes_color_func(lower, upper, numx, numy, numz, f_sdf, f_color_r, f_color_g, f_color_b, isovalue)
verts.shape = (-1, 6)
faces.shape = (-1, 3)
return verts, faces
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/marchingcubes.cpp
================================================
#include "marchingcubes.h"
namespace mc
{
int edge_table[256] =
{
0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
};
int triangle_table[256][16] =
{
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
};
namespace private_
{
double mc_isovalue_interpolation(double isovalue, double f1, double f2,
double x1, double x2)
{
if(f2==f1)
return (x2+x1)/2;
return (x2-x1)*(isovalue-f1)/(f2-f1) + x1;
}
void mc_add_vertex(double x1, double y1, double z1, double c2,
int axis, double f1, double f2, double isovalue, std::vector* vertices)
{
if(axis == 0)
{
double x = mc_isovalue_interpolation(isovalue, f1, f2, x1, c2);
vertices->push_back(x);
vertices->push_back(y1);
vertices->push_back(z1);
return;
}
if(axis == 1)
{
double y = mc_isovalue_interpolation(isovalue, f1, f2, y1, c2);
vertices->push_back(x1);
vertices->push_back(y);
vertices->push_back(z1);
return;
}
if(axis == 2)
{
double z = mc_isovalue_interpolation(isovalue, f1, f2, z1, c2);
vertices->push_back(x1);
vertices->push_back(y1);
vertices->push_back(z);
return;
}
}
}
}
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/marchingcubes.h
================================================
#ifndef _MARCHING_CUBES_H
#define _MARCHING_CUBES_H
#include
#include
#include
#include
#include
#include "Eigen/Eigen" // git clone https://gitlab.com/libeigen/eigen.git
typedef Eigen::Matrix Vector6d;
namespace mc
{
extern int edge_table[256];
extern int triangle_table[256][16];
namespace private_
{
double mc_isovalue_interpolation(double isovalue, double f1, double f2,
double x1, double x2);
void mc_add_vertex(double x1, double y1, double z1, double c2,
int axis, double f1, double f2, double isovalue, std::vector* vertices);
struct MC_Triangle {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
int p[3];
};
struct MC_Gridcell {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Eigen::Vector3d p[8];
double val[8];
};
struct MC_Gridcell_Color {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Vector6d p[8];
double val[8];
};
}
template
void marching_cubes(const vector3& lower, const vector3& upper,
int numx, int numy, int numz, formula f, double isovalue,
std::vector& vertices, std::vector& polygons)
{
using coord_type = typename vector3::value_type;
using size_type = typename vector3::size_type;
using namespace private_;
// Some initial checks
if(numx < 2 || numy < 2 || numz < 2)
return;
if(!std::equal(std::begin(lower), std::end(lower), std::begin(upper),
[](double a, double b)->bool {return a <= b;}))
return;
#define OWN_IMPL
#ifdef OWN_IMPL
double dx = (upper[0] - lower[0]) / (numx - 1.0);
double dy = (upper[1] - lower[1]) / (numy - 1.0);
double dz = (upper[2] - lower[2]) / (numz - 1.0);
auto coord_mapper = [&](int x, int y, int z) { return Eigen::Vector3d( lower[0] + x * dx, lower[1] + y * dy, lower[2] + z * dz ); };
auto push_vertex = [&] (Eigen::Vector3d xyz) {int id = vertices.size()/3; vertices.push_back(xyz.x()); vertices.push_back(xyz.y()); vertices.push_back(xyz.z()); return id;};
// vertex zero crossing interpolation
// f(p2) = valp2
// x
// /
// x f(p) = isolevel
// /
// /
// /
// x
// f(p1) = valp1
auto VertexInterp = [&](double isolevel, const Eigen::Vector3d& p1, const Eigen::Vector3d& p2, double valp1, double valp2) -> Eigen::Vector3d
{
double alpha = (valp2 - isolevel) / (valp2 - valp1);
return alpha*p1 + (1 - alpha)*p2;
};
// store intersections of old z plane to avoid duplicated vertices
int* edge_intersections_old_x = new int[(numx-1) * numy];
int* edge_intersections_old_y = new int[numx * (numy-1)];
int* edge_intersections_current_x = new int[(numx-1) * numy];
int* edge_intersections_current_y = new int[numx * (numy-1)];
// store intersections within the z-planes to avoid duplicated vertices
int* edge_intersections_current_z = new int[numx * numy];
for (int z = 0; z < numz - 1; z++)
{
// swap index storage
std::swap(edge_intersections_old_x, edge_intersections_current_x); // old = current
std::swap(edge_intersections_old_y, edge_intersections_current_y);
std::fill_n(edge_intersections_current_x, (numx-1) * numy, -1); // invalidate
std::fill_n(edge_intersections_current_y, (numy-1) * numx, -1); // invalidate
std::fill_n(edge_intersections_current_z, numy * numx, -1); // invalidate
for (int y = 0; y < numy - 1; y++)
{
for (int x = 0; x < numx - 1; x++)
{
// Process Volume Cell
MC_Gridcell cell;
//
// 4---5
// / /|
// 0---1 6
// | |/
// 3---2
// cell corners
cell.p[0] = coord_mapper(x + 1, y, z);
cell.p[1] = coord_mapper(x, y, z);
cell.p[2] = coord_mapper(x, y + 1, z);
cell.p[3] = coord_mapper(x + 1, y + 1, z);
cell.p[4] = coord_mapper(x + 1, y, z + 1);
cell.p[5] = coord_mapper(x, y, z + 1);
cell.p[6] = coord_mapper(x, y + 1, z + 1);
cell.p[7] = coord_mapper(x + 1, y + 1, z + 1);
// cell corner values
cell.val[0] = (double)f(x + 1, y, z);
cell.val[1] = (double)f(x, y, z);
cell.val[2] = (double)f(x, y + 1, z);
cell.val[3] = (double)f(x + 1, y + 1, z);
cell.val[4] = (double)f(x + 1, y, z + 1);
cell.val[5] = (double)f(x, y, z + 1);
cell.val[6] = (double)f(x, y + 1, z + 1);
cell.val[7] = (double)f(x + 1, y + 1, z + 1);
// triangulation code
int cubeindex = 0;
if (cell.val[0] < isovalue) cubeindex |= 1;
if (cell.val[1] < isovalue) cubeindex |= 2;
if (cell.val[2] < isovalue) cubeindex |= 4;
if (cell.val[3] < isovalue) cubeindex |= 8;
if (cell.val[4] < isovalue) cubeindex |= 16;
if (cell.val[5] < isovalue) cubeindex |= 32;
if (cell.val[6] < isovalue) cubeindex |= 64;
if (cell.val[7] < isovalue) cubeindex |= 128;
// Cube is entirely in/out of the surface
if (edge_table[cubeindex] == 0) continue;
/* Find the vertices where the surface intersects the cube */
int vertlist[12];
{ // edges on the old z plane
if (edge_table[cubeindex] & 1) // edge in x at y
{
if(z==0) vertlist[0] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[1], cell.val[0], cell.val[1]));
else vertlist[0] = edge_intersections_old_x[y * (numx-1) + x];
}
if (edge_table[cubeindex] & 2) // edge in y at x
{
if(z==0) vertlist[1] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[2], cell.val[1], cell.val[2]));
else vertlist[1] = edge_intersections_old_y[x * (numy-1) + y];
}
if (edge_table[cubeindex] & 4) // edge in x at y+1
{
if(z==0) vertlist[2] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[3], cell.val[2], cell.val[3]));
else vertlist[2] = edge_intersections_old_x[(y+1) * (numx-1) + x];
}
if (edge_table[cubeindex] & 8) // edge in y at x+1
{
if(z==0) vertlist[3] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[0], cell.val[3], cell.val[0]));
else vertlist[3] = edge_intersections_old_y[(x+1) * (numy-1) + y];
}
}
{ // edges on the new z plane
if (edge_table[cubeindex] & 16) // edge in x at y
{
if (edge_intersections_current_x[y * (numx-1) + x] == -1) // check if already assigned
{
vertlist[4] = push_vertex(VertexInterp(isovalue, cell.p[4], cell.p[5], cell.val[4], cell.val[5]));
edge_intersections_current_x[y * (numx-1) + x] = vertlist[4];
}
else
{
vertlist[4] = edge_intersections_current_x[y * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 32) // edge in y at x
{
if(edge_intersections_current_y[x * (numy-1) + y] == -1)
{
vertlist[5] = push_vertex(VertexInterp(isovalue, cell.p[5], cell.p[6], cell.val[5], cell.val[6]));
edge_intersections_current_y[x * (numy-1) + y] = vertlist[5];
}
else
{
vertlist[5] = edge_intersections_current_y[x * (numy-1) + y];
}
}
if (edge_table[cubeindex] & 64) // edge in x at y+1
{
if (edge_intersections_current_x[(y+1) * (numx-1) + x] == -1)
{
vertlist[6] = push_vertex(VertexInterp(isovalue, cell.p[6], cell.p[7], cell.val[6], cell.val[7]));
edge_intersections_current_x[(y+1) * (numx-1) + x] = vertlist[6];
}
else
{
vertlist[6] = edge_intersections_current_x[(y+1) * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 128) // edge in y at x+1
{
if (edge_intersections_current_y[(x+1) * (numy-1) + y] == -1)
{
vertlist[7] = push_vertex(VertexInterp(isovalue, cell.p[7], cell.p[4], cell.val[7], cell.val[4]));
edge_intersections_current_y[(x+1) * (numy-1) + y] = vertlist[7];
}
else
{
vertlist[7] = edge_intersections_current_y[(x+1) * (numy-1) + y];
}
}
}
{ // between the z planes
if (edge_table[cubeindex] & 256) // 0 -- 4, x + 1, y
{
if (edge_intersections_current_z[y * numx + (x+1)] == -1)
{
vertlist[8] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[4], cell.val[0], cell.val[4]));
edge_intersections_current_z[y * numx + (x+1)] = vertlist[8];
}
else
{
vertlist[8] = edge_intersections_current_z[y * numx + (x+1)];
}
}
if (edge_table[cubeindex] & 512) // 1 -- 5, x, y
{
if (edge_intersections_current_z[y * numx + x] == -1)
{
vertlist[9] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[5], cell.val[1], cell.val[5]));
edge_intersections_current_z[y * numx + x] = vertlist[9];
}
else
{
vertlist[9] = edge_intersections_current_z[y * numx + x];
}
}
if (edge_table[cubeindex] & 1024) // 2 -- 6, x, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + x] == -1)
{
vertlist[10] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[6], cell.val[2], cell.val[6]));
edge_intersections_current_z[(y+1) * numx + x] = vertlist[10];
}
else
{
vertlist[10] = edge_intersections_current_z[(y+1) * numx + x];
}
}
if (edge_table[cubeindex] & 2048) // 3 -- 7, x + 1, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + (x+1)] == -1)
{
vertlist[11] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[7], cell.val[3], cell.val[7]));
edge_intersections_current_z[(y+1) * numx + (x+1)] = vertlist[11];
}
else
{
vertlist[11] = edge_intersections_current_z[(y+1) * numx + (x+1)];
}
}
}
// push face indices
for (int i = 0; triangle_table[cubeindex][i] != -1; ++i)
polygons.push_back(vertlist[triangle_table[cubeindex][i]]);
}
}
}
delete[] edge_intersections_old_x;
delete[] edge_intersections_old_y;
delete[] edge_intersections_current_x;
delete[] edge_intersections_current_y;
delete[] edge_intersections_current_z;
#else
// numx, numy and numz are the numbers of evaluations in each direction
--numx; --numy; --numz;
coord_type dx = (upper[0] - lower[0]) / static_cast(numx);
coord_type dy = (upper[1] - lower[1]) / static_cast(numy);
coord_type dz = (upper[2] - lower[2]) / static_cast(numz);
const int num_shared_indices = 2 * (numy + 1) * (numz + 1);
std::vector shared_indices_x(num_shared_indices);
std::vector shared_indices_y(num_shared_indices);
std::vector shared_indices_z(num_shared_indices);
// const int numz = numz*3;
const int numyz = numy*numz;
for(int i=0; i indices;
// for three edges we have to compute it for sure (if zerocrossing)
if(edges & 0x040)
{
indices[6] = vertices.size() / 3;
shared_indices_x[i_mod_2_inv*numyz + (j+1)*numz + (k+1)] = indices[6];
mc_add_vertex(x_dx, y_dy, z_dz, x, 0, v[6], v[7], isovalue, &vertices);
}
if(edges & 0x020)
{
indices[5] = vertices.size() / 3;
shared_indices_y[i_mod_2_inv*numyz + (j+1)*numz + (k+1)] = indices[5];
mc_add_vertex(x_dx, y, z_dz, y_dy, 1, v[5], v[6], isovalue, &vertices);
}
if(edges & 0x400)
{
indices[10] = vertices.size() / 3;
shared_indices_z[i_mod_2_inv*numyz + (j+1)*numz + (k+1)] = indices[10];
mc_add_vertex(x_dx, y+dx, z, z_dz, 2, v[2], v[6], isovalue, &vertices);
}
if(edges & 0x001)
{
if(j == 0 && k == 0)
{
indices[0] = vertices.size() / 3;
mc_add_vertex(x, y, z, x_dx, 0, v[0], v[1], isovalue, &vertices);
}
else
indices[0] = shared_indices_x[i_mod_2_inv*numyz + j*numz + k];
}
if(edges & 0x002)
{
if(k == 0)
{
indices[1] = vertices.size() / 3;
shared_indices_y[i_mod_2_inv*numyz + (j+1)*numz + k] = indices[1];
mc_add_vertex(x_dx, y, z, y_dy, 1, v[1], v[2], isovalue, &vertices);
}
else
indices[1] = shared_indices_y[i_mod_2_inv*numyz + (j+1)*numz + k];
}
if(edges & 0x004)
{
if(k == 0)
{
indices[2] = vertices.size() / 3;
shared_indices_x[i_mod_2_inv*numyz + (j+1)*numz + k] = indices[2];
mc_add_vertex(x_dx, y_dy, z, x, 0, v[2], v[3], isovalue, &vertices);
}
else
indices[2] = shared_indices_x[i_mod_2_inv*numyz + (j+1)*numz + k];
}
if(edges & 0x008)
{
if(i == 0 && k == 0)
{
indices[3] = vertices.size() / 3;
mc_add_vertex(x, y_dy, z, y, 1, v[3], v[0], isovalue, &vertices);
}
else
indices[3] = shared_indices_y[i_mod_2*numyz + (j+1)*numz + k];
}
if(edges & 0x010)
{
if(j == 0)
{
indices[4] = vertices.size() / 3;
shared_indices_x[i_mod_2_inv*numyz + j*numz + (k+1)] = indices[4];
mc_add_vertex(x, y, z_dz, x_dx, 0, v[4], v[5], isovalue, &vertices);
}
else
indices[4] = shared_indices_x[i_mod_2_inv*numyz + j*numz + (k+1)];
}
if(edges & 0x080)
{
if(i == 0)
{
indices[7] = vertices.size() / 3;
shared_indices_y[i_mod_2*numyz + (j+1)*numz + (k+1)] = indices[7];
mc_add_vertex(x, y_dy, z_dz, y, 1, v[7], v[4], isovalue, &vertices);
}
else
indices[7] = shared_indices_y[i_mod_2*numyz + (j+1)*numz + (k+1)];
}
if(edges & 0x100)
{
if(i == 0 && j == 0)
{
indices[8] = vertices.size() / 3;
mc_add_vertex(x, y, z, z_dz, 2, v[0], v[4], isovalue, &vertices);
}
else
indices[8] = shared_indices_z[i_mod_2*numyz + j*numz + (k+1)];
}
if(edges & 0x200)
{
if(j == 0)
{
indices[9] = vertices.size() / 3;
shared_indices_z[i_mod_2_inv*numyz + j*numz + (k+1)] = indices[9];
mc_add_vertex(x_dx, y, z, z_dz, 2, v[1], v[5], isovalue, &vertices);
}
else
indices[9] = shared_indices_z[i_mod_2_inv*numyz + j*numz + (k+1)];
}
if(edges & 0x800)
{
if(i == 0)
{
indices[11] = vertices.size() / 3;
shared_indices_z[i_mod_2*numyz + (j+1)*numz + (k+1)] = indices[11];
mc_add_vertex(x, y_dy, z, z_dz, 2, v[3], v[7], isovalue, &vertices);
}
else
indices[11] = shared_indices_z[i_mod_2*numyz + (j+1)*numz + (k+1)];
}
int tri;
int* triangle_table_ptr = triangle_table[cubeindex];
for(int m=0; tri = triangle_table_ptr[m], tri != -1; ++m)
polygons.push_back(indices[tri]);
/*if(triangle_table_ptr[0] == -1) continue;
Eigen::Vector3d last(vertices[3*indices[triangle_table_ptr[0] ]+0], vertices[3*indices[triangle_table_ptr[0] ]+1], vertices[3*indices[triangle_table_ptr[0] ]+2]);
for(int m=0; tri = triangle_table_ptr[m], tri != -1; ++m)
{
Eigen::Vector3d current(vertices[3*indices[tri]+0], vertices[3*indices[tri]+1], vertices[3*indices[tri]+2]);
if ((current-last).norm() > std::sqrt(dx*dx + dy*dy + dz*dz))
{
std::cout << "error: " << (current-last).norm() << std::endl;
std::cout << "cubeindex: " << cubeindex << std::endl;
std::cout << "i: " << i << std::endl;
std::cout << "j: " << j << std::endl;
std::cout << "k: " << k << std::endl;
std::cout << "m: " << m << std::endl;
}
last = current;
polygons.push_back(indices[tri]);
}*/
}
}
}
#endif
}
/////////////////////////////
/////////////////////////////
////////// COLOR //////////
/////////////////////////////
/////////////////////////////
template
void marching_cubes_color(const vector3& lower, const vector3& upper,
int numx, int numy, int numz, formula_sdf f_sdf, formula_color f_color, double isovalue,
std::vector& vertices, std::vector& polygons)
{
using coord_type = typename vector3::value_type;
using size_type = typename vector3::size_type;
using namespace private_;
// Some initial checks
if(numx < 2 || numy < 2 || numz < 2)
return;
if(!std::equal(std::begin(lower), std::end(lower), std::begin(upper),
[](double a, double b)->bool {return a <= b;}))
return;
double dx = (upper[0] - lower[0]) / (numx - 1.0);
double dy = (upper[1] - lower[1]) / (numy - 1.0);
double dz = (upper[2] - lower[2]) / (numz - 1.0);
auto coord_mapper = [&](int x, int y, int z) { return Eigen::Vector3d( lower[0] + x * dx, lower[1] + y * dy, lower[2] + z * dz ); };
//auto push_vertex = [&] (Eigen::Vector3d xyz) {int id = vertices.size()/3; vertices.push_back(xyz.x()); vertices.push_back(xyz.y()); vertices.push_back(xyz.z()); return id;};
auto push_vertex = [&] (const Vector6d& xyz_rgb)
{
int id = vertices.size()/6;
for(unsigned int i=0; i<6; ++i) vertices.push_back(xyz_rgb[i]);
return id;
};
// vertex zero crossing interpolation
// f(p2) = valp2
// x
// /
// x f(p) = isolevel
// /
// /
// /
// x
// f(p1) = valp1
auto VertexInterp = [&](double isolevel, const Vector6d& p1, const Vector6d& p2, double valp1, double valp2) -> Vector6d
{
double alpha = (valp2 - isolevel) / (valp2 - valp1);
return alpha*p1 + (1 - alpha)*p2;
};
// store intersections of old z plane to avoid duplicated vertices
int* edge_intersections_old_x = new int[(numx-1) * numy];
int* edge_intersections_old_y = new int[numx * (numy-1)];
int* edge_intersections_current_x = new int[(numx-1) * numy];
int* edge_intersections_current_y = new int[numx * (numy-1)];
// store intersections within the z-planes to avoid duplicated vertices
int* edge_intersections_current_z = new int[numx * numy];
for (int z = 0; z < numz - 1; z++)
{
// swap index storage
std::swap(edge_intersections_old_x, edge_intersections_current_x); // old = current
std::swap(edge_intersections_old_y, edge_intersections_current_y);
std::fill_n(edge_intersections_current_x, (numx-1) * numy, -1); // invalidate
std::fill_n(edge_intersections_current_y, (numy-1) * numx, -1); // invalidate
std::fill_n(edge_intersections_current_z, numy * numx, -1); // invalidate
for (int y = 0; y < numy - 1; y++)
{
for (int x = 0; x < numx - 1; x++)
{
// Process Volume Cell
MC_Gridcell_Color cell;
//
// 4---5
// / /|
// 0---1 6
// | |/
// 3---2
// cell corners
cell.p[0].block<3,1>(0,0) = coord_mapper(x + 1, y, z);
cell.p[1].block<3,1>(0,0) = coord_mapper(x, y, z);
cell.p[2].block<3,1>(0,0) = coord_mapper(x, y + 1, z);
cell.p[3].block<3,1>(0,0) = coord_mapper(x + 1, y + 1, z);
cell.p[4].block<3,1>(0,0) = coord_mapper(x + 1, y, z + 1);
cell.p[5].block<3,1>(0,0) = coord_mapper(x, y, z + 1);
cell.p[6].block<3,1>(0,0) = coord_mapper(x, y + 1, z + 1);
cell.p[7].block<3,1>(0,0) = coord_mapper(x + 1, y + 1, z + 1);
// cell colors
cell.p[0].block<3,1>(3,0) = f_color(x + 1, y, z);
cell.p[1].block<3,1>(3,0) = f_color(x, y, z);
cell.p[2].block<3,1>(3,0) = f_color(x, y + 1, z);
cell.p[3].block<3,1>(3,0) = f_color(x + 1, y + 1, z);
cell.p[4].block<3,1>(3,0) = f_color(x + 1, y, z + 1);
cell.p[5].block<3,1>(3,0) = f_color(x, y, z + 1);
cell.p[6].block<3,1>(3,0) = f_color(x, y + 1, z + 1);
cell.p[7].block<3,1>(3,0) = f_color(x + 1, y + 1, z + 1);
// cell corner values
cell.val[0] = (double)f_sdf(x + 1, y, z);
cell.val[1] = (double)f_sdf(x, y, z);
cell.val[2] = (double)f_sdf(x, y + 1, z);
cell.val[3] = (double)f_sdf(x + 1, y + 1, z);
cell.val[4] = (double)f_sdf(x + 1, y, z + 1);
cell.val[5] = (double)f_sdf(x, y, z + 1);
cell.val[6] = (double)f_sdf(x, y + 1, z + 1);
cell.val[7] = (double)f_sdf(x + 1, y + 1, z + 1);
// triangulation code
int cubeindex = 0;
if (cell.val[0] < isovalue) cubeindex |= 1;
if (cell.val[1] < isovalue) cubeindex |= 2;
if (cell.val[2] < isovalue) cubeindex |= 4;
if (cell.val[3] < isovalue) cubeindex |= 8;
if (cell.val[4] < isovalue) cubeindex |= 16;
if (cell.val[5] < isovalue) cubeindex |= 32;
if (cell.val[6] < isovalue) cubeindex |= 64;
if (cell.val[7] < isovalue) cubeindex |= 128;
// Cube is entirely in/out of the surface
if (edge_table[cubeindex] == 0) continue;
/* Find the vertices where the surface intersects the cube */
int vertlist[12];
{ // edges on the old z plane
if (edge_table[cubeindex] & 1) // edge in x at y
{
if(z==0) vertlist[0] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[1], cell.val[0], cell.val[1]));
else vertlist[0] = edge_intersections_old_x[y * (numx-1) + x];
}
if (edge_table[cubeindex] & 2) // edge in y at x
{
if(z==0) vertlist[1] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[2], cell.val[1], cell.val[2]));
else vertlist[1] = edge_intersections_old_y[x * (numy-1) + y];
}
if (edge_table[cubeindex] & 4) // edge in x at y+1
{
if(z==0) vertlist[2] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[3], cell.val[2], cell.val[3]));
else vertlist[2] = edge_intersections_old_x[(y+1) * (numx-1) + x];
}
if (edge_table[cubeindex] & 8) // edge in y at x+1
{
if(z==0) vertlist[3] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[0], cell.val[3], cell.val[0]));
else vertlist[3] = edge_intersections_old_y[(x+1) * (numy-1) + y];
}
}
{ // edges on the new z plane
if (edge_table[cubeindex] & 16) // edge in x at y
{
if (edge_intersections_current_x[y * (numx-1) + x] == -1) // check if already assigned
{
vertlist[4] = push_vertex(VertexInterp(isovalue, cell.p[4], cell.p[5], cell.val[4], cell.val[5]));
edge_intersections_current_x[y * (numx-1) + x] = vertlist[4];
}
else
{
vertlist[4] = edge_intersections_current_x[y * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 32) // edge in y at x
{
if(edge_intersections_current_y[x * (numy-1) + y] == -1)
{
vertlist[5] = push_vertex(VertexInterp(isovalue, cell.p[5], cell.p[6], cell.val[5], cell.val[6]));
edge_intersections_current_y[x * (numy-1) + y] = vertlist[5];
}
else
{
vertlist[5] = edge_intersections_current_y[x * (numy-1) + y];
}
}
if (edge_table[cubeindex] & 64) // edge in x at y+1
{
if (edge_intersections_current_x[(y+1) * (numx-1) + x] == -1)
{
vertlist[6] = push_vertex(VertexInterp(isovalue, cell.p[6], cell.p[7], cell.val[6], cell.val[7]));
edge_intersections_current_x[(y+1) * (numx-1) + x] = vertlist[6];
}
else
{
vertlist[6] = edge_intersections_current_x[(y+1) * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 128) // edge in y at x+1
{
if (edge_intersections_current_y[(x+1) * (numy-1) + y] == -1)
{
vertlist[7] = push_vertex(VertexInterp(isovalue, cell.p[7], cell.p[4], cell.val[7], cell.val[4]));
edge_intersections_current_y[(x+1) * (numy-1) + y] = vertlist[7];
}
else
{
vertlist[7] = edge_intersections_current_y[(x+1) * (numy-1) + y];
}
}
}
{ // between the z planes
if (edge_table[cubeindex] & 256) // 0 -- 4, x + 1, y
{
if (edge_intersections_current_z[y * numx + (x+1)] == -1)
{
vertlist[8] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[4], cell.val[0], cell.val[4]));
edge_intersections_current_z[y * numx + (x+1)] = vertlist[8];
}
else
{
vertlist[8] = edge_intersections_current_z[y * numx + (x+1)];
}
}
if (edge_table[cubeindex] & 512) // 1 -- 5, x, y
{
if (edge_intersections_current_z[y * numx + x] == -1)
{
vertlist[9] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[5], cell.val[1], cell.val[5]));
edge_intersections_current_z[y * numx + x] = vertlist[9];
}
else
{
vertlist[9] = edge_intersections_current_z[y * numx + x];
}
}
if (edge_table[cubeindex] & 1024) // 2 -- 6, x, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + x] == -1)
{
vertlist[10] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[6], cell.val[2], cell.val[6]));
edge_intersections_current_z[(y+1) * numx + x] = vertlist[10];
}
else
{
vertlist[10] = edge_intersections_current_z[(y+1) * numx + x];
}
}
if (edge_table[cubeindex] & 2048) // 3 -- 7, x + 1, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + (x+1)] == -1)
{
vertlist[11] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[7], cell.val[3], cell.val[7]));
edge_intersections_current_z[(y+1) * numx + (x+1)] = vertlist[11];
}
else
{
vertlist[11] = edge_intersections_current_z[(y+1) * numx + (x+1)];
}
}
}
// push face indices
for (int i = 0; triangle_table[cubeindex][i] != -1; ++i)
polygons.push_back(vertlist[triangle_table[cubeindex][i]]);
}
}
}
delete[] edge_intersections_old_x;
delete[] edge_intersections_old_y;
delete[] edge_intersections_current_x;
delete[] edge_intersections_current_y;
delete[] edge_intersections_current_z;
}
//////////////////////////////////////
//////////////////////////////////////
////////// SUPER SAMPLING //////////
//////////////////////////////////////
//////////////////////////////////////
template
void marching_cubes_super_sampling(const vector3& lower, const vector3& upper,
int numx, int numy, int numz,
int superx, int supery, int superz,
formula f,
formulaX f_superX, formulaY f_superY, formulaZ f_superZ,
double isovalue,
std::vector& vertices, std::vector& polygons)
{
using coord_type = typename vector3::value_type;
using size_type = typename vector3::size_type;
using namespace private_;
// Some initial checks
if(numx < 2 || numy < 2 || numz < 2)
return;
if(!std::equal(std::begin(lower), std::end(lower), std::begin(upper),
[](double a, double b)->bool {return a <= b;}))
return;
double dx = (upper[0] - lower[0]) / (numx - 1.0);
double dy = (upper[1] - lower[1]) / (numy - 1.0);
double dz = (upper[2] - lower[2]) / (numz - 1.0);
double scale_x = (numx - 1.0) / ( numx + (numx - 1) * superx - 1.0 ); // map super sampling coordinates back to actual sampling coordinates
double scale_y = (numy - 1.0) / ( numy + (numy - 1) * supery - 1.0 );
double scale_z = (numz - 1.0) / ( numz + (numz - 1) * superz - 1.0 );
//auto coord_mapper = [&](int x, int y, int z) { return Eigen::Vector3d( lower[0] + x * dx, lower[1] + y * dy, lower[2] + z * dz ); };
auto coord_mapper = [&](int x, int y, int z) { return Eigen::Vector3d( x,y,z ); };
auto push_vertex = [&] (Eigen::Vector3d xyz) {int id = vertices.size()/3; vertices.push_back(xyz.x()); vertices.push_back(xyz.y()); vertices.push_back(xyz.z()); return id;};
auto sign = [](double x) { return x > 0.0; };
// vertex zero crossing interpolation
// f(p2) = valp2
// x
// /
// x f(p) = isolevel
// /
// /
// /
// x
// f(p1) = valp1
auto VertexInterp = [&](double isolevel, const Eigen::Vector3d& p1, const Eigen::Vector3d& p2, double valp1, double valp2) -> Eigen::Vector3d
{
bool edge_in_x_dir = p1.x() != p2.x() && p1.y() == p2.y() && p1.z() == p2.z();
bool edge_in_y_dir = p1.x() == p2.x() && p1.y() != p2.y() && p1.z() == p2.z();
bool edge_in_z_dir = p1.x() == p2.x() && p1.y() == p2.y() && p1.z() != p2.z();
//if (edge_in_x_dir == true && edge_in_y_dir==true) std::cout << "ERROR XY" << std::endl;
//if (edge_in_x_dir == true && edge_in_z_dir==true) std::cout << "ERROR XZ" << std::endl;
//if (edge_in_y_dir == true && edge_in_z_dir==true) std::cout << "ERROR YZ" << std::endl;
//if (edge_in_x_dir == false && edge_in_y_dir == false && edge_in_z_dir==false) std::cout << "ERROR XYZ=FALSE" << std::endl;
Eigen::Vector3d p1_ss = p1;
Eigen::Vector3d p2_ss = p2;
double valp1_ss = valp1;
double valp2_ss = valp2;
//if (edge_in_x_dir) std::cout << "edge_in_x_dir" << std::endl;
//if (edge_in_y_dir) std::cout << "edge_in_y_dir" << std::endl;
//if (edge_in_z_dir) std::cout << "edge_in_z_dir" << std::endl;
//if (fabs(valp1-isolevel)!=0.0 && fabs(valp2-isolevel)==0.0)
{
if (edge_in_x_dir)
{
// [ 0.0, 0.0, 0.0, 1.0, 1.0 ] -->valp1 = 0.0, valp2=1.0 --> val_prev=0.0
// [ 1.0, 1.0, 0.0, 0.0, 0.0 ] -->valp1 = 1.0, valp2=0.0 --> val_prev=1.0
int min_x = std::min(p1.x(), p2.x());
double val_prev = valp1;
if(p2.x() == min_x) val_prev=valp2;
int y = p1.y();
int z = p1.z();
for(int i=1; i<=superx+1; ++i) // could do interval halfing / binary search
{
// find isolevel point
int x = min_x*(superx+1) + i;
double val = (double)f_superX(x, y, z);
if (sign(val-isolevel) != sign(val_prev-isolevel) || (fabs(val-isolevel)==0.0 && fabs(val_prev-isolevel)!=0.0 )) // zero crossing
{
valp1_ss = val_prev;
valp2_ss = val;
p1_ss.x() = (x - 1) * scale_x;
p2_ss.x() = x * scale_x;
break;
}
val_prev = val;
}
}
if (edge_in_y_dir)
{
int min_y = std::min(p1.y(), p2.y());
double val_prev = valp1;
if(p2.y() == min_y) val_prev=valp2;
int x = p1.x();
int z = p1.z();
for(int i=1; i<=supery+1; ++i) // could do interval halfing / binary search
{
// find isolevel point
int y = min_y*(supery+1) + i;
double val = (double)f_superY(x, y, z);
if (sign(val-isolevel) != sign(val_prev-isolevel) || (fabs(val-isolevel)==0.0 && fabs(val_prev-isolevel)!=0.0 )) // zero crossing
{
valp1_ss = val_prev;
valp2_ss = val;
p1_ss.y() = (y - 1) * scale_y;
p2_ss.y() = y * scale_y;
break;
}
val_prev = val;
}
}
if (edge_in_z_dir)
{
int min_z = std::min(p1.z(), p2.z());
double val_prev = valp1;
if(p2.z() == min_z) val_prev=valp2;
int x = p1.x();
int y = p1.y();
for(int i=1; i<=superz+1; ++i) // could do interval halfing / binary search
{
// find isolevel point
int z = min_z*(superz+1) + i;
double val = (double)f_superZ(x, y, z);
if (sign(val-isolevel) != sign(val_prev-isolevel) || (fabs(val-isolevel)==0.0 && fabs(val_prev-isolevel)!=0.0 )) // zero crossing
{
valp1_ss = val_prev;
valp2_ss = val;
p1_ss.z() = (z - 1) * scale_z;
p2_ss.z() = z * scale_z;
break;
}
val_prev = val;
}
}
}
// coord mapper
p1_ss = Eigen::Vector3d( lower[0] + p1_ss.x() * dx, lower[1] + p1_ss.y() * dy, lower[2] + p1_ss.z() * dz);
p2_ss = Eigen::Vector3d( lower[0] + p2_ss.x() * dx, lower[1] + p2_ss.y() * dy, lower[2] + p2_ss.z() * dz);
// actual interpolation
double alpha = (valp2_ss - isolevel) / (valp2_ss - valp1_ss);
if (valp2_ss - valp1_ss == 0.0)
{
alpha = 0.5;
}
return alpha*p1_ss + (1 - alpha)*p2_ss;
};
// store intersections of old z plane to avoid duplicated vertices
int* edge_intersections_old_x = new int[(numx-1) * numy];
int* edge_intersections_old_y = new int[numx * (numy-1)];
int* edge_intersections_current_x = new int[(numx-1) * numy];
int* edge_intersections_current_y = new int[numx * (numy-1)];
// store intersections within the z-planes to avoid duplicated vertices
int* edge_intersections_current_z = new int[numx * numy];
for (int z = 0; z < numz - 1; z++)
{
// swap index storage
std::swap(edge_intersections_old_x, edge_intersections_current_x); // old = current
std::swap(edge_intersections_old_y, edge_intersections_current_y);
std::fill_n(edge_intersections_current_x, (numx-1) * numy, -1); // invalidate
std::fill_n(edge_intersections_current_y, (numy-1) * numx, -1); // invalidate
std::fill_n(edge_intersections_current_z, numy * numx, -1); // invalidate
for (int y = 0; y < numy - 1; y++)
{
for (int x = 0; x < numx - 1; x++)
{
// Process Volume Cell
MC_Gridcell cell;
//
// 4---5
// / /|
// 0---1 6
// | |/
// 3---2
// cell corners
cell.p[0] = coord_mapper(x + 1, y, z);
cell.p[1] = coord_mapper(x, y, z);
cell.p[2] = coord_mapper(x, y + 1, z);
cell.p[3] = coord_mapper(x + 1, y + 1, z);
cell.p[4] = coord_mapper(x + 1, y, z + 1);
cell.p[5] = coord_mapper(x, y, z + 1);
cell.p[6] = coord_mapper(x, y + 1, z + 1);
cell.p[7] = coord_mapper(x + 1, y + 1, z + 1);
// cell corner values
cell.val[0] = (double)f(x + 1, y, z);
cell.val[1] = (double)f(x, y, z);
cell.val[2] = (double)f(x, y + 1, z);
cell.val[3] = (double)f(x + 1, y + 1, z);
cell.val[4] = (double)f(x + 1, y, z + 1);
cell.val[5] = (double)f(x, y, z + 1);
cell.val[6] = (double)f(x, y + 1, z + 1);
cell.val[7] = (double)f(x + 1, y + 1, z + 1);
// triangulation code
int cubeindex = 0;
if (cell.val[0] < isovalue) cubeindex |= 1;
if (cell.val[1] < isovalue) cubeindex |= 2;
if (cell.val[2] < isovalue) cubeindex |= 4;
if (cell.val[3] < isovalue) cubeindex |= 8;
if (cell.val[4] < isovalue) cubeindex |= 16;
if (cell.val[5] < isovalue) cubeindex |= 32;
if (cell.val[6] < isovalue) cubeindex |= 64;
if (cell.val[7] < isovalue) cubeindex |= 128;
// Cube is entirely in/out of the surface
if (edge_table[cubeindex] == 0) continue;
/* Find the vertices where the surface intersects the cube */
int vertlist[12];
{ // edges on the old z plane
if (edge_table[cubeindex] & 1) // edge in x at y
{
if(z==0) vertlist[0] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[1], cell.val[0], cell.val[1]));
else vertlist[0] = edge_intersections_old_x[y * (numx-1) + x];
}
if (edge_table[cubeindex] & 2) // edge in y at x
{
if(z==0) vertlist[1] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[2], cell.val[1], cell.val[2]));
else vertlist[1] = edge_intersections_old_y[x * (numy-1) + y];
}
if (edge_table[cubeindex] & 4) // edge in x at y+1
{
if(z==0) vertlist[2] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[3], cell.val[2], cell.val[3]));
else vertlist[2] = edge_intersections_old_x[(y+1) * (numx-1) + x];
}
if (edge_table[cubeindex] & 8) // edge in y at x+1
{
if(z==0) vertlist[3] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[0], cell.val[3], cell.val[0]));
else vertlist[3] = edge_intersections_old_y[(x+1) * (numy-1) + y];
}
}
{ // edges on the new z plane
if (edge_table[cubeindex] & 16) // edge in x at y
{
if (edge_intersections_current_x[y * (numx-1) + x] == -1) // check if already assigned
{
vertlist[4] = push_vertex(VertexInterp(isovalue, cell.p[4], cell.p[5], cell.val[4], cell.val[5]));
edge_intersections_current_x[y * (numx-1) + x] = vertlist[4];
}
else
{
vertlist[4] = edge_intersections_current_x[y * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 32) // edge in y at x
{
if(edge_intersections_current_y[x * (numy-1) + y] == -1)
{
vertlist[5] = push_vertex(VertexInterp(isovalue, cell.p[5], cell.p[6], cell.val[5], cell.val[6]));
edge_intersections_current_y[x * (numy-1) + y] = vertlist[5];
}
else
{
vertlist[5] = edge_intersections_current_y[x * (numy-1) + y];
}
}
if (edge_table[cubeindex] & 64) // edge in x at y+1
{
if (edge_intersections_current_x[(y+1) * (numx-1) + x] == -1)
{
vertlist[6] = push_vertex(VertexInterp(isovalue, cell.p[6], cell.p[7], cell.val[6], cell.val[7]));
edge_intersections_current_x[(y+1) * (numx-1) + x] = vertlist[6];
}
else
{
vertlist[6] = edge_intersections_current_x[(y+1) * (numx-1) + x];
}
}
if (edge_table[cubeindex] & 128) // edge in y at x+1
{
if (edge_intersections_current_y[(x+1) * (numy-1) + y] == -1)
{
vertlist[7] = push_vertex(VertexInterp(isovalue, cell.p[7], cell.p[4], cell.val[7], cell.val[4]));
edge_intersections_current_y[(x+1) * (numy-1) + y] = vertlist[7];
}
else
{
vertlist[7] = edge_intersections_current_y[(x+1) * (numy-1) + y];
}
}
}
{ // between the z planes
if (edge_table[cubeindex] & 256) // 0 -- 4, x + 1, y
{
if (edge_intersections_current_z[y * numx + (x+1)] == -1)
{
vertlist[8] = push_vertex(VertexInterp(isovalue, cell.p[0], cell.p[4], cell.val[0], cell.val[4]));
edge_intersections_current_z[y * numx + (x+1)] = vertlist[8];
}
else
{
vertlist[8] = edge_intersections_current_z[y * numx + (x+1)];
}
}
if (edge_table[cubeindex] & 512) // 1 -- 5, x, y
{
if (edge_intersections_current_z[y * numx + x] == -1)
{
vertlist[9] = push_vertex(VertexInterp(isovalue, cell.p[1], cell.p[5], cell.val[1], cell.val[5]));
edge_intersections_current_z[y * numx + x] = vertlist[9];
}
else
{
vertlist[9] = edge_intersections_current_z[y * numx + x];
}
}
if (edge_table[cubeindex] & 1024) // 2 -- 6, x, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + x] == -1)
{
vertlist[10] = push_vertex(VertexInterp(isovalue, cell.p[2], cell.p[6], cell.val[2], cell.val[6]));
edge_intersections_current_z[(y+1) * numx + x] = vertlist[10];
}
else
{
vertlist[10] = edge_intersections_current_z[(y+1) * numx + x];
}
}
if (edge_table[cubeindex] & 2048) // 3 -- 7, x + 1, y + 1
{
if (edge_intersections_current_z[(y+1) * numx + (x+1)] == -1)
{
vertlist[11] = push_vertex(VertexInterp(isovalue, cell.p[3], cell.p[7], cell.val[3], cell.val[7]));
edge_intersections_current_z[(y+1) * numx + (x+1)] = vertlist[11];
}
else
{
vertlist[11] = edge_intersections_current_z[(y+1) * numx + (x+1)];
}
}
}
// push face indices
for (int i = 0; triangle_table[cubeindex][i] != -1; ++i)
polygons.push_back(vertlist[triangle_table[cubeindex][i]]);
}
}
}
delete[] edge_intersections_old_x;
delete[] edge_intersections_old_y;
delete[] edge_intersections_current_x;
delete[] edge_intersections_current_y;
delete[] edge_intersections_current_z;
}
}
#endif // _MARCHING_CUBES_H
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/pyarray_symbol.h
================================================
#define PY_ARRAY_UNIQUE_SYMBOL mcubes_PyArray_API
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/pyarraymodule.h
================================================
#ifndef _EXTMODULE_H
#define _EXTMODULE_H
#include
#include
// #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL mcubes_PyArray_API
#define NO_IMPORT_ARRAY
#include "numpy/arrayobject.h"
#include
template
struct numpy_typemap;
#define define_numpy_type(ctype, dtype) \
template<> \
struct numpy_typemap \
{static const int type = dtype;};
define_numpy_type(bool, NPY_BOOL);
define_numpy_type(char, NPY_BYTE);
define_numpy_type(short, NPY_SHORT);
define_numpy_type(int, NPY_INT);
define_numpy_type(long, NPY_LONG);
define_numpy_type(long long, NPY_LONGLONG);
define_numpy_type(unsigned char, NPY_UBYTE);
define_numpy_type(unsigned short, NPY_USHORT);
define_numpy_type(unsigned int, NPY_UINT);
define_numpy_type(unsigned long, NPY_ULONG);
define_numpy_type(unsigned long long, NPY_ULONGLONG);
define_numpy_type(float, NPY_FLOAT);
define_numpy_type(double, NPY_DOUBLE);
define_numpy_type(long double, NPY_LONGDOUBLE);
define_numpy_type(std::complex, NPY_CFLOAT);
define_numpy_type(std::complex, NPY_CDOUBLE);
define_numpy_type(std::complex, NPY_CLONGDOUBLE);
template
T PyArray_SafeGet(const PyArrayObject* aobj, const npy_intp* indaux)
{
// HORROR.
npy_intp* ind = const_cast(indaux);
void* ptr = PyArray_GetPtr(const_cast(aobj), ind);
switch(PyArray_TYPE(aobj))
{
case NPY_BOOL:
return static_cast(*reinterpret_cast(ptr));
case NPY_BYTE:
return static_cast(*reinterpret_cast(ptr));
case NPY_SHORT:
return static_cast(*reinterpret_cast(ptr));
case NPY_INT:
return static_cast(*reinterpret_cast(ptr));
case NPY_LONG:
return static_cast(*reinterpret_cast(ptr));
case NPY_LONGLONG:
return static_cast(*reinterpret_cast(ptr));
case NPY_UBYTE:
return static_cast(*reinterpret_cast(ptr));
case NPY_USHORT:
return static_cast(*reinterpret_cast(ptr));
case NPY_UINT:
return static_cast(*reinterpret_cast(ptr));
case NPY_ULONG:
return static_cast(*reinterpret_cast(ptr));
case NPY_ULONGLONG:
return static_cast(*reinterpret_cast(ptr));
case NPY_FLOAT:
return static_cast(*reinterpret_cast(ptr));
case NPY_DOUBLE:
return static_cast(*reinterpret_cast(ptr));
case NPY_LONGDOUBLE:
return static_cast(*reinterpret_cast(ptr));
default:
throw std::runtime_error("data type not supported");
}
}
template
T PyArray_SafeSet(PyArrayObject* aobj, const npy_intp* indaux, const T& value)
{
// HORROR.
npy_intp* ind = const_cast(indaux);
void* ptr = PyArray_GetPtr(aobj, ind);
switch(PyArray_TYPE(aobj))
{
case NPY_BOOL:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_BYTE:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_SHORT:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_INT:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_LONG:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_LONGLONG:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_UBYTE:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_USHORT:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_UINT:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_ULONG:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_ULONGLONG:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_FLOAT:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_DOUBLE:
*reinterpret_cast(ptr) = static_cast(value);
break;
case NPY_LONGDOUBLE:
*reinterpret_cast(ptr) = static_cast(value);
break;
default:
throw std::runtime_error("data type not supported");
}
}
#endif
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/pywrapper.cpp
================================================
#include "pywrapper.h"
#include "marchingcubes.h"
#include
#include
PyObject* marching_cubes_func(PyObject* lower, PyObject* upper,
int numx, int numy, int numz, PyObject* pyfunc, double isovalue)
{
std::vector vertices;
std::vector polygons;
// Copy the lower and upper coordinates to a C array.
std::array lower_;
std::array upper_;
for(int i=0; i<3; ++i)
{
PyObject* l = PySequence_GetItem(lower, i);
if(l == NULL)
throw std::runtime_error("len(lower) < 3");
PyObject* u = PySequence_GetItem(upper, i);
if(u == NULL)
{
Py_DECREF(l);
throw std::runtime_error("len(upper) < 3");
}
lower_[i] = PyFloat_AsDouble(l);
upper_[i] = PyFloat_AsDouble(u);
Py_DECREF(l);
Py_DECREF(u);
if(lower_[i]==-1.0 || upper_[i]==-1.0)
{
if(PyErr_Occurred())
throw std::runtime_error("unknown error");
}
}
auto pyfunc_to_cfunc = [&](double x, double y, double z) -> double {
PyObject* res = PyObject_CallFunction(pyfunc, "(d,d,d)", x, y, z);
if(res == NULL)
return 0.0;
double result = PyFloat_AsDouble(res);
Py_DECREF(res);
return result;
};
// Marching cubes.
mc::marching_cubes(lower_, upper_, numx, numy, numz, pyfunc_to_cfunc, isovalue, vertices, polygons);
// Copy the result to two Python ndarrays.
npy_intp size_vertices = vertices.size();
npy_intp size_polygons = polygons.size();
PyArrayObject* verticesarr = reinterpret_cast(PyArray_SimpleNew(1, &size_vertices, PyArray_DOUBLE));
PyArrayObject* polygonsarr = reinterpret_cast(PyArray_SimpleNew(1, &size_polygons, PyArray_ULONG));
std::vector::const_iterator it = vertices.begin();
for(int i=0; it!=vertices.end(); ++i, ++it)
*reinterpret_cast(PyArray_GETPTR1(verticesarr, i)) = *it;
std::vector::const_iterator it2 = polygons.begin();
for(int i=0; it2!=polygons.end(); ++i, ++it2)
*reinterpret_cast(PyArray_GETPTR1(polygonsarr, i)) = *it2;
PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr);
Py_XDECREF(verticesarr);
Py_XDECREF(polygonsarr);
return res;
}
PyObject* marching_cubes(PyArrayObject* arr, double isovalue)
{
if(PyArray_NDIM(arr) != 3)
throw std::runtime_error("Only three-dimensional arrays are supported.");
// Prepare data.
npy_intp* shape = PyArray_DIMS(arr);
std::array lower{0, 0, 0};
std::array upper{shape[0]-1, shape[1]-1, shape[2]-1};
long numx = upper[0] - lower[0] + 1;
long numy = upper[1] - lower[1] + 1;
long numz = upper[2] - lower[2] + 1;
std::vector vertices;
std::vector polygons;
auto pyarray_to_cfunc = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x, y, z};
return PyArray_SafeGet(arr, c);
};
// Marching cubes.
mc::marching_cubes(lower, upper, numx, numy, numz, pyarray_to_cfunc, isovalue,
vertices, polygons);
// Copy the result to two Python ndarrays.
npy_intp size_vertices = vertices.size();
npy_intp size_polygons = polygons.size();
PyArrayObject* verticesarr = reinterpret_cast(PyArray_SimpleNew(1, &size_vertices, PyArray_DOUBLE));
PyArrayObject* polygonsarr = reinterpret_cast(PyArray_SimpleNew(1, &size_polygons, PyArray_ULONG));
std::vector::const_iterator it = vertices.begin();
for(int i=0; it!=vertices.end(); ++i, ++it)
*reinterpret_cast(PyArray_GETPTR1(verticesarr, i)) = *it;
std::vector::const_iterator it2 = polygons.begin();
for(int i=0; it2!=polygons.end(); ++i, ++it2)
*reinterpret_cast(PyArray_GETPTR1(polygonsarr, i)) = *it2;
PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr);
Py_XDECREF(verticesarr);
Py_XDECREF(polygonsarr);
return res;
}
PyObject* marching_cubes_color_func(PyObject* lower, PyObject* upper,
int numx, int numy, int numz, PyObject* pyfunc_sdf, PyObject* pyfunc_r, PyObject* pyfunc_g, PyObject* pyfunc_b, double isovalue)
{
std::vector vertices;
std::vector polygons;
// Copy the lower and upper coordinates to a C array.
std::array lower_;
std::array upper_;
for(int i=0; i<3; ++i)
{
PyObject* l = PySequence_GetItem(lower, i);
if(l == NULL)
throw std::runtime_error("len(lower) < 3");
PyObject* u = PySequence_GetItem(upper, i);
if(u == NULL)
{
Py_DECREF(l);
throw std::runtime_error("len(upper) < 3");
}
lower_[i] = PyFloat_AsDouble(l);
upper_[i] = PyFloat_AsDouble(u);
Py_DECREF(l);
Py_DECREF(u);
if(lower_[i]==-1.0 || upper_[i]==-1.0)
{
if(PyErr_Occurred())
throw std::runtime_error("unknown error");
}
}
auto pyfunc_to_cfunc_sdf = [&](double x, double y, double z) -> double {
PyObject* res = PyObject_CallFunction(pyfunc_sdf, "(d,d,d)", x, y, z);
if(res == NULL)
return 0.0;
double result = PyFloat_AsDouble(res);
Py_DECREF(res);
return result;
};
auto pyfunc_to_cfunc_color = [&](double x, double y, double z) -> Eigen::Vector3d {
Eigen::Vector3d col;
{ // red
PyObject* res = PyObject_CallFunction(pyfunc_r, "(d,d,d)", x, y, z);
if(res == NULL) return Eigen::Vector3d::Zero();
col.x() = PyFloat_AsDouble(res);
Py_DECREF(res);
}
{ // green
PyObject* res = PyObject_CallFunction(pyfunc_g, "(d,d,d)", x, y, z);
if(res == NULL) return Eigen::Vector3d::Zero();
col.y() = PyFloat_AsDouble(res);
Py_DECREF(res);
}
{ // blue
PyObject* res = PyObject_CallFunction(pyfunc_b, "(d,d,d)", x, y, z);
if(res == NULL) return Eigen::Vector3d::Zero();
col.z() = PyFloat_AsDouble(res);
Py_DECREF(res);
}
return col;
};
// Marching cubes.
mc::marching_cubes_color(lower_, upper_, numx, numy, numz, pyfunc_to_cfunc_sdf, pyfunc_to_cfunc_color, isovalue, vertices, polygons);
// Copy the result to two Python ndarrays.
npy_intp size_vertices = vertices.size();
npy_intp size_polygons = polygons.size();
PyArrayObject* verticesarr = reinterpret_cast(PyArray_SimpleNew(1, &size_vertices, PyArray_DOUBLE));
PyArrayObject* polygonsarr = reinterpret_cast(PyArray_SimpleNew(1, &size_polygons, PyArray_ULONG));
std::vector::const_iterator it = vertices.begin();
for(int i=0; it!=vertices.end(); ++i, ++it)
*reinterpret_cast(PyArray_GETPTR1(verticesarr, i)) = *it;
std::vector::const_iterator it2 = polygons.begin();
for(int i=0; it2!=polygons.end(); ++i, ++it2)
*reinterpret_cast(PyArray_GETPTR1(polygonsarr, i)) = *it2;
PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr);
Py_XDECREF(verticesarr);
Py_XDECREF(polygonsarr);
return res;
}
PyObject* marching_cubes_color(PyArrayObject* arr_sdf, PyArrayObject* arr_color, double isovalue)
{
if(PyArray_NDIM(arr_sdf) != 3)
throw std::runtime_error("Only three-dimensional arrays are supported (SDF).");
if(PyArray_NDIM(arr_color) != 4)
throw std::runtime_error("Only four-dimensional arrays are supported (RGB).");
// Prepare data.
npy_intp* shape = PyArray_DIMS(arr_sdf);
npy_intp* shape_color = PyArray_DIMS(arr_color);
if(shape[0] != shape_color[0] || shape[1] != shape_color[1] || shape[2] != shape_color[2])
throw std::runtime_error("SDF and RGB volumes do not match in size.");
if(shape_color[3] != 3)
throw std::runtime_error("Only RGB colors are supported.");
std::array lower{0, 0, 0};
std::array upper{shape[0]-1, shape[1]-1, shape[2]-1};
long numx = upper[0] - lower[0] + 1;
long numy = upper[1] - lower[1] + 1;
long numz = upper[2] - lower[2] + 1;
std::vector vertices;
std::vector polygons;
auto pyarray_to_cfunc_sdf = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x, y, z};
return PyArray_SafeGet(arr_sdf, c);
};
auto pyarray_to_cfunc_color = [&](long x, long y, long z) -> Eigen::Vector3d {
Eigen::Vector3d color;
npy_intp c_r[4] = {x, y, z, 0};
npy_intp c_g[4] = {x, y, z, 1};
npy_intp c_b[4] = {x, y, z, 2};
color.x() = PyArray_SafeGet(arr_color, c_r);
color.y() = PyArray_SafeGet(arr_color, c_g);
color.z() = PyArray_SafeGet(arr_color, c_b);
return color;
};
// Marching cubes.
mc::marching_cubes_color(lower, upper, numx, numy, numz, pyarray_to_cfunc_sdf, pyarray_to_cfunc_color, isovalue, vertices, polygons);
// Copy the result to two Python ndarrays.
npy_intp size_vertices = vertices.size();
npy_intp size_polygons = polygons.size();
PyArrayObject* verticesarr = reinterpret_cast(PyArray_SimpleNew(1, &size_vertices, PyArray_DOUBLE));
PyArrayObject* polygonsarr = reinterpret_cast(PyArray_SimpleNew(1, &size_polygons, PyArray_ULONG));
std::vector::const_iterator it = vertices.begin();
for(int i=0; it!=vertices.end(); ++i, ++it)
*reinterpret_cast(PyArray_GETPTR1(verticesarr, i)) = *it;
std::vector::const_iterator it2 = polygons.begin();
for(int i=0; it2!=polygons.end(); ++i, ++it2)
*reinterpret_cast(PyArray_GETPTR1(polygonsarr, i)) = *it2;
PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr);
Py_XDECREF(verticesarr);
Py_XDECREF(polygonsarr);
return res;
}
PyObject* marching_cubes_super_sampling(PyArrayObject* arrX, PyArrayObject* arrY, PyArrayObject* arrZ, double isovalue)
{
if(PyArray_NDIM(arrX) != 3)
throw std::runtime_error("Only three-dimensional arrays are supported.");
if(PyArray_NDIM(arrY) != 3)
throw std::runtime_error("Only three-dimensional arrays are supported.");
if(PyArray_NDIM(arrZ) != 3)
throw std::runtime_error("Only three-dimensional arrays are supported.");
// Prepare data.
npy_intp* shapeX = PyArray_DIMS(arrX);
npy_intp* shapeY = PyArray_DIMS(arrY);
npy_intp* shapeZ = PyArray_DIMS(arrZ);
npy_intp shape[3] = {shapeY[0], shapeX[1], shapeX[2]};
npy_intp supersamples[3] = { (shapeX[0]-shape[0]) / (shape[0]-1), // samples along the edge (between two voxel nodes)
(shapeY[1]-shape[1]) / (shape[1]-1),
(shapeZ[2]-shape[2]) / (shape[2]-1)};
if(shapeX[2] != shapeY[2] || shapeX[1] != shapeZ[1] || shapeY[0] != shapeZ[0])
throw std::runtime_error("X,Y,Z supersampled sdf arrays need to be compatible.");
if( shapeX[0] != shape[0] + (shape[0]-1)*supersamples[0]
|| shapeY[1] != shape[1] + (shape[1]-1)*supersamples[1]
|| shapeZ[2] != shape[2] + (shape[2]-1)*supersamples[2])
throw std::runtime_error("X,Y,Z supersampled sdf arrays need to be compatible (must be dim + supersamples*(dim-1) !).");
std::array lower{0, 0, 0};
std::array upper{shape[0]-1, shape[1]-1, shape[2]-1};
long numx = upper[0] - lower[0] + 1;
long numy = upper[1] - lower[1] + 1;
long numz = upper[2] - lower[2] + 1;
std::vector vertices;
std::vector polygons;
auto pyarray_to_cfunc = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x * (supersamples[0]+1), y, z};
return PyArray_SafeGet(arrX, c);
};
auto pyarray_to_cfuncX = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x, y, z};
return PyArray_SafeGet(arrX, c);
};
auto pyarray_to_cfuncY = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x, y, z};
return PyArray_SafeGet(arrY, c);
};
auto pyarray_to_cfuncZ = [&](long x, long y, long z) -> double {
const npy_intp c[3] = {x, y, z};
return PyArray_SafeGet(arrZ, c);
};
// Marching cubes.
mc::marching_cubes_super_sampling(lower, upper, numx, numy, numz, supersamples[0], supersamples[1], supersamples[2], pyarray_to_cfunc, pyarray_to_cfuncX, pyarray_to_cfuncY, pyarray_to_cfuncZ, isovalue,
vertices, polygons);
// Copy the result to two Python ndarrays.
npy_intp size_vertices = vertices.size();
npy_intp size_polygons = polygons.size();
PyArrayObject* verticesarr = reinterpret_cast(PyArray_SimpleNew(1, &size_vertices, PyArray_DOUBLE));
PyArrayObject* polygonsarr = reinterpret_cast(PyArray_SimpleNew(1, &size_polygons, PyArray_ULONG));
std::vector::const_iterator it = vertices.begin();
for(int i=0; it!=vertices.end(); ++i, ++it)
*reinterpret_cast(PyArray_GETPTR1(verticesarr, i)) = *it;
std::vector::const_iterator it2 = polygons.begin();
for(int i=0; it2!=polygons.end(); ++i, ++it2)
*reinterpret_cast(PyArray_GETPTR1(polygonsarr, i)) = *it2;
PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr);
Py_XDECREF(verticesarr);
Py_XDECREF(polygonsarr);
return res;
}
================================================
FILE: external/PyMarchingCubes/marching_cubes/src/pywrapper.h
================================================
#ifndef _PYWRAPPER_H
#define _PYWRAPPER_H
#include
#include "pyarraymodule.h"
#include
PyObject* marching_cubes(PyArrayObject* arr, double isovalue);
PyObject* marching_cubes_func(PyObject* lower, PyObject* upper,
int numx, int numy, int numz, PyObject* f, double isovalue);
PyObject* marching_cubes_color(PyArrayObject* arr_sdf, PyArrayObject* arr_color, double isovalue);
PyObject* marching_cubes_color_func(PyObject* lower, PyObject* upper,
int numx, int numy, int numz, PyObject* f_sdf, PyObject* f_color_r, PyObject* f_color_g, PyObject* f_color_b, double isovalue);
PyObject* marching_cubes_super_sampling(PyArrayObject* arrX, PyArrayObject* arrY, PyArrayObject* arrZ, double isovalue);
#endif // _PYWRAPPER_H
================================================
FILE: external/PyMarchingCubes/requirements.txt
================================================
numpy>=1.11.3
scipy>=1.0.0
cython>=0.25.0
================================================
FILE: external/PyMarchingCubes/setup.py
================================================
# -*- encoding: utf-8 -*-
import sys, os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
from setuptools import setup
from setuptools.extension import Extension
class lazy_cythonize(list):
"""
Lazy evaluate extension definition, to allow correct requirements install.
"""
def __init__(self, callback):
super(lazy_cythonize, self).__init__()
self._list, self.callback = None, callback
def c_list(self):
if self._list is None:
self._list = self.callback()
return self._list
def __iter__(self):
for e in self.c_list():
yield e
def __getitem__(self, ii):
return self.c_list()[ii]
def __len__(self):
return len(self.c_list())
def extensions():
from Cython.Build import cythonize
import numpy
numpy_include_dir = numpy.get_include()
eigen_include_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'eigen3'))
marching_cubes_module = Extension(
"marching_cubes._mcubes",
[
"marching_cubes/src/_mcubes.pyx",
"marching_cubes/src/pywrapper.cpp",
"marching_cubes/src/marchingcubes.cpp"
],
language="c++",
extra_compile_args=['-std=c++11', '-Wall'],
include_dirs=[numpy_include_dir, eigen_include_dir],
depends=[
"marching_cubes/src/marchingcubes.h",
"marching_cubes/src/pyarray_symbol.h",
"marching_cubes/src/pyarraymodule.h",
"marching_cubes/src/pywrapper.h"
],
)
return cythonize([marching_cubes_module])
setup(
name="PyMarchingCubes",
version="0.0.2",
description="Marching cubes for Python",
author="Justus Thies (PyMCubes: Pablo Márquez Neila)",
url="https://github.com/JustusThies/PyMarchingCubes",
license="BSD 3-clause",
long_description="""
Marching cubes for Python
""",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: BSD License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: C++",
"Programming Language :: Python",
"Topic :: Multimedia :: Graphics :: 3D Modeling",
"Topic :: Scientific/Engineering :: Image Recognition",
],
packages=["marching_cubes"],
ext_modules=lazy_cythonize(extensions),
requires=['numpy', 'Cython', 'PyCollada'],
setup_requires=['numpy', 'Cython']
)
================================================
FILE: external/PyMarchingCubes/test_mcubes.py
================================================
import pytest
import numpy as np
from numpy.testing import assert_array_equal, assert_allclose
import marching_cubes as mcubes
def test_empty():
levelset = np.zeros((50, 50, 50))
vertices, triangles = mcubes.marching_cubes(levelset, 0.5)
assert len(vertices) == len(triangles) == 0
def test_sphere():
x, y, z = np.mgrid[:100, :100, :100]
u = (x - 50)**2 + (y - 50)**2 + (z - 50)**2 - 25**2
def func(x, y, z):
return (x - 50)**2 + (y - 50)**2 + (z - 50)**2 - 25**2
vertices1, triangles1 = mcubes.marching_cubes(u, 0.0)
vertices2, triangles2 = mcubes.marching_cubes_func(
(0, 0, 0),
(99, 99, 99),
100, 100, 100,
func, 0.0
)
assert_allclose(vertices1, vertices2)
assert_array_equal(triangles1, triangles2)
def test_no_duplicates():
def sphere(x, y, z):
return np.sqrt((x - 4)**2 + (y - 4)**2 + (z - 4)**2) - 4
vertices, _ = mcubes.marching_cubes_func((2, 2, 2), (9, 9, 9), 20, 20, 20, sphere, 0)
assert len(vertices) == len(np.unique(vertices, axis=0))
def test_export():
u = np.zeros((10, 10, 10))
u[2:-2, 2:-2, 2:-2] = 1.0
vertices, triangles = mcubes.marching_cubes(u, 0.5)
mcubes.export_obj(vertices, triangles, "output/test.obj")
mcubes.export_off(vertices, triangles, "output/test.off")
mcubes.export_mesh(vertices, triangles, "output/test.dae")
def test_invalid_input():
def func(x, y, z):
return x**2 + y**2 + z**2 - 1
mcubes.marching_cubes_func((-1.5, -1.5, -1.5), (1.5, 1.5, 1.5), 10, 10, 10, func, 0)
with pytest.raises(ValueError):
mcubes.marching_cubes_func((0, 0, 0), (0, 0, 0), 10, 10, 10, func, 0)
with pytest.raises(ValueError):
mcubes.marching_cubes_func((-1.5, -1.5, -1.5), (1.5, 1.5, 1.5), 1, 10, 10, func, 0)
with pytest.raises(Exception):
mcubes.marching_cubes_func((-1.5, -1.5), (1.5, 1.5, 1.5), 10, 10, 10, func, 0)
with pytest.raises(Exception):
mcubes.marching_cubes_func((-1.5, -1.5, -1.5), (1.5, 1.5), 10, 10, 10, func, 0)
================================================
FILE: external/PyMarchingCubes/test_smoothing.py
================================================
import pytest
import numpy as np
import marching_cubes as mcubes
def test_sphere():
# Create sphere with radius 25 centered at (50, 50, 50)
x, y, z = np.mgrid[:100, :100, :100]
levelset = np.sqrt((x - 50)**2 + (y - 50)**2 + (z - 50)**2) - 25
# vertices, triangles = mcubes.marching_cubes(levelset, 0)
# mcubes.export_obj(vertices, triangles, 'sphere1.obj')
binary_levelset = levelset > 0
smoothed_levelset = mcubes.smooth(
binary_levelset,
method='constrained',
max_iters=500,
rel_tol=1e-4
)
vertices, _ = mcubes.marching_cubes(smoothed_levelset, 0.0)
# Check all vertices have same distance to (50, 50, 50)
dist = np.sqrt(np.sum((vertices - [50, 50, 50])**2, axis=1))
assert dist.min() > 24.5 and dist.max() < 25.5
assert np.all(np.abs(smoothed_levelset - levelset) < 1)
assert np.all((smoothed_levelset > 0) == binary_levelset)
def test_gaussian_smoothing():
# Create sphere with radius 25 centered at (50, 50, 50)
x, y, z = np.mgrid[:100, :100, :100]
levelset = np.sqrt((x - 50)**2 + (y - 50)**2 + (z - 50)**2) - 25
binary_levelset = levelset > 0
smoothed_levelset = mcubes.smooth(
binary_levelset,
method='gaussian',
sigma=3
)
vertices, _ = mcubes.marching_cubes(smoothed_levelset, 0.0)
# Check all vertices have same distance to (50, 50, 50)
dist = np.sqrt(np.sum((vertices - [50, 50, 50])**2, axis=1))
assert dist.min() > 24 and dist.max() < 25
def test_wrong_ndim():
binary_levelset = np.random.uniform(size=(10)) < 0.5
with pytest.raises(ValueError):
mcubes.smooth(
binary_levelset,
method='constrained',
max_iters=500,
rel_tol=1e-4
)
binary_levelset = np.random.uniform(size=(10, 10, 10, 10)) < 0.5
with pytest.raises(ValueError):
mcubes.smooth(
binary_levelset,
method='constrained',
max_iters=500,
rel_tol=1e-4
)
def test_wrong_method():
with pytest.raises(ValueError):
mcubes.smooth(
np.zeros((10, 10), dtype=np.bool_),
method='wrong',
max_iters=500,
rel_tol=1e-4
)
def test_circle():
x, y = np.mgrid[:100, :100]
levelset = np.sqrt((x - 50)**2 + (y - 50)**2) - 25
binary_levelset = levelset > 0
smoothed_levelset = mcubes.smooth(
binary_levelset,
max_iters=500,
rel_tol=1e-4
)
assert np.all(np.abs(smoothed_levelset - levelset) < 1)
assert np.all((smoothed_levelset > 0) == binary_levelset)
# if __name__ == '__main__':
# # logging.basicConfig(level=logging.DEBUG)
# test_circle()
# test_sphere()
# test_large_sphere()
================================================
FILE: external/eigen3/Eigen/Cholesky
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CHOLESKY_MODULE_H
#define EIGEN_CHOLESKY_MODULE_H
#include "Core"
#include "Jacobi"
#include "src/Core/util/DisableStupidWarnings.h"
/** \defgroup Cholesky_Module Cholesky module
*
*
*
* This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices.
* Those decompositions are also accessible via the following methods:
* - MatrixBase::llt()
* - MatrixBase::ldlt()
* - SelfAdjointView::llt()
* - SelfAdjointView::ldlt()
*
* \code
* #include
* \endcode
*/
#include "src/Cholesky/LLT.h"
#include "src/Cholesky/LDLT.h"
#ifdef EIGEN_USE_LAPACKE
#ifdef EIGEN_USE_MKL
#include "mkl_lapacke.h"
#else
#include "src/misc/lapacke.h"
#endif
#include "src/Cholesky/LLT_LAPACKE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_CHOLESKY_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/CholmodSupport
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H
#define EIGEN_CHOLMODSUPPORT_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
extern "C" {
#include
}
/** \ingroup Support_modules
* \defgroup CholmodSupport_Module CholmodSupport module
*
* This module provides an interface to the Cholmod library which is part of the suitesparse package.
* It provides the two following main factorization classes:
* - class CholmodSupernodalLLT: a supernodal LLT Cholesky factorization.
* - class CholmodDecomposiiton: a general L(D)LT Cholesky factorization with automatic or explicit runtime selection of the underlying factorization method (supernodal or simplicial).
*
* For the sake of completeness, this module also propose the two following classes:
* - class CholmodSimplicialLLT
* - class CholmodSimplicialLDLT
* Note that these classes does not bring any particular advantage compared to the built-in
* SimplicialLLT and SimplicialLDLT factorization classes.
*
* \code
* #include
* \endcode
*
* In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be linked to the cholmod library and its dependencies.
* The dependencies depend on how cholmod has been compiled.
* For a cmake based project, you can use our FindCholmod.cmake module to help you in this task.
*
*/
#include "src/CholmodSupport/CholmodSupport.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_CHOLMODSUPPORT_MODULE_H
================================================
FILE: external/eigen3/Eigen/Core
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud
// Copyright (C) 2007-2011 Benoit Jacob
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CORE_H
#define EIGEN_CORE_H
// first thing Eigen does: stop the compiler from committing suicide
#include "src/Core/util/DisableStupidWarnings.h"
#if defined(__CUDACC__) && !defined(EIGEN_NO_CUDA)
#define EIGEN_CUDACC __CUDACC__
#endif
#if defined(__CUDA_ARCH__) && !defined(EIGEN_NO_CUDA)
#define EIGEN_CUDA_ARCH __CUDA_ARCH__
#endif
#if defined(__CUDACC_VER_MAJOR__) && (__CUDACC_VER_MAJOR__ >= 9)
#define EIGEN_CUDACC_VER ((__CUDACC_VER_MAJOR__ * 10000) + (__CUDACC_VER_MINOR__ * 100))
#elif defined(__CUDACC_VER__)
#define EIGEN_CUDACC_VER __CUDACC_VER__
#else
#define EIGEN_CUDACC_VER 0
#endif
// Handle NVCC/CUDA/SYCL
#if defined(__CUDACC__) || defined(__SYCL_DEVICE_ONLY__)
// Do not try asserts on CUDA and SYCL!
#ifndef EIGEN_NO_DEBUG
#define EIGEN_NO_DEBUG
#endif
#ifdef EIGEN_INTERNAL_DEBUGGING
#undef EIGEN_INTERNAL_DEBUGGING
#endif
#ifdef EIGEN_EXCEPTIONS
#undef EIGEN_EXCEPTIONS
#endif
// All functions callable from CUDA code must be qualified with __device__
#ifdef __CUDACC__
// Do not try to vectorize on CUDA and SYCL!
#ifndef EIGEN_DONT_VECTORIZE
#define EIGEN_DONT_VECTORIZE
#endif
#define EIGEN_DEVICE_FUNC __host__ __device__
// We need cuda_runtime.h to ensure that that EIGEN_USING_STD_MATH macro
// works properly on the device side
#include
#else
#define EIGEN_DEVICE_FUNC
#endif
#else
#define EIGEN_DEVICE_FUNC
#endif
// When compiling CUDA device code with NVCC, pull in math functions from the
// global namespace. In host mode, and when device doee with clang, use the
// std versions.
#if defined(__CUDA_ARCH__) && defined(__NVCC__)
#define EIGEN_USING_STD_MATH(FUNC) using ::FUNC;
#else
#define EIGEN_USING_STD_MATH(FUNC) using std::FUNC;
#endif
#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_USE_SYCL)
#define EIGEN_EXCEPTIONS
#endif
#ifdef EIGEN_EXCEPTIONS
#include
#endif
// then include this file where all our macros are defined. It's really important to do it first because
// it's where we do all the alignment settings (platform detection and honoring the user's will if he
// defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization.
#include "src/Core/util/Macros.h"
// Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3)
// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details.
#if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6)
#pragma GCC optimize ("-fno-ipa-cp-clone")
#endif
#include
// this include file manages BLAS and MKL related macros
// and inclusion of their respective header files
#include "src/Core/util/MKL_support.h"
// if alignment is disabled, then disable vectorization. Note: EIGEN_MAX_ALIGN_BYTES is the proper check, it takes into
// account both the user's will (EIGEN_MAX_ALIGN_BYTES,EIGEN_DONT_ALIGN) and our own platform checks
#if EIGEN_MAX_ALIGN_BYTES==0
#ifndef EIGEN_DONT_VECTORIZE
#define EIGEN_DONT_VECTORIZE
#endif
#endif
#if EIGEN_COMP_MSVC
#include // for _aligned_malloc -- need it regardless of whether vectorization is enabled
#if (EIGEN_COMP_MSVC >= 1500) // 2008 or later
// Remember that usage of defined() in a #define is undefined by the standard.
// a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP.
#if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || EIGEN_ARCH_x86_64
#define EIGEN_SSE2_ON_MSVC_2008_OR_LATER
#endif
#endif
#else
// Remember that usage of defined() in a #define is undefined by the standard
#if (defined __SSE2__) && ( (!EIGEN_COMP_GNUC) || EIGEN_COMP_ICC || EIGEN_GNUC_AT_LEAST(4,2) )
#define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC
#endif
#endif
#ifndef EIGEN_DONT_VECTORIZE
#if defined (EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER)
// Defines symbols for compile-time detection of which instructions are
// used.
// EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_SSE
#define EIGEN_VECTORIZE_SSE2
// Detect sse3/ssse3/sse4:
// gcc and icc defines __SSE3__, ...
// there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you
// want to force the use of those instructions with msvc.
#ifdef __SSE3__
#define EIGEN_VECTORIZE_SSE3
#endif
#ifdef __SSSE3__
#define EIGEN_VECTORIZE_SSSE3
#endif
#ifdef __SSE4_1__
#define EIGEN_VECTORIZE_SSE4_1
#endif
#ifdef __SSE4_2__
#define EIGEN_VECTORIZE_SSE4_2
#endif
#ifdef __AVX__
#define EIGEN_VECTORIZE_AVX
#define EIGEN_VECTORIZE_SSE3
#define EIGEN_VECTORIZE_SSSE3
#define EIGEN_VECTORIZE_SSE4_1
#define EIGEN_VECTORIZE_SSE4_2
#endif
#ifdef __AVX2__
#define EIGEN_VECTORIZE_AVX2
#endif
#ifdef __FMA__
#define EIGEN_VECTORIZE_FMA
#endif
#if defined(__AVX512F__) && defined(EIGEN_ENABLE_AVX512)
#define EIGEN_VECTORIZE_AVX512
#define EIGEN_VECTORIZE_AVX2
#define EIGEN_VECTORIZE_AVX
#define EIGEN_VECTORIZE_FMA
#ifdef __AVX512DQ__
#define EIGEN_VECTORIZE_AVX512DQ
#endif
#ifdef __AVX512ER__
#define EIGEN_VECTORIZE_AVX512ER
#endif
#endif
// include files
// This extern "C" works around a MINGW-w64 compilation issue
// https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354
// In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do).
// However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations
// with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know;
// so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too.
// notice that since these are C headers, the extern "C" is theoretically needed anyways.
extern "C" {
// In theory we should only include immintrin.h and not the other *mmintrin.h header files directly.
// Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus:
#if EIGEN_COMP_ICC >= 1110
#include
#else
#include
#include
#include
#ifdef EIGEN_VECTORIZE_SSE3
#include
#endif
#ifdef EIGEN_VECTORIZE_SSSE3
#include
#endif
#ifdef EIGEN_VECTORIZE_SSE4_1
#include
#endif
#ifdef EIGEN_VECTORIZE_SSE4_2
#include
#endif
#if defined(EIGEN_VECTORIZE_AVX) || defined(EIGEN_VECTORIZE_AVX512)
#include
#endif
#endif
} // end extern "C"
#elif defined __VSX__
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_VSX
#include
// We need to #undef all these ugly tokens defined in
// => use __vector instead of vector
#undef bool
#undef vector
#undef pixel
#elif defined __ALTIVEC__
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_ALTIVEC
#include
// We need to #undef all these ugly tokens defined in
// => use __vector instead of vector
#undef bool
#undef vector
#undef pixel
#elif (defined __ARM_NEON) || (defined __ARM_NEON__)
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_NEON
#include
#elif (defined __s390x__ && defined __VEC__)
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_ZVECTOR
#include
#endif
#endif
#if defined(__F16C__) && !defined(EIGEN_COMP_CLANG)
// We can use the optimized fp16 to float and float to fp16 conversion routines
#define EIGEN_HAS_FP16_C
#endif
#if defined __CUDACC__
#define EIGEN_VECTORIZE_CUDA
#include
#if EIGEN_CUDACC_VER >= 70500
#define EIGEN_HAS_CUDA_FP16
#endif
#endif
#if defined EIGEN_HAS_CUDA_FP16
#include
#include
#endif
#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE)
#define EIGEN_HAS_OPENMP
#endif
#ifdef EIGEN_HAS_OPENMP
#include
#endif
// MSVC for windows mobile does not have the errno.h file
#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM
#define EIGEN_HAS_ERRNO
#endif
#ifdef EIGEN_HAS_ERRNO
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include // for CHAR_BIT
// for min/max:
#include
// for std::is_nothrow_move_assignable
#ifdef EIGEN_INCLUDE_TYPE_TRAITS
#include
#endif
// for outputting debug info
#ifdef EIGEN_DEBUG_ASSIGN
#include
#endif
// required for __cpuid, needs to be included after cmath
#if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE
#include
#endif
/** \brief Namespace containing all symbols from the %Eigen library. */
namespace Eigen {
inline static const char *SimdInstructionSetsInUse(void) {
#if defined(EIGEN_VECTORIZE_AVX512)
return "AVX512, FMA, AVX2, AVX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2";
#elif defined(EIGEN_VECTORIZE_AVX)
return "AVX SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2";
#elif defined(EIGEN_VECTORIZE_SSE4_2)
return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2";
#elif defined(EIGEN_VECTORIZE_SSE4_1)
return "SSE, SSE2, SSE3, SSSE3, SSE4.1";
#elif defined(EIGEN_VECTORIZE_SSSE3)
return "SSE, SSE2, SSE3, SSSE3";
#elif defined(EIGEN_VECTORIZE_SSE3)
return "SSE, SSE2, SSE3";
#elif defined(EIGEN_VECTORIZE_SSE2)
return "SSE, SSE2";
#elif defined(EIGEN_VECTORIZE_ALTIVEC)
return "AltiVec";
#elif defined(EIGEN_VECTORIZE_VSX)
return "VSX";
#elif defined(EIGEN_VECTORIZE_NEON)
return "ARM NEON";
#elif defined(EIGEN_VECTORIZE_ZVECTOR)
return "S390X ZVECTOR";
#else
return "None";
#endif
}
} // end namespace Eigen
#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT
// This will generate an error message:
#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information
#endif
namespace Eigen {
// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to
// ensure QNX/QCC support
using std::size_t;
// gcc 4.6.0 wants std:: for ptrdiff_t
using std::ptrdiff_t;
}
/** \defgroup Core_Module Core module
* This is the main module of Eigen providing dense matrix and vector support
* (both fixed and dynamic size) with all the features corresponding to a BLAS library
* and much more...
*
* \code
* #include
* \endcode
*/
#include "src/Core/util/Constants.h"
#include "src/Core/util/Meta.h"
#include "src/Core/util/ForwardDeclarations.h"
#include "src/Core/util/StaticAssert.h"
#include "src/Core/util/XprHelper.h"
#include "src/Core/util/Memory.h"
#include "src/Core/NumTraits.h"
#include "src/Core/MathFunctions.h"
#include "src/Core/GenericPacketMath.h"
#include "src/Core/MathFunctionsImpl.h"
#include "src/Core/arch/Default/ConjHelper.h"
#if defined EIGEN_VECTORIZE_AVX512
#include "src/Core/arch/SSE/PacketMath.h"
#include "src/Core/arch/AVX/PacketMath.h"
#include "src/Core/arch/AVX512/PacketMath.h"
#include "src/Core/arch/AVX512/MathFunctions.h"
#elif defined EIGEN_VECTORIZE_AVX
// Use AVX for floats and doubles, SSE for integers
#include "src/Core/arch/SSE/PacketMath.h"
#include "src/Core/arch/SSE/Complex.h"
#include "src/Core/arch/SSE/MathFunctions.h"
#include "src/Core/arch/AVX/PacketMath.h"
#include "src/Core/arch/AVX/MathFunctions.h"
#include "src/Core/arch/AVX/Complex.h"
#include "src/Core/arch/AVX/TypeCasting.h"
#include "src/Core/arch/SSE/TypeCasting.h"
#elif defined EIGEN_VECTORIZE_SSE
#include "src/Core/arch/SSE/PacketMath.h"
#include "src/Core/arch/SSE/MathFunctions.h"
#include "src/Core/arch/SSE/Complex.h"
#include "src/Core/arch/SSE/TypeCasting.h"
#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX)
#include "src/Core/arch/AltiVec/PacketMath.h"
#include "src/Core/arch/AltiVec/MathFunctions.h"
#include "src/Core/arch/AltiVec/Complex.h"
#elif defined EIGEN_VECTORIZE_NEON
#include "src/Core/arch/NEON/PacketMath.h"
#include "src/Core/arch/NEON/MathFunctions.h"
#include "src/Core/arch/NEON/Complex.h"
#elif defined EIGEN_VECTORIZE_ZVECTOR
#include "src/Core/arch/ZVector/PacketMath.h"
#include "src/Core/arch/ZVector/MathFunctions.h"
#include "src/Core/arch/ZVector/Complex.h"
#endif
// Half float support
#include "src/Core/arch/CUDA/Half.h"
#include "src/Core/arch/CUDA/PacketMathHalf.h"
#include "src/Core/arch/CUDA/TypeCasting.h"
#if defined EIGEN_VECTORIZE_CUDA
#include "src/Core/arch/CUDA/PacketMath.h"
#include "src/Core/arch/CUDA/MathFunctions.h"
#endif
#include "src/Core/arch/Default/Settings.h"
#include "src/Core/functors/TernaryFunctors.h"
#include "src/Core/functors/BinaryFunctors.h"
#include "src/Core/functors/UnaryFunctors.h"
#include "src/Core/functors/NullaryFunctors.h"
#include "src/Core/functors/StlFunctors.h"
#include "src/Core/functors/AssignmentFunctors.h"
// Specialized functors to enable the processing of complex numbers
// on CUDA devices
#include "src/Core/arch/CUDA/Complex.h"
#include "src/Core/IO.h"
#include "src/Core/DenseCoeffsBase.h"
#include "src/Core/DenseBase.h"
#include "src/Core/MatrixBase.h"
#include "src/Core/EigenBase.h"
#include "src/Core/Product.h"
#include "src/Core/CoreEvaluators.h"
#include "src/Core/AssignEvaluator.h"
#ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874
// at least confirmed with Doxygen 1.5.5 and 1.5.6
#include "src/Core/Assign.h"
#endif
#include "src/Core/ArrayBase.h"
#include "src/Core/util/BlasUtil.h"
#include "src/Core/DenseStorage.h"
#include "src/Core/NestByValue.h"
// #include "src/Core/ForceAlignedAccess.h"
#include "src/Core/ReturnByValue.h"
#include "src/Core/NoAlias.h"
#include "src/Core/PlainObjectBase.h"
#include "src/Core/Matrix.h"
#include "src/Core/Array.h"
#include "src/Core/CwiseTernaryOp.h"
#include "src/Core/CwiseBinaryOp.h"
#include "src/Core/CwiseUnaryOp.h"
#include "src/Core/CwiseNullaryOp.h"
#include "src/Core/CwiseUnaryView.h"
#include "src/Core/SelfCwiseBinaryOp.h"
#include "src/Core/Dot.h"
#include "src/Core/StableNorm.h"
#include "src/Core/Stride.h"
#include "src/Core/MapBase.h"
#include "src/Core/Map.h"
#include "src/Core/Ref.h"
#include "src/Core/Block.h"
#include "src/Core/VectorBlock.h"
#include "src/Core/Transpose.h"
#include "src/Core/DiagonalMatrix.h"
#include "src/Core/Diagonal.h"
#include "src/Core/DiagonalProduct.h"
#include "src/Core/Redux.h"
#include "src/Core/Visitor.h"
#include "src/Core/Fuzzy.h"
#include "src/Core/Swap.h"
#include "src/Core/CommaInitializer.h"
#include "src/Core/GeneralProduct.h"
#include "src/Core/Solve.h"
#include "src/Core/Inverse.h"
#include "src/Core/SolverBase.h"
#include "src/Core/PermutationMatrix.h"
#include "src/Core/Transpositions.h"
#include "src/Core/TriangularMatrix.h"
#include "src/Core/SelfAdjointView.h"
#include "src/Core/products/GeneralBlockPanelKernel.h"
#include "src/Core/products/Parallelizer.h"
#include "src/Core/ProductEvaluators.h"
#include "src/Core/products/GeneralMatrixVector.h"
#include "src/Core/products/GeneralMatrixMatrix.h"
#include "src/Core/SolveTriangular.h"
#include "src/Core/products/GeneralMatrixMatrixTriangular.h"
#include "src/Core/products/SelfadjointMatrixVector.h"
#include "src/Core/products/SelfadjointMatrixMatrix.h"
#include "src/Core/products/SelfadjointProduct.h"
#include "src/Core/products/SelfadjointRank2Update.h"
#include "src/Core/products/TriangularMatrixVector.h"
#include "src/Core/products/TriangularMatrixMatrix.h"
#include "src/Core/products/TriangularSolverMatrix.h"
#include "src/Core/products/TriangularSolverVector.h"
#include "src/Core/BandMatrix.h"
#include "src/Core/CoreIterators.h"
#include "src/Core/ConditionEstimator.h"
#include "src/Core/BooleanRedux.h"
#include "src/Core/Select.h"
#include "src/Core/VectorwiseOp.h"
#include "src/Core/Random.h"
#include "src/Core/Replicate.h"
#include "src/Core/Reverse.h"
#include "src/Core/ArrayWrapper.h"
#ifdef EIGEN_USE_BLAS
#include "src/Core/products/GeneralMatrixMatrix_BLAS.h"
#include "src/Core/products/GeneralMatrixVector_BLAS.h"
#include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h"
#include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h"
#include "src/Core/products/SelfadjointMatrixVector_BLAS.h"
#include "src/Core/products/TriangularMatrixMatrix_BLAS.h"
#include "src/Core/products/TriangularMatrixVector_BLAS.h"
#include "src/Core/products/TriangularSolverMatrix_BLAS.h"
#endif // EIGEN_USE_BLAS
#ifdef EIGEN_USE_MKL_VML
#include "src/Core/Assign_MKL.h"
#endif
#include "src/Core/GlobalFunctions.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_CORE_H
================================================
FILE: external/eigen3/Eigen/Dense
================================================
#include "Core"
#include "LU"
#include "Cholesky"
#include "QR"
#include "SVD"
#include "Geometry"
#include "Eigenvalues"
================================================
FILE: external/eigen3/Eigen/Eigen
================================================
#include "Dense"
#include "Sparse"
================================================
FILE: external/eigen3/Eigen/Eigenvalues
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_EIGENVALUES_MODULE_H
#define EIGEN_EIGENVALUES_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
#include "Cholesky"
#include "Jacobi"
#include "Householder"
#include "LU"
#include "Geometry"
/** \defgroup Eigenvalues_Module Eigenvalues module
*
*
*
* This module mainly provides various eigenvalue solvers.
* This module also provides some MatrixBase methods, including:
* - MatrixBase::eigenvalues(),
* - MatrixBase::operatorNorm()
*
* \code
* #include
* \endcode
*/
#include "src/misc/RealSvd2x2.h"
#include "src/Eigenvalues/Tridiagonalization.h"
#include "src/Eigenvalues/RealSchur.h"
#include "src/Eigenvalues/EigenSolver.h"
#include "src/Eigenvalues/SelfAdjointEigenSolver.h"
#include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h"
#include "src/Eigenvalues/HessenbergDecomposition.h"
#include "src/Eigenvalues/ComplexSchur.h"
#include "src/Eigenvalues/ComplexEigenSolver.h"
#include "src/Eigenvalues/RealQZ.h"
#include "src/Eigenvalues/GeneralizedEigenSolver.h"
#include "src/Eigenvalues/MatrixBaseEigenvalues.h"
#ifdef EIGEN_USE_LAPACKE
#ifdef EIGEN_USE_MKL
#include "mkl_lapacke.h"
#else
#include "src/misc/lapacke.h"
#endif
#include "src/Eigenvalues/RealSchur_LAPACKE.h"
#include "src/Eigenvalues/ComplexSchur_LAPACKE.h"
#include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_EIGENVALUES_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/Geometry
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_GEOMETRY_MODULE_H
#define EIGEN_GEOMETRY_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
#include "SVD"
#include "LU"
#include
/** \defgroup Geometry_Module Geometry module
*
* This module provides support for:
* - fixed-size homogeneous transformations
* - translation, scaling, 2D and 3D rotations
* - \link Quaternion quaternions \endlink
* - cross products (\ref MatrixBase::cross, \ref MatrixBase::cross3)
* - orthognal vector generation (\ref MatrixBase::unitOrthogonal)
* - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink
* - \link AlignedBox axis aligned bounding boxes \endlink
* - \link umeyama least-square transformation fitting \endlink
*
* \code
* #include
* \endcode
*/
#include "src/Geometry/OrthoMethods.h"
#include "src/Geometry/EulerAngles.h"
#include "src/Geometry/Homogeneous.h"
#include "src/Geometry/RotationBase.h"
#include "src/Geometry/Rotation2D.h"
#include "src/Geometry/Quaternion.h"
#include "src/Geometry/AngleAxis.h"
#include "src/Geometry/Transform.h"
#include "src/Geometry/Translation.h"
#include "src/Geometry/Scaling.h"
#include "src/Geometry/Hyperplane.h"
#include "src/Geometry/ParametrizedLine.h"
#include "src/Geometry/AlignedBox.h"
#include "src/Geometry/Umeyama.h"
// Use the SSE optimized version whenever possible. At the moment the
// SSE version doesn't compile when AVX is enabled
#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX
#include "src/Geometry/arch/Geometry_SSE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_GEOMETRY_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/Householder
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_HOUSEHOLDER_MODULE_H
#define EIGEN_HOUSEHOLDER_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
/** \defgroup Householder_Module Householder module
* This module provides Householder transformations.
*
* \code
* #include
* \endcode
*/
#include "src/Householder/Householder.h"
#include "src/Householder/HouseholderSequence.h"
#include "src/Householder/BlockHouseholder.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_HOUSEHOLDER_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/IterativeLinearSolvers
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
#include "SparseCore"
#include "OrderingMethods"
#include "src/Core/util/DisableStupidWarnings.h"
/**
* \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module
*
* This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse.
* Those solvers are accessible via the following classes:
* - ConjugateGradient for selfadjoint (hermitian) matrices,
* - LeastSquaresConjugateGradient for rectangular least-square problems,
* - BiCGSTAB for general square matrices.
*
* These iterative solvers are associated with some preconditioners:
* - IdentityPreconditioner - not really useful
* - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices.
* - IncompleteLUT - incomplete LU factorization with dual thresholding
*
* Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport.
*
\code
#include
\endcode
*/
#include "src/IterativeLinearSolvers/SolveWithGuess.h"
#include "src/IterativeLinearSolvers/IterativeSolverBase.h"
#include "src/IterativeLinearSolvers/BasicPreconditioners.h"
#include "src/IterativeLinearSolvers/ConjugateGradient.h"
#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h"
#include "src/IterativeLinearSolvers/BiCGSTAB.h"
#include "src/IterativeLinearSolvers/IncompleteLUT.h"
#include "src/IterativeLinearSolvers/IncompleteCholesky.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
================================================
FILE: external/eigen3/Eigen/Jacobi
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_JACOBI_MODULE_H
#define EIGEN_JACOBI_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
/** \defgroup Jacobi_Module Jacobi module
* This module provides Jacobi and Givens rotations.
*
* \code
* #include
* \endcode
*
* In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation:
* - MatrixBase::applyOnTheLeft()
* - MatrixBase::applyOnTheRight().
*/
#include "src/Jacobi/Jacobi.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_JACOBI_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/LU
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_LU_MODULE_H
#define EIGEN_LU_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
/** \defgroup LU_Module LU module
* This module includes %LU decomposition and related notions such as matrix inversion and determinant.
* This module defines the following MatrixBase methods:
* - MatrixBase::inverse()
* - MatrixBase::determinant()
*
* \code
* #include
* \endcode
*/
#include "src/misc/Kernel.h"
#include "src/misc/Image.h"
#include "src/LU/FullPivLU.h"
#include "src/LU/PartialPivLU.h"
#ifdef EIGEN_USE_LAPACKE
#ifdef EIGEN_USE_MKL
#include "mkl_lapacke.h"
#else
#include "src/misc/lapacke.h"
#endif
#include "src/LU/PartialPivLU_LAPACKE.h"
#endif
#include "src/LU/Determinant.h"
#include "src/LU/InverseImpl.h"
// Use the SSE optimized version whenever possible. At the moment the
// SSE version doesn't compile when AVX is enabled
#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX
#include "src/LU/arch/Inverse_SSE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_LU_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/MetisSupport
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_METISSUPPORT_MODULE_H
#define EIGEN_METISSUPPORT_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
extern "C" {
#include
}
/** \ingroup Support_modules
* \defgroup MetisSupport_Module MetisSupport module
*
* \code
* #include
* \endcode
* This module defines an interface to the METIS reordering package (http://glaros.dtc.umn.edu/gkhome/views/metis).
* It can be used just as any other built-in method as explained in \link OrderingMethods_Module here. \endlink
*/
#include "src/MetisSupport/MetisSupport.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_METISSUPPORT_MODULE_H
================================================
FILE: external/eigen3/Eigen/OrderingMethods
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_ORDERINGMETHODS_MODULE_H
#define EIGEN_ORDERINGMETHODS_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
/**
* \defgroup OrderingMethods_Module OrderingMethods module
*
* This module is currently for internal use only
*
* It defines various built-in and external ordering methods for sparse matrices.
* They are typically used to reduce the number of elements during
* the sparse matrix decomposition (LLT, LU, QR).
* Precisely, in a preprocessing step, a permutation matrix P is computed using
* those ordering methods and applied to the columns of the matrix.
* Using for instance the sparse Cholesky decomposition, it is expected that
* the nonzeros elements in LLT(A*P) will be much smaller than that in LLT(A).
*
*
* Usage :
* \code
* #include
* \endcode
*
* A simple usage is as a template parameter in the sparse decomposition classes :
*
* \code
* SparseLU > solver;
* \endcode
*
* \code
* SparseQR > solver;
* \endcode
*
* It is possible as well to call directly a particular ordering method for your own purpose,
* \code
* AMDOrdering ordering;
* PermutationMatrix perm;
* SparseMatrix A;
* //Fill the matrix ...
*
* ordering(A, perm); // Call AMD
* \endcode
*
* \note Some of these methods (like AMD or METIS), need the sparsity pattern
* of the input matrix to be symmetric. When the matrix is structurally unsymmetric,
* Eigen computes internally the pattern of \f$A^T*A\f$ before calling the method.
* If your matrix is already symmetric (at leat in structure), you can avoid that
* by calling the method with a SelfAdjointView type.
*
* \code
* // Call the ordering on the pattern of the lower triangular matrix A
* ordering(A.selfadjointView(), perm);
* \endcode
*/
#ifndef EIGEN_MPL2_ONLY
#include "src/OrderingMethods/Amd.h"
#endif
#include "src/OrderingMethods/Ordering.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_ORDERINGMETHODS_MODULE_H
================================================
FILE: external/eigen3/Eigen/PaStiXSupport
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_PASTIXSUPPORT_MODULE_H
#define EIGEN_PASTIXSUPPORT_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
extern "C" {
#include
#include
}
#ifdef complex
#undef complex
#endif
/** \ingroup Support_modules
* \defgroup PaStiXSupport_Module PaStiXSupport module
*
* This module provides an interface to the PaSTiX library.
* PaSTiX is a general \b supernodal, \b parallel and \b opensource sparse solver.
* It provides the two following main factorization classes:
* - class PastixLLT : a supernodal, parallel LLt Cholesky factorization.
* - class PastixLDLT: a supernodal, parallel LDLt Cholesky factorization.
* - class PastixLU : a supernodal, parallel LU factorization (optimized for a symmetric pattern).
*
* \code
* #include
* \endcode
*
* In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be linked to the PaSTiX library and its dependencies.
* The dependencies depend on how PaSTiX has been compiled.
* For a cmake based project, you can use our FindPaSTiX.cmake module to help you in this task.
*
*/
#include "src/PaStiXSupport/PaStiXSupport.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_PASTIXSUPPORT_MODULE_H
================================================
FILE: external/eigen3/Eigen/PardisoSupport
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_PARDISOSUPPORT_MODULE_H
#define EIGEN_PARDISOSUPPORT_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
#include
/** \ingroup Support_modules
* \defgroup PardisoSupport_Module PardisoSupport module
*
* This module brings support for the Intel(R) MKL PARDISO direct sparse solvers.
*
* \code
* #include
* \endcode
*
* In order to use this module, the MKL headers must be accessible from the include paths, and your binary must be linked to the MKL library and its dependencies.
* See this \ref TopicUsingIntelMKL "page" for more information on MKL-Eigen integration.
*
*/
#include "src/PardisoSupport/PardisoSupport.h"
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_PARDISOSUPPORT_MODULE_H
================================================
FILE: external/eigen3/Eigen/QR
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_QR_MODULE_H
#define EIGEN_QR_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
#include "Cholesky"
#include "Jacobi"
#include "Householder"
/** \defgroup QR_Module QR module
*
*
*
* This module provides various QR decompositions
* This module also provides some MatrixBase methods, including:
* - MatrixBase::householderQr()
* - MatrixBase::colPivHouseholderQr()
* - MatrixBase::fullPivHouseholderQr()
*
* \code
* #include
* \endcode
*/
#include "src/QR/HouseholderQR.h"
#include "src/QR/FullPivHouseholderQR.h"
#include "src/QR/ColPivHouseholderQR.h"
#include "src/QR/CompleteOrthogonalDecomposition.h"
#ifdef EIGEN_USE_LAPACKE
#ifdef EIGEN_USE_MKL
#include "mkl_lapacke.h"
#else
#include "src/misc/lapacke.h"
#endif
#include "src/QR/HouseholderQR_LAPACKE.h"
#include "src/QR/ColPivHouseholderQR_LAPACKE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_QR_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/QtAlignedMalloc
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_QTMALLOC_MODULE_H
#define EIGEN_QTMALLOC_MODULE_H
#include "Core"
#if (!EIGEN_MALLOC_ALREADY_ALIGNED)
#include "src/Core/util/DisableStupidWarnings.h"
void *qMalloc(std::size_t size)
{
return Eigen::internal::aligned_malloc(size);
}
void qFree(void *ptr)
{
Eigen::internal::aligned_free(ptr);
}
void *qRealloc(void *ptr, std::size_t size)
{
void* newPtr = Eigen::internal::aligned_malloc(size);
std::memcpy(newPtr, ptr, size);
Eigen::internal::aligned_free(ptr);
return newPtr;
}
#include "src/Core/util/ReenableStupidWarnings.h"
#endif
#endif // EIGEN_QTMALLOC_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/SPQRSupport
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPQRSUPPORT_MODULE_H
#define EIGEN_SPQRSUPPORT_MODULE_H
#include "SparseCore"
#include "src/Core/util/DisableStupidWarnings.h"
#include "SuiteSparseQR.hpp"
/** \ingroup Support_modules
* \defgroup SPQRSupport_Module SuiteSparseQR module
*
* This module provides an interface to the SPQR library, which is part of the suitesparse package.
*
* \code
* #include
* \endcode
*
* In order to use this module, the SPQR headers must be accessible from the include paths, and your binary must be linked to the SPQR library and its dependencies (Cholmod, AMD, COLAMD,...).
* For a cmake based project, you can use our FindSPQR.cmake and FindCholmod.Cmake modules
*
*/
#include "src/CholmodSupport/CholmodSupport.h"
#include "src/SPQRSupport/SuiteSparseQRSupport.h"
#endif
================================================
FILE: external/eigen3/Eigen/SVD
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SVD_MODULE_H
#define EIGEN_SVD_MODULE_H
#include "QR"
#include "Householder"
#include "Jacobi"
#include "src/Core/util/DisableStupidWarnings.h"
/** \defgroup SVD_Module SVD module
*
*
*
* This module provides SVD decomposition for matrices (both real and complex).
* Two decomposition algorithms are provided:
* - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones.
* - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems.
* These decompositions are accessible via the respective classes and following MatrixBase methods:
* - MatrixBase::jacobiSvd()
* - MatrixBase::bdcSvd()
*
* \code
* #include
* \endcode
*/
#include "src/misc/RealSvd2x2.h"
#include "src/SVD/UpperBidiagonalization.h"
#include "src/SVD/SVDBase.h"
#include "src/SVD/JacobiSVD.h"
#include "src/SVD/BDCSVD.h"
#if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT)
#ifdef EIGEN_USE_MKL
#include "mkl_lapacke.h"
#else
#include "src/misc/lapacke.h"
#endif
#include "src/SVD/JacobiSVD_LAPACKE.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_SVD_MODULE_H
/* vim: set filetype=cpp et sw=2 ts=2 ai: */
================================================
FILE: external/eigen3/Eigen/Sparse
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSE_MODULE_H
#define EIGEN_SPARSE_MODULE_H
/** \defgroup Sparse_Module Sparse meta-module
*
* Meta-module including all related modules:
* - \ref SparseCore_Module
* - \ref OrderingMethods_Module
* - \ref SparseCholesky_Module
* - \ref SparseLU_Module
* - \ref SparseQR_Module
* - \ref IterativeLinearSolvers_Module
*
\code
#include
\endcode
*/
#include "SparseCore"
#include "OrderingMethods"
#ifndef EIGEN_MPL2_ONLY
#include "SparseCholesky"
#endif
#include "SparseLU"
#include "SparseQR"
#include "IterativeLinearSolvers"
#endif // EIGEN_SPARSE_MODULE_H
================================================
FILE: external/eigen3/Eigen/SparseCholesky
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2013 Gael Guennebaud
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSECHOLESKY_MODULE_H
#define EIGEN_SPARSECHOLESKY_MODULE_H
#include "SparseCore"
#include "OrderingMethods"
#include "src/Core/util/DisableStupidWarnings.h"
/**
* \defgroup SparseCholesky_Module SparseCholesky module
*
* This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices.
* Those decompositions are accessible via the following classes:
* - SimplicialLLt,
* - SimplicialLDLt
*
* Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module.
*
* \code
* #include
* \endcode
*/
#ifdef EIGEN_MPL2_ONLY
#error The SparseCholesky module has nothing to offer in MPL2 only mode
#endif
#include "src/SparseCholesky/SimplicialCholesky.h"
#ifndef EIGEN_MPL2_ONLY
#include "src/SparseCholesky/SimplicialCholesky_impl.h"
#endif
#include "src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_SPARSECHOLESKY_MODULE_H
================================================
FILE: external/eigen3/Eigen/SparseCore
================================================
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSECORE_MODULE_H
#define EIGEN_SPARSECORE_MODULE_H
#include "Core"
#include "src/Core/util/DisableStupidWarnings.h"
#include
#include