easy-iso

Iso-surface extraction from volume data
git clone https://git.0xfab.ch/easy-iso.git
Log | Files | Refs | Submodules | README | LICENSE

commit a939059e03a9484df2330f1123a677b6eca010d2
parent 0a03d44d05e123755cf7de1a7a87897aa3db7d89
Author: Fabian Wermelinger <fabianw@mavt.ethz.ch>
Date:   Mon, 28 Nov 2016 15:25:12 +0100

added working version (non MPI)

Diffstat:
Ainclude/ArgumentParser.h | 399+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Matrix3D.h | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/common.h | 30++++++++++++++++++++++++++++++
Asrc/Interpolator.h | 262+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/IsoExtractor.h | 681+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/easy_iso.cpp | 31+++++++++++++++++++++++++++++++
Asrc/interpolation/M2.h | 28++++++++++++++++++++++++++++
Asrc/interpolation/M5.h | 33+++++++++++++++++++++++++++++++++
Asrc/interpolation/Mprime4.h | 30++++++++++++++++++++++++++++++
Asrc/interpolation/kernels.h | 13+++++++++++++
10 files changed, 1677 insertions(+), 0 deletions(-)

diff --git a/include/ArgumentParser.h b/include/ArgumentParser.h @@ -0,0 +1,399 @@ +/* + * ArgumentParser.h + * Cubism + * + * This argument parser assumes that all arguments are optional ie, each of the argument names is preceded by a '-' + * all arguments are however NOT optional to avoid a mess with default values and returned values when not found! + * + * More converter could be required: + * add as needed + * TypeName as{TypeName}() in Value + * + * Created by Christian Conti on 6/7/10. + * Copyright 2010 ETH Zurich. All rights reserved. + * + */ + +#pragma once +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <map> +#include <vector> +#include <string> +#include <iostream> +#include <sstream> +#include <iomanip> +#include <fstream> +#include <limits> + + +using namespace std; + +class Value +{ +private: + string content; + +public: + + Value() : content("") {} + + Value(string content_) : content(content_) { /*printf("%s\n",content.c_str());*/ } + + double asDouble(double def=0) + { + if (content == "") + { + ostringstream sbuf; + sbuf << def; + content = sbuf.str(); + } + return (double) atof(content.c_str()); + } + + int asInt(int def=0) + { + if (content == "") + { + ostringstream sbuf; + sbuf << def; + content = sbuf.str(); + } + return atoi(content.c_str()); + } + + bool asBool(bool def=false) + { + if (content == "") + { + if (def) content = "true"; + else content = "false"; + } + if (content == "0") return false; + if (content == "false") return false; + + return true; + } + + string asString(string def="") + { + if (content == "") content = def; + + return content; + } +}; + +class CommandlineParser +{ +private: + const int iArgC; + const char** vArgV; + bool bStrictMode, bVerbose; + +protected: + map<string,Value> mapArguments; + +public: + + Value& operator()(const string arg) + { + if (bStrictMode) + { + map<string,Value>::const_iterator it = mapArguments.find(arg); + + if (it == mapArguments.end()) + { + printf("Runtime option NOT SPECIFIED! ABORTING! name: %s\n",arg.data()); + abort(); + } + } + + if (bVerbose) printf("%s is %s\n", arg.data(), mapArguments[arg].asString().data()); + return mapArguments[arg]; + } + + bool check(const string arg) const + { + return mapArguments.find(arg) != mapArguments.end(); + } + + CommandlineParser(const int argc, const char ** argv) : mapArguments(), iArgC(argc), vArgV(argv), bStrictMode(false), bVerbose(true) + { + for (int i=1; i<argc; i++) + if (argv[i][0] == '-') + { + string values = ""; + int itemCount = 0; + + for (int j=i+1; j<argc; j++) + { + const bool leadingDash = (argv[j][0] == '-'); + const char c = argv[j][1]; + const bool firstNumeric = ((c >= '0' && c <= '9') || c == 0) ? true : false; + if (leadingDash && !firstNumeric) + break; + else + { + if (strcmp(values.c_str(), "")) + values += ' '; + + values += argv[j]; + itemCount++; + } + } + + if (itemCount == 0) + values = "true"; + + mapArguments[argv[i]] = Value(values); + i += itemCount; + } + + mute(); + //printf("found %ld arguments of %d\n",mapArguments.size(),argc); + } + + int getargc() const { return iArgC; } + + const char** getargv() const { return vArgV; } + + void set_strict_mode() + { + bStrictMode = true; + } + + void unset_strict_mode() + { + bStrictMode = false; + } + + void mute() + { + bVerbose = false; + } + + void loud() + { + bVerbose = true; + } + + void save_options(string path=".") + { + string options; + for(map<string,Value>::iterator it=mapArguments.begin(); it!=mapArguments.end(); it++) + { + options+= it->first + " " + it->second.asString() + " "; + } + string filepath = (path + "/" + string("argumentparser.log")); + FILE * f = fopen(filepath.data(), "a"); + if (f == NULL) + { + printf("impossible to write %s.\n", filepath.data()); + return; + } + fprintf(f, "%s\n", options.data()); + fclose(f); + } + + void print_args() + { + for(map<string,Value>::iterator it=mapArguments.begin(); it!=mapArguments.end(); it++) + { + std::cout.width(50); + std::cout.fill('.'); + std::cout << std::left << it->first; + std::cout << ": " << it->second.asString() << std::endl; + } + } +}; + + +class ArgumentParser: public CommandlineParser +{ + typedef std::map<std::string, Value> ArgMap; + typedef std::map<std::string, Value*> pArgMap; + typedef std::map<std::string, ArgMap* > FileMap; + + const char commentStart; + + // keep a reference form option origin + ArgMap from_commandline; + FileMap from_files; + pArgMap from_code; + + // helper + void _ignoreComments(std::istream& stream, const char commentChar) + { + stream >> std::ws; + int nextchar = stream.peek(); + while (nextchar == commentChar) + { + stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); + stream >> std::ws; + nextchar = stream.peek(); + } + } + + bool _existKey(std::string& key) const + { + const std::string og_key = key; + bool bExist = true; + + // look for both possible keys (i.e. with leading "-" and without) + ArgMap::const_iterator it = mapArguments.find(key); + if (it == mapArguments.end()) + { + if (key[0] == '-') key = key.erase(0, 1); + else key = "-" + key; + it = mapArguments.find(key); + if (it == mapArguments.end()) + { + key = og_key; + bExist = false; + } + } + return bExist; + } + + inline std::string _stripKey(std::string key) const + { + if (key[0] == '-') key = key.erase(0, 1); + return key; + } + + +public: + ArgumentParser(const int _argc, const char ** _argv): + CommandlineParser(_argc, _argv), commentStart('#') + { + from_commandline = mapArguments; + } + + virtual ~ArgumentParser() + { + for (FileMap::iterator it = from_files.begin(); it != from_files.end(); it++) + delete it->second; + } + + void readFile(const std::string filepath) + { + from_files[filepath] = new ArgMap; + ArgMap& myFMap = *(from_files[filepath]); + + std::ifstream confFile(filepath.c_str()); + if (confFile.is_open()) + { + // read (key value) pairs from input file, ignore comments + // beginning with "#" + _ignoreComments(confFile, commentStart); + while (!confFile.eof()) + { + std::string line, key, val; + std::getline(confFile, line); + std::istringstream lineStream(line); + lineStream >> key; + lineStream >> val; + _ignoreComments(lineStream, commentStart); + while(!lineStream.eof()) + { + std::string multiVal; + lineStream >> multiVal; + val += (" " + multiVal); + _ignoreComments(lineStream, commentStart); + } + if (_existKey(key)) continue; + + std::pair<string, Value> item(key, Value(val)); + mapArguments.insert(item); // add to parent container + myFMap.insert(item); // add to private container + + _ignoreComments(confFile, commentStart); + } + } + } + + Value& operator()(std::string key) + { + const bool bDefaultInCode = !_existKey(key); + Value& retval = CommandlineParser::operator()(key); + if (bDefaultInCode) from_code[key] = &retval; + return retval; + } + + inline bool check(std::string key) const { return _existKey(key); } + inline bool exist(std::string key) const { return _existKey(key); } + + void print_args() + { + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + std::cout << "* Summary:" << std::endl; + std::cout << "* Parameter read from command line: " << from_commandline.size() << std::endl; + size_t nFiles = 0; + size_t nFileParameter = 0; + for (FileMap::const_iterator it=from_files.begin(); it!=from_files.end(); ++it) + { + if (it->second->size() > 0) + { + ++nFiles; + nFileParameter += it->second->size(); + } + } + std::cout << "* Parameter read from " << std::setw(3) << std::right << nFiles << " file(s): " << nFileParameter << std::endl; + std::cout << "* Parameter read from defaults in code: " << from_code.size() << std::endl; + std::cout << "* Total number of parameter read from all sources: " << mapArguments.size() << std::endl; + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + + // command line given arguments + if (!from_commandline.empty()) + { + std::cout << "* Command Line:" << std::endl; + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + for(ArgMap::iterator it=from_commandline.begin(); it!=from_commandline.end(); it++) + { + std::cout.width(50); + std::cout.fill('.'); + std::cout << std::left << _stripKey(it->first); + std::cout << ": " << it->second.asString() << std::endl; + } + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + } + + // options read from input files + if (!from_files.empty()) + { + for (FileMap::iterator itFile=from_files.begin(); itFile!=from_files.end(); itFile++) + { + if (!itFile->second->empty()) + { + std::cout << "* File: " << itFile->first << std::endl; + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + ArgMap& fileArgs = *(itFile->second); + for(ArgMap::iterator it=fileArgs.begin(); it!=fileArgs.end(); it++) + { + std::cout.width(50); + std::cout.fill('.'); + std::cout << std::left << _stripKey(it->first); + std::cout << ": " << it->second.asString() << std::endl; + } + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + } + } + } + + // defaults defined in code + if (!from_code.empty()) + { + std::cout << "* Defined in Code:" << std::endl; + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + for(pArgMap::iterator it=from_code.begin(); it!=from_code.end(); it++) + { + std::cout.width(50); + std::cout.fill('.'); + std::cout << std::left << _stripKey(it->first); + std::cout << ": " << it->second->asString() << std::endl; + } + std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + } + } +}; diff --git a/include/Matrix3D.h b/include/Matrix3D.h @@ -0,0 +1,170 @@ +// File : Matrix3D.h +// Date : Wed Nov 23 14:45:22 2016 +// Author : Fabian Wermelinger +// Description: 3D Matrix +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef MATRIX3D_H_L9MVKQGE +#define MATRIX3D_H_L9MVKQGE + +#include <cassert> +#include <cstdlib> +#include <cstddef> +#include <cstring> +#include <iostream> + +template <typename T, int XS=0, int XE=0, int YS=0, int YE=0, int ZS=0, int ZE=0> +class Matrix3D +{ +public: + Matrix3D() : m_Nx(0), m_Ny(0), m_Nz(0), m_allocated(false), m_data(nullptr) { } + + Matrix3D(const int Nx, const int Ny, const int Nz, const T* const data = nullptr) : + m_Nx(0), m_Ny(0), m_Nz(0), m_allocated(false), m_data(nullptr) + { + alloc(Nx, Ny, Nz, data); + } + + Matrix3D(const Matrix3D& rhs) : + m_Nx(0), m_Ny(0), m_Nz(0), m_allocated(false), m_data(nullptr) + { + if (rhs.m_allocated) + { + m_data = _alloc(rhs.m_Nx, rhs.m_Ny, rhs.m_Nz); + _copy(rhs.m_data); + } + } + + Matrix3D(Matrix3D&& rhs) : + m_Nx(rhs.m_Nx), m_Ny(rhs.m_Ny), m_Nz(rhs.m_Nz), + m_XS(rhs.m_XS), m_XE(rhs.m_XE), m_Xpitch(rhs.m_Xpitch), m_Npitched(rhs.m_Npitched), + m_allocated(rhs.m_allocated), m_data(std::move(rhs.m_data)) + { } + + ~Matrix3D() { if (m_allocated) free(m_data); } + + Matrix3D& operator=(const Matrix3D& rhs) + { + if (this != &rhs) + { + _reset(); + if (rhs.m_allocated) + { + m_data = _alloc(rhs.m_Nx, rhs.m_Ny, rhs.m_Nz); + _copy(rhs.m_data); + } + } + return *this; + } + + Matrix3D& operator=(Matrix3D&& rhs) + { + if (this != &rhs) + { + _reset(); + if (rhs.m_allocated) + { + m_Nx = rhs.m_Nx; + m_Ny = rhs.m_Ny; + m_Nz = rhs.m_Nz; + m_XS = rhs.m_XS; + m_XE = rhs.m_XE; + m_Xpitch = rhs.m_Xpitch; + m_Npitched = rhs.m_Npitched; + m_allocated = rhs.m_allocated; + m_data = std::move(rhs.m_data); + rhs.m_allocated = false; + } + } + return *this; + } + + T operator()(const int ix, const int iy, const int iz) const + { + assert(m_allocated); + assert(ix >= XS && ix < m_Nx+XE); + assert(iy >= YS && iy < m_Ny+YE); + assert(iz >= ZS && iz < m_Nz+ZE); + return m_data[(ix-XS) + m_Xpitch*(iy-YS) + m_Xpitch*(m_Ny+YE-YS)*(iz-ZS)]; + } + + T& operator()(const int ix, const int iy, const int iz) + { + assert(m_allocated); + assert(ix >= XS && ix < m_Nx+XE); + assert(iy >= YS && iy < m_Ny+YE); + assert(iz >= ZS && iz < m_Nz+ZE); + return m_data[(ix-XS) + m_Xpitch*(iy-YS) + m_Xpitch*(m_Ny+YE-YS)*(iz-ZS)]; + } + + inline void alloc(const int Nx, const int Ny, const int Nz, const T* const data = nullptr) + { + if (m_allocated) free(m_data); + m_data = _alloc(Nx, Ny, Nz); + + if (data) + { + for (int iz = 0; iz < m_Nz; ++iz) + for (int iy = 0; iy < m_Ny; ++iy) + { + const T* const src = data + m_Nx*iy + m_Nx*m_Ny*iz; + T* dst = &(this->operator()(0,iy,iz)); + memcpy(dst, src, m_Nx*sizeof(T)); + } + } + } + + inline int Nx() const { return m_Nx; } + inline int Ny() const { return m_Ny; } + inline int Nz() const { return m_Nz; } + +private: + int m_Nx; + int m_Ny; + int m_Nz; + int m_XS, m_XE, m_Xpitch, m_Npitched; + bool m_allocated; + T* m_data; + + inline T* _alloc(const int Nx, const int Ny, const int Nz) + { + m_Nx = Nx; + m_Ny = Ny; + m_Nz = Nz; + const int alignedElements = _ALIGN_/sizeof(T); + m_XS = alignedElements * (XS - (alignedElements-1))/alignedElements; + m_XE = alignedElements * (XE + (alignedElements-1))/alignedElements; + m_Xpitch = (m_Nx+m_XE) - m_XS; + m_Npitched = m_Xpitch * (m_Ny+YE-YS) * (m_Nz+ZE-ZS); + + void* pmem; + if (posix_memalign(&pmem, _ALIGN_, m_Npitched*sizeof(T))) + { + std::cerr << "ERROR: Matrix3D: can not allocate memory" << std::endl; + abort(); + } + memset(pmem, 0, m_Npitched*sizeof(T)); + m_allocated = true; + return (T*)pmem; + } + + inline void _copy(const T* const base) + { + const int Nslice = m_Xpitch * (m_Ny+YE-YS); + for (int iz = 0; iz < m_Nz+ZE-ZS; ++iz) + { + const T* const src = base + Nslice*iz; + T* dst = m_data + Nslice*iz; + memcpy(dst, src, Nslice*sizeof(T)); + } + } + + inline void _reset() + { + if (m_allocated) free(m_data); + m_Nx = m_Ny = m_Nz = m_XS = m_XE = m_Xpitch = m_Npitched = 0; + m_allocated = false; + m_data = nullptr; + } +}; + +#endif /* MATRIX3D_H_L9MVKQGE */ diff --git a/include/common.h b/include/common.h @@ -0,0 +1,30 @@ +// File : common.h +// Date : Tue Nov 22 15:51:55 2016 +// Author : Fabian Wermelinger +// Description: common stuff +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef COMMON_H_ZH0IVQBA +#define COMMON_H_ZH0IVQBA + +#ifdef _FLOAT_PRECISION_ +typedef float Real; +#else +typedef double Real; +#endif + +#ifdef _USE_HDF_ +#ifdef _FLOAT_PRECISION_ +#define HDF_PRECISION H5T_NATIVE_FLOAT +#else +#define HDF_PRECISION H5T_NATIVE_DOUBLE +#endif +#endif /* _USE_HDF_ */ + +#ifndef _ALIGN_ +#define _ALIGN_ 16 +#endif /* _ALIGN_ */ + +#include "Matrix3D.h" +typedef Matrix3D<Real,-3,3,-3,3,-3,3> Matrix_t; + +#endif /* COMMON_H_ZH0IVQBA */ diff --git a/src/Interpolator.h b/src/Interpolator.h @@ -0,0 +1,262 @@ +// File : Interpolator.h +// Date : Tue Nov 22 15:37:00 2016 +// Author : Fabian Wermelinger +// Description: Data interpolator type +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef INTERPOLATOR_H_QCK6H0CI +#define INTERPOLATOR_H_QCK6H0CI + +#include <cassert> +#include <cstdlib> +#include <iostream> +#include <cmath> +#include <cstring> +#include <string> +#include <functional> +#ifdef _USE_HDF_ +#include <hdf5.h> +#endif /* _USE_HDF_ */ + +// TODO: (fabianw@mavt.ethz.ch; Thu Nov 24 08:21:14 2016) testing +#include <fstream> + +#include "common.h" +#include "ArgumentParser.h" +#ifdef _USE_CUBISMZ_ +#include "Reader_WaveletCompression.h" +#endif /* _USE_CUBISMZ_ */ + + +template <typename TKernel> +class Interpolator +{ +public: + Interpolator(ArgumentParser& p) : + m_extent(p("extent").asDouble(1.0)) + { + // cell centered or nodal values? + if (p("data").asString("cell") == "cell") _getH = [](const Real e, const int N) { return e/static_cast<Real>(N); }; + else if (p("data").asString("cell") == "node") _getH = [](const Real e, const int N) { return e/static_cast<Real>(N-1); }; + else + { + std::cerr << "ERROR: Interpolator: Unknown data attribute \"" << p("data").asString() << "\"" << std::endl; + abort(); + } + + // load the data + if (p("load").asString("h5") == "h5") _load_h5(p); + else if (p("load").asString("h5") == "wavelet") _load_wavelet(p); + else + { + std::cerr << "ERROR: Interpolator: Undefined loader \"" << p("load").asString() << "\"" << std::endl; + abort(); + } + + const int Nmax = std::max(m_data.Nx(), std::max(m_data.Ny(), m_data.Nz())); + assert(Nmax > 1); + m_h = _getH(m_extent, Nmax); + m_invh = 1.0/m_h; + + // init coordinate transform + m_xorigin_off = p("xmin").asDouble(0.0); + m_yorigin_off = p("ymin").asDouble(0.0); + m_zorigin_off = p("zmin").asDouble(0.0); + m_isNodal = 1; + if (p("data").asString("cell") == "cell") + { + m_isNodal = 0; + m_xorigin_off += 0.5*m_h; + m_yorigin_off += 0.5*m_h; + m_zorigin_off += 0.5*m_h; + } + } + virtual ~Interpolator() {} + + Real operator()(const Real x, const Real y, const Real z) const + { + const Real xo = x - m_xorigin_off; + const Real yo = y - m_yorigin_off; + const Real zo = z - m_zorigin_off; + + const int ix0 = _idx(xo); + const int iy0 = _idx(yo); + const int iz0 = _idx(zo); + + Real interp = 0.0; + for (int iz = TKernel::start; iz < TKernel::end; ++iz) + for (int iy = TKernel::start; iy < TKernel::end; ++iy) + for (int ix = TKernel::start; ix < TKernel::end; ++ix) + { + const Real xj = _pos(ix0+ix); + const Real yj = _pos(iy0+iy); + const Real zj = _pos(iz0+iz); + const Real Mx = m_kernel((xo-xj)*m_invh); + const Real My = m_kernel((yo-yj)*m_invh); + const Real Mz = m_kernel((zo-zj)*m_invh); + interp += m_data(ix0+ix,iy0+iy,iz0+iz)*Mx*My*Mz; + } + return interp; + } + + Real getH() const { return m_h; } + Real getExtent() const { return m_extent; } + int getNx() const { return m_data.Nx(); } + int getNy() const { return m_data.Ny(); } + int getNz() const { return m_data.Nz(); } + int isNodal() const { return m_isNodal; } + + // TODO: (fabianw@mavt.ethz.ch; Thu Nov 24 16:38:31 2016) trash this + // void dump_data(const Real x, const Real y, const Real z) const + // { + // const Real xo = x - m_xorigin_off; + // const Real yo = y - m_yorigin_off; + // const Real zo = z - m_zorigin_off; + + // const int iy = _idx(yo); + // const int iz = _idx(zo); + + // ofstream idata("raw_data.dat"); + // for (int ix = 0; ix < m_data.Nx(); ++ix) + // idata << _pos(ix)+m_xorigin_off << "\t" << m_data(ix,iy,iz) << std::endl; + // } + + +private: + const Real m_extent; + Real m_xorigin_off; + Real m_yorigin_off; + Real m_zorigin_off; + Real m_h, m_invh; + int m_isNodal; + + Matrix_t m_data; + TKernel m_kernel; + + // loader + void _load_h5(ArgumentParser& p); + void _load_wavelet(ArgumentParser& p); + + // helper + std::function<Real(const Real, const int)> _getH; + inline int _idx(const Real x) const { return x*m_invh; } + inline Real _pos(const int i) const { return i*m_h; } +}; + + +template <typename TKernel> +void Interpolator<TKernel>::_load_h5(ArgumentParser& parser) +{ +#ifdef _USE_HDF_ + const std::string group = parser("hdf5_group").asString("/data"); + const std::string filename = parser("file").asString(""); + if (filename == "") + { + std::cerr << "ERROR: Interpolator: -file is not specified. No input file given" << std::endl; + abort(); + } + + hid_t file_id, dataset_id, dataspace_id, file_dataspace_id; + hsize_t* dims; + hssize_t num_elem; + int rank, ndims, NCH; + int maxDim[3]; + Real* data; + + file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + dataset_id = H5Dopen(file_id, group.c_str(), H5P_DEFAULT); + file_dataspace_id = H5Dget_space(dataset_id); + rank = H5Sget_simple_extent_ndims(file_dataspace_id); + dims = new hsize_t[rank]; + ndims = H5Sget_simple_extent_dims(file_dataspace_id, dims, NULL); + num_elem = H5Sget_simple_extent_npoints(file_dataspace_id); + data = new Real[num_elem]; + maxDim[2] = dims[0]; + maxDim[1] = dims[1]; + maxDim[0] = dims[2]; + NCH = dims[3]; + dataspace_id = H5Screate_simple(rank, dims, NULL); + int status = H5Dread(dataset_id, HDF_PRECISION, dataspace_id, file_dataspace_id, H5P_DEFAULT, data); + + /* release stuff */ + delete [] dims; + status = H5Dclose(dataset_id); + status = H5Sclose(dataspace_id); + status = H5Sclose(file_dataspace_id); + status = H5Fclose(file_id); + + if (NCH > 1) + { + const int channel = parser("channel").asInt(0); // data channel + const bool magnitude = parser("magnitude").asBool(false); // vector magnitude (only if NCH == 3) + if (magnitude && NCH == 3) + { + int k = 0; + for (int i = 0; i < num_elem; i += NCH) + { + const Real a = data[i+0]; + const Real b = data[i+1]; + const Real c = data[i+2]; + data[k++] = std::sqrt(a*a + b*b + c*c); + } + + } + else + { + assert(channel < NCH); + int k = 0; + for (int i = 0; i < num_elem; i += NCH) + data[k++] = data[i+channel]; + } + } + this->m_data = std::move(Matrix_t(maxDim[0], maxDim[1], maxDim[2], data)); + delete [] data; +#endif /* _USE_HDF_ */ +} + +template <typename TKernel> +void Interpolator<TKernel>::_load_wavelet(ArgumentParser& p) +{ +#ifdef _USE_CUBISMZ_ + const bool byte_swap = p("-swap").asBool(false); + const int wavelet_type = p("-wtype").asInt(1); + const std::string filename = p("file").asString(""); + if (filename == "") + { + std::cerr << "ERROR: Interpolator: -file is not specified. No input file given" << std::endl; + abort(); + } + + const string fname(filename); + Reader_WaveletCompression myreader(fname, byte_swap, wavelet_type); + myreader.load_file(); + const int NBX = myreader.xblocks(); + const int NBY = myreader.yblocks(); + const int NBZ = myreader.zblocks(); + const int maxDim[3] = {NBX*_BLOCKSIZE_, NBY*_BLOCKSIZE_, NBZ*_BLOCKSIZE_}; + Real* const data = new Real[maxDim[0]*maxDim[1]*maxDim[2]]; + + Real blockdata[_BLOCKSIZE_][_BLOCKSIZE_][_BLOCKSIZE_]; + for (int iz=0; iz < NBZ; ++iz) + for (int iy=0; iy < NBY; ++iy) + for (int ix=0; ix < NBX; ++ix) + { + const double zratio = myreader.load_block2(ix, iy, iz, blockdata); + + for (int z=0; z < _BLOCKSIZE_; ++z) + for (int y=0; y < _BLOCKSIZE_; ++y) + { + assert(iy*_BLOCKSIZE_+y < maxDim[1]); + assert(iz*_BLOCKSIZE_+z < maxDim[2]); + Real* const dst = data + _BLOCKSIZE_*(ix + NBX*(y+iy*_BLOCKSIZE_ + (z+iz*_BLOCKSIZE_)*NBY*_BLOCKSIZE_)); + memcpy(dst, &blockdata[z][y][0], _BLOCKSIZE_*sizeof(Real)); + } + } + + this->m_data = std::move(Matrix_t(maxDim[0], maxDim[1], maxDim[2], data)); + delete [] data; +#else + fprintf(stderr, "WARNING: Executable was compiled without wavelet compressor support...\n"); +#endif /* _USE_CUBISMZ_ */ +} + +#endif /* INTERPOLATOR_H_QCK6H0CI */ diff --git a/src/IsoExtractor.h b/src/IsoExtractor.h @@ -0,0 +1,681 @@ +// File : IsoExtractor.h +// Date : Fri Nov 25 19:12:52 2016 +// Author : Fabian Wermelinger +// Description: Iso surface extractor +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef ISOEXTRACTOR_H_A1WQHFFC +#define ISOEXTRACTOR_H_A1WQHFFC + +#include <vector> +#include <fstream> +#include <string> +#include <ctime> +#include <cstdlib> +#include "common.h" +#include "ArgumentParser.h" +#include "Interpolator.h" + +struct Triangle +{ + Real vertices[3][3]; +}; + +static const Real gVertexOffset[8][3] = +{ + {0.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0},{1.0, 0.0, 1.0},{1.0, 1.0, 1.0},{0.0, 1.0, 1.0} +}; + +static const int gEdgeConnection[12][2] = +{ + {0,1}, {1,2}, {2,3}, {3,0}, + {4,5}, {5,6}, {6,7}, {7,4}, + {0,4}, {1,5}, {2,6}, {3,7} +}; + +static const Real gEdgeDirection[12][3] = +{ + {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, + {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0}, + {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0, 0.0, 1.0} +}; + +static const int gTetrahedronEdgeConnection[6][2] = +{ + {0,1}, {1,2}, {2,0}, {0,3}, {1,3}, {2,3} +}; + +static const int gTetrahedronsInACube[6][4] = +{ + {0,5,1,6}, + {0,1,2,6}, + {0,2,3,6}, + {0,3,7,6}, + {0,7,4,6}, + {0,4,5,6}, +}; + +static const int gCubeEdgeFlags[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 +}; + +static const int gTriangleConnectionTable[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} +}; + +static const int gTetrahedronEdgeFlags[16] = +{ + 0x00, 0x0d, 0x13, 0x1e, 0x26, 0x2b, 0x35, 0x38, 0x38, 0x35, 0x2b, 0x26, 0x1e, 0x13, 0x0d, 0x00 +}; + +static const int gTetrahedronTriangles[16][7] = +{ + {-1, -1, -1, -1, -1, -1, -1}, + { 0, 3, 2, -1, -1, -1, -1}, + { 0, 1, 4, -1, -1, -1, -1}, + { 1, 4, 2, 2, 4, 3, -1}, + + { 1, 2, 5, -1, -1, -1, -1}, + { 0, 3, 5, 0, 5, 1, -1}, + { 0, 2, 5, 0, 5, 4, -1}, + { 5, 4, 3, -1, -1, -1, -1}, + + { 3, 4, 5, -1, -1, -1, -1}, + { 4, 5, 0, 5, 2, 0, -1}, + { 1, 5, 0, 5, 3, 0, -1}, + { 5, 2, 1, -1, -1, -1, -1}, + + { 3, 4, 2, 2, 4, 1, -1}, + { 4, 1, 0, -1, -1, -1, -1}, + { 2, 3, 0, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1} +}; + + +template <typename Tinterp> +class IsoExtractor +{ +public: + IsoExtractor(ArgumentParser& parser) : + m_parser(parser), + m_interp(parser), + m_x0(parser("xmin").asDouble(0.0)), + m_y0(parser("ymin").asDouble(0.0)), + m_z0(parser("zmin").asDouble(0.0)) {} + ~IsoExtractor() {} + + void extract(const Real isoval, const std::string fout) + { + const Real x0 = m_parser("xmin").asDouble(0.0); + const Real y0 = m_parser("ymin").asDouble(0.0); + const Real z0 = m_parser("zmin").asDouble(0.0); + + const Real cscale = m_parser("cube_scale").asDouble(1.0); + assert(cscale > 0.0); + const int Nx = static_cast<Real>(m_interp.getNx()) / cscale; + const int Ny = static_cast<Real>(m_interp.getNy()) / cscale; + const int Nz = static_cast<Real>(m_interp.getNz()) / cscale; + assert(Nx > 1); + assert(Ny > 1); + assert(Nz > 1); + const Real ch = m_interp.getExtent() / (std::max(Nx, std::max(Ny, Nz)) - m_interp.isNodal()); + + m_triList.clear(); + + if (m_parser("march").asString("cube") == "cube") + { + for (int k = 0; k < Nz; ++k) + for (int j = 0; j < Ny; ++j) + for (int i = 0; i < Nx; ++i) + { + const Real x = i*ch; + const Real y = j*ch; + const Real z = k*ch; + _marchCube(x, y, z, ch, isoval); + } + } + else if (m_parser("march").asString("cube") == "tetrahedron") + { + for (int k = 0; k < Nz; ++k) + for (int j = 0; j < Ny; ++j) + for (int i = 0; i < Nx; ++i) + { + const Real x = i*ch; + const Real y = j*ch; + const Real z = k*ch; + _marchTetrahedron(x, y, z, ch, isoval); + } + } + else + { + std::cerr << "ERROR: IsoExtractor: Unknown algorithm " << m_parser("march").asString() << std::endl; + abort(); + } + + _writePLY(fout, m_triList); + } + + +private: + ArgumentParser& m_parser; + Interpolator<Tinterp> m_interp; + const Real m_x0; + const Real m_y0; + const Real m_z0; + + std::vector<Triangle> m_triList; + + // helper + inline Real _getEdgeFrac(const Real v0, const Real v1, const Real t) + { + const Real dv = v1 - v0; + if (dv == 0.0) return 0.5; + return (t - v0)/dv; + } + + inline void _marchCube(const Real x, const Real y, const Real z, const Real h, const Real target); + inline void _marchTetrahedron(const Real x, const Real y, const Real z, const Real h, const Real target); + inline void _evalTetrahedron(const Real coords[4][3], const Real val[4], const Real target); + + void _writePLY(const std::string basename, const std::vector<Triangle>& tList) + { + time_t rawtime; + std::time(&rawtime); + struct tm* timeinfo = std::localtime(&rawtime); + char buf[256]; + std::strftime(buf, 256, "%A, %h %d %Y, %r %Z %z", timeinfo); + + const unsigned int one = 1; + const unsigned char* const lsb = (const unsigned char*)(&one); + const std::string endianess((*lsb) ? "binary_little_endian" : "binary_big_endian"); + + // write header + std::ofstream ply(basename+".ply"); + ply << "ply" << std::endl; + ply << "format "; + if (m_parser("binary").asBool(true)) + ply << endianess; + else + ply << "ascii"; + ply << " 1.0" << std::endl; + ply << "comment generated by IsoExtractor.h on " << buf << std::endl; + ply << "element vertex " << tList.size()*3 << std::endl; + ply << "property float x" << std::endl; + ply << "property float y" << std::endl; + ply << "property float z" << std::endl; + ply << "element face " << tList.size() << std::endl; + ply << "property list uchar int vertex_index" << std::endl; + ply << "end_header" << std::endl; + ply.close(); + + // write content + if (m_parser("binary").asBool(true)) + { + ply.open(basename+".ply", std::ios::out | std::ios::app | std::ios::binary); + _writePLY_binary(ply, tList); + } + else + { + ply.open(basename+".ply", std::ios::out | std::ios::app | std::ios::binary); + _writePLY_ascii(ply, tList); + } + ply.close(); + } + + void _writePLY_binary(std::ostream& ply, const std::vector<Triangle>& tList) + { + for (auto t : tList) + { + float tc[3][3]; + for (int j = 0; j < 3; ++j) + { + tc[j][0] = t.vertices[j][0]; + tc[j][1] = t.vertices[j][1]; + tc[j][2] = t.vertices[j][2]; + } + ply.write((char*)&tc[0][0], 9*sizeof(float)); + } + + const char nVert = 3; + for (int i = 0; i < tList.size()*3; i += 3) + { + int tv[3] = {i, i+1, i+2}; + ply.write(&nVert, sizeof(char)); + ply.write((char*)&tv[0], 3*sizeof(int)); + } + } + + void _writePLY_ascii(std::ostream& ply, const std::vector<Triangle>& tList) + { + for (auto t : tList) + for (int j = 0; j < 3; ++j) + ply << t.vertices[j][0] << " " << t.vertices[j][1] << " " << t.vertices[j][2] << std::endl; + for (int i = 0; i < tList.size()*3; i += 3) + ply << "3 " << i << " " << i+1 << " " << i+2 << std::endl; + } +}; + + +template <typename Tinterp> +void IsoExtractor<Tinterp>::_marchCube(const Real x, const Real y, const Real z, const Real h, const Real target) +{ + Real valCubeVerts[8]; + Real coordEdgeVert[12][3]; + + // compute cube vertex values + for (int i = 0; i < 8; ++i) + valCubeVerts[i] = m_interp( + x + h*gVertexOffset[i][0], + y + h*gVertexOffset[i][1], + z + h*gVertexOffset[i][2]); + + // find if there are vertices inside and outside the target value + int flagVert = 0; + for (int i = 0; i < 8; ++i) + { + if (valCubeVerts[i] <= target) flagVert |= 1 << i; + } + + // indentify the edge intersections + const int flagEdge = gCubeEdgeFlags[flagVert]; + + // if there are no intersections at all, bye + if(flagEdge == 0) + return; + + // compute coordinates of triangle vertices on intersected edges + for (int i = 0; i < 12; ++i) + { + if (flagEdge & (1 << i)) + { + // linear interpolation + const Real frac = _getEdgeFrac(valCubeVerts[gEdgeConnection[i][0]], valCubeVerts[gEdgeConnection[i][1]], target); + coordEdgeVert[i][0] = x + h*(gVertexOffset[gEdgeConnection[i][0]][0] + frac*gEdgeDirection[i][0]); + coordEdgeVert[i][1] = y + h*(gVertexOffset[gEdgeConnection[i][0]][1] + frac*gEdgeDirection[i][1]); + coordEdgeVert[i][2] = z + h*(gVertexOffset[gEdgeConnection[i][0]][2] + frac*gEdgeDirection[i][2]); + } + } + + // push the triangles found into the list + for (int i = 0; i < 5; ++i) + { + if (gTriangleConnectionTable[flagVert][3*i] < 0) break; + + Triangle tri; + for (int j = 0; j < 3; ++j) + { + const int k = gTriangleConnectionTable[flagVert][3*i + j]; + tri.vertices[j][0] = coordEdgeVert[k][0]; + tri.vertices[j][1] = coordEdgeVert[k][1]; + tri.vertices[j][2] = coordEdgeVert[k][2]; + } + m_triList.push_back(tri); + } +} + + +template <typename Tinterp> +void IsoExtractor<Tinterp>::_marchTetrahedron(const Real x, const Real y, const Real z, const Real h, const Real target) +{ + Real valCubeVerts[8]; + Real coordCubeVerts[8][3]; + Real valTetraVerts[4]; + Real coordTetraVerts[4][3]; + + // compute cube vertex coordinates + for (int i = 0; i < 8; ++i) + { + coordCubeVerts[i][0] = x + h*gVertexOffset[i][0]; + coordCubeVerts[i][1] = y + h*gVertexOffset[i][1]; + coordCubeVerts[i][2] = z + h*gVertexOffset[i][2]; + } + + // compute cube vertex values + for (int i = 0; i < 8; ++i) + valCubeVerts[i] = m_interp( + coordCubeVerts[i][0], + coordCubeVerts[i][1], + coordCubeVerts[i][2]); + + for (int i = 0; i < 6; ++i) + { + for (int j = 0; j < 4; ++j) + { + const int vertID = gTetrahedronsInACube[i][j]; + coordTetraVerts[j][0] = coordCubeVerts[vertID][0]; + coordTetraVerts[j][1] = coordCubeVerts[vertID][1]; + coordTetraVerts[j][2] = coordCubeVerts[vertID][2]; + valTetraVerts[j] = valCubeVerts[vertID]; + } + _evalTetrahedron(coordTetraVerts, valTetraVerts, target); + } +} + + +template <typename Tinterp> +void IsoExtractor<Tinterp>::_evalTetrahedron(const Real coords[4][3], const Real val[4], const Real target) +{ + Real coordEdgeVert[6][3]; + + // find if there are vertices inside and outside the target value + int flagVert = 0; + for (int i = 0; i < 4; ++i) + { + if (val[i] <= target) flagVert |= 1 << i; + } + + // indentify the edge intersections + const int flagEdge = gTetrahedronEdgeFlags[flagVert]; + + // if there are no intersections at all, bye + if(flagEdge == 0) + return; + + // compute coordinates of triangle vertices on intersected edges + for (int i = 0; i < 6; ++i) + { + if (flagEdge & (1 << i)) + { + const int vert0 = gTetrahedronEdgeConnection[i][0]; + const int vert1 = gTetrahedronEdgeConnection[i][1]; + + // linear interpolation + const Real frac = _getEdgeFrac(val[vert0], val[vert1], target); + const Real ifrac= 1.0 - frac; + + coordEdgeVert[i][0] = ifrac*coords[vert0][0] + frac*coords[vert1][0]; + coordEdgeVert[i][1] = ifrac*coords[vert0][1] + frac*coords[vert1][1]; + coordEdgeVert[i][2] = ifrac*coords[vert0][2] + frac*coords[vert1][2]; + } + } + + // push the triangles found into the list + for (int i = 0; i < 2; ++i) + { + if (gTetrahedronTriangles[flagVert][3*i] < 0) break; + + Triangle tri; + for (int j = 0; j < 3; ++j) + { + const int k = gTetrahedronTriangles[flagVert][3*i + j]; + tri.vertices[j][0] = coordEdgeVert[k][0]; + tri.vertices[j][1] = coordEdgeVert[k][1]; + tri.vertices[j][2] = coordEdgeVert[k][2]; + } + m_triList.push_back(tri); + } +} + +#endif /* ISOEXTRACTOR_H_A1WQHFFC */ diff --git a/src/easy_iso.cpp b/src/easy_iso.cpp @@ -0,0 +1,31 @@ +// File : easy_iso.cpp +// Date : Tue Nov 22 15:00:14 2016 +// Author : Fabian Wermelinger +// Description: Isosurface extractor +// Copyright 2016 ETH Zurich. All Rights Reserved. +#include <string> +#include <sstream> +#include "ArgumentParser.h" +#include "interpolation/kernels.h" +#include "IsoExtractor.h" + +int main(int argc, char* argv[]) +{ + ArgumentParser parser(argc, const_cast<const char**>(argv)); + + using Tinterp = M2; + if (parser("interp_kernel").asString("M2") == "Mp4") + using Tinterp = Mprime4; + else if (parser("interp_kernel").asString("M2") == "M5") + using Tinterp = M5; + + IsoExtractor<Tinterp> iso(parser); + + const Real isoval = parser("isoval").asDouble(0.0); + std::ostringstream basename; + basename << "isosurf_" << isoval; + const std::string fout = parser("fout").asString(basename.str()); + iso.extract(isoval, fout); + + return 0; +} diff --git a/src/interpolation/M2.h b/src/interpolation/M2.h @@ -0,0 +1,28 @@ +// File : M2.h +// Date : Thu Nov 24 16:14:51 2016 +// Author : Fabian Wermelinger +// Description: M2 interpolation kernel (Monaghan 19885) -- triangular function +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef M2_H_LQ69GRM8 +#define M2_H_LQ69GRM8 + +#include <cmath> +#include "common.h" + +class M2 +{ +public: + static constexpr int start = 0; + static constexpr int end = 2; + + inline Real operator()(const Real x) const + { + const Real IxI = std::abs(x); + if (IxI <= 1.0) + return 1.0 - IxI; + else + return 0.0; + } +}; + +#endif /* M2_H_LQ69GRM8 */ diff --git a/src/interpolation/M5.h b/src/interpolation/M5.h @@ -0,0 +1,33 @@ +// File : M5.h +// Date : Thu Nov 24 09:33:24 2016 +// Author : Fabian Wermelinger +// Description: M5 smoothing interpolation kernel (Monaghan 1985) +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef M5_H_G6FRPHTC +#define M5_H_G6FRPHTC + +#include <cmath> +#include "common.h" + +class M5 +{ +public: + static constexpr int start = -2; + static constexpr int end = 4; + + inline Real operator()(const Real x) const + { + const Real a0 = 1.0/48.0; + const Real IxI = std::abs(x); + if (IxI < 0.5) + return a0*(43.125-75.0*IxI*IxI+42.0*IxI*IxI*IxI*IxI); + else if (IxI < 1.5) + return a0*(41.25+20.0*IxI-150.0*IxI*IxI+120.0*IxI*IxI*IxI-28.0*IxI*IxI*IxI*IxI); + else if (IxI < 2.5) + return a0*(IxI-2.5)*(IxI-2.5)*(IxI-2.5)*(7.0*IxI-7.5); + else + return 0.0; + } +}; + +#endif /* M5_H_G6FRPHTC */ diff --git a/src/interpolation/Mprime4.h b/src/interpolation/Mprime4.h @@ -0,0 +1,30 @@ +// File : Mprime4.h +// Date : Thu Nov 24 08:33:08 2016 +// Author : Fabian Wermelinger +// Description: M^\prime_4 interpolation kernel (3rd order) +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef MPRIME4_H_KXJZRENA +#define MPRIME4_H_KXJZRENA + +#include <cmath> +#include "common.h" + +class Mprime4 +{ +public: + static constexpr int start = -1; + static constexpr int end = 3; + + inline Real operator()(const Real x) const + { + const Real IxI = std::abs(x); + if (IxI < 1.0) + return 0.5*(IxI - 1.0)*(3.0*IxI*IxI - 2.0*IxI - 2.0); + else if (IxI < 2.0) + return -0.5*(IxI - 1.0)*(IxI - 2.0)*(IxI - 2.0); + else + return 0.0; + } +}; + +#endif /* MPRIME4_H_KXJZRENA */ diff --git a/src/interpolation/kernels.h b/src/interpolation/kernels.h @@ -0,0 +1,13 @@ +// File : kernels.h +// Date : Thu Nov 24 16:47:33 2016 +// Author : Fabian Wermelinger +// Description: Interpolation kernels +// Copyright 2016 ETH Zurich. All Rights Reserved. +#ifndef KERNELS_H_IRWGGDVC +#define KERNELS_H_IRWGGDVC + +#include "interpolation/M2.h" +#include "interpolation/Mprime4.h" +#include "interpolation/M5.h" + +#endif /* KERNELS_H_IRWGGDVC */