From be731665f0f923af118e4e6a9661998c46216517 Mon Sep 17 00:00:00 2001 From: HiroIshida Date: Mon, 20 Jan 2025 02:20:37 +0900 Subject: [PATCH] chore: add SDFGen (MIT-licensed) source code under third --- third/SDFGen/.gitignore | 2 + third/SDFGen/CMakeLists.txt | 13 + third/SDFGen/README.md | 25 ++ third/SDFGen/array1.h | 794 +++++++++++++++++++++++++++++++++ third/SDFGen/array3.h | 272 +++++++++++ third/SDFGen/makelevelset3.cpp | 184 ++++++++ third/SDFGen/makelevelset3.h | 16 + third/SDFGen/util.h | 470 +++++++++++++++++++ third/SDFGen/vec.h | 478 ++++++++++++++++++++ 9 files changed, 2254 insertions(+) create mode 100644 third/SDFGen/.gitignore create mode 100644 third/SDFGen/CMakeLists.txt create mode 100644 third/SDFGen/README.md create mode 100644 third/SDFGen/array1.h create mode 100644 third/SDFGen/array3.h create mode 100644 third/SDFGen/makelevelset3.cpp create mode 100644 third/SDFGen/makelevelset3.h create mode 100644 third/SDFGen/util.h create mode 100644 third/SDFGen/vec.h diff --git a/third/SDFGen/.gitignore b/third/SDFGen/.gitignore new file mode 100644 index 0000000..6bace84 --- /dev/null +++ b/third/SDFGen/.gitignore @@ -0,0 +1,2 @@ +action.sh +/build diff --git a/third/SDFGen/CMakeLists.txt b/third/SDFGen/CMakeLists.txt new file mode 100644 index 0000000..9e3c50c --- /dev/null +++ b/third/SDFGen/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) +Project("SDFGen") + +SET(CMAKE_BUILD_TYPE Release) + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin) + +set(CMAKE_CXX_FLAGS "-O3") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native") +# static +add_library(sdfgen STATIC makelevelset3.cpp) +# add_executable(${PROJECT_NAME} main.cpp makelevelset3.cpp) diff --git a/third/SDFGen/README.md b/third/SDFGen/README.md new file mode 100644 index 0000000..ed85c98 --- /dev/null +++ b/third/SDFGen/README.md @@ -0,0 +1,25 @@ +# SDFGen +A simple commandline utility to generate grid-based signed distance field (level set) generator from triangle meshes, using code from Robert Bridson's website. + + +The MIT License (MIT) + +Copyright (c) 2015, Christopher Batty + +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. diff --git a/third/SDFGen/array1.h b/third/SDFGen/array1.h new file mode 100644 index 0000000..9c67b49 --- /dev/null +++ b/third/SDFGen/array1.h @@ -0,0 +1,794 @@ +#ifndef ARRAY1_H +#define ARRAY1_H + +#include +#include +#include +#include +#include +#include +#include +#include + +// In this file: +// Array1: a dynamic 1D array for plain-old-data (not objects) +// WrapArray1: a 1D array wrapper around an existing array (perhaps objects, perhaps data) +// For the most part std::vector operations are supported, though for the Wrap version +// note that memory is never allocated/deleted and constructor/destructors are never called +// from within the class, thus only shallow copies can be made and some operations such as +// resize() and push_back() are limited. +// Note: for the most part assertions are done with assert(), not exceptions... + +// gross template hacking to determine if a type is integral or not +struct Array1True {}; +struct Array1False {}; +template struct Array1IsIntegral{ typedef Array1False type; }; // default: no (specializations to yes follow) +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; +template<> struct Array1IsIntegral{ typedef Array1True type; }; + +//============================================================================ +template +struct Array1 +{ + // STL-friendly typedefs + + typedef T* iterator; + typedef const T* const_iterator; + typedef unsigned long size_type; + typedef long difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // the actual representation + + unsigned long n; + unsigned long max_n; + T* data; + + // STL vector's interface, with additions, but only valid when used with plain-old-data + + Array1(void) + : n(0), max_n(0), data(0) + {} + + // note: default initial values are zero + Array1(unsigned long n_) + : n(0), max_n(0), data(0) + { + if(n_>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + data=(T*)std::calloc(n_, sizeof(T)); + if(!data) throw std::bad_alloc(); + n=n_; + max_n=n_; + } + + Array1(unsigned long n_, const T& value) + : n(0), max_n(0), data(0) + { + if(n_>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + data=(T*)std::calloc(n_, sizeof(T)); + if(!data) throw std::bad_alloc(); + n=n_; + max_n=n_; + for(unsigned long i=0; iULONG_MAX/sizeof(T)) throw std::bad_alloc(); + data=(T*)std::calloc(max_n_, sizeof(T)); + if(!data) throw std::bad_alloc(); + n=n_; + max_n=max_n_; + for(unsigned long i=0; iULONG_MAX/sizeof(T)) throw std::bad_alloc(); + data=(T*)std::calloc(n_, sizeof(T)); + if(!data) throw std::bad_alloc(); + n=n_; + max_n=n_; + assert(data_); + std::memcpy(data, data_, n*sizeof(T)); + } + + Array1(unsigned long n_, const T* data_, unsigned long max_n_) + : n(0), max_n(0), data(0) + { + assert(n_<=max_n_); + if(max_n_>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + data=(T*)std::calloc(max_n_, sizeof(T)); + if(!data) throw std::bad_alloc(); + max_n=max_n_; + n=n_; + assert(data_); + std::memcpy(data, data_, n*sizeof(T)); + } + + Array1(const Array1 &x) + : n(0), max_n(0), data(0) + { + data=(T*)std::malloc(x.n*sizeof(T)); + if(!data) throw std::bad_alloc(); + n=x.n; + max_n=x.n; + std::memcpy(data, x.data, n*sizeof(T)); + } + + ~Array1(void) + { + std::free(data); +#ifndef NDEBUG + data=0; + n=max_n=0; +#endif + } + + const T& operator[](unsigned long i) const + { return data[i]; } + + T& operator[](unsigned long i) + { return data[i]; } + + // these are range-checked (in debug mode) versions of operator[], like at() + const T& operator()(unsigned long i) const + { + assert(i& operator=(const Array1& x) + { + if(max_n& x) const + { + if(n!=x.n) return false; + for(unsigned long i=0; i& x) const + { + if(n!=x.n) return true; + for(unsigned long i=0; i& x) const + { + for(unsigned long i=0; i(const Array1& x) const + { + for(unsigned long i=0; ix[i]) return true; + else if(x[i]>data[i]) return false; + } + return n>x.n; + } + + bool operator<=(const Array1& x) const + { + for(unsigned long i=0; i=(const Array1& x) const + { + for(unsigned long i=0; ix[i]) return true; + else if(x[i]>data[i]) return false; + } + return n>=x.n; + } + + void add_unique(const T& value) + { + for(unsigned long i=0; imax_n){ + if(num>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + std::free(data); + data=(T*)std::malloc(num*sizeof(T)); + if(!data) throw std::bad_alloc(); + max_n=num; + } + n=num; + std::memcpy(data, copydata, n*sizeof(T)); + } + + template + void assign(InputIterator first, InputIterator last) + { assign_(first, last, typename Array1IsIntegral::type()); } + + template + void assign_(InputIterator first, InputIterator last, Array1True check) + { fill(first, last); } + + template + void assign_(InputIterator first, InputIterator last, Array1False check) + { + unsigned long i=0; + InputIterator p=first; + for(; p!=last; ++p, ++i){ + if(i==max_n) grow(); + data[i]=*p; + } + n=i; + } + + const T& at(unsigned long i) const + { + assert(i0); + return data[n-1]; + } + + T& back(void) + { + assert(data && n>0); + return data[n-1]; + } + + const T* begin(void) const + { return data; } + + T* begin(void) + { return data; } + + unsigned long capacity(void) const + { return max_n; } + + void clear(void) + { + std::free(data); + data=0; + max_n=0; + n=0; + } + + bool empty(void) const + { return n==0; } + + const T* end(void) const + { return data+n; } + + T* end(void) + { return data+n; } + + void erase(unsigned long index) + { + assert(indexmax_n){ + if(num>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + std::free(data); + data=(T*)std::malloc(num*sizeof(T)); + if(!data) throw std::bad_alloc(); + max_n=num; + } + n=num; + for(unsigned long i=0; i0); + return *data; + } + + T& front(void) + { + assert(n>0); + return *data; + } + + void grow(void) + { + unsigned long new_size=(max_n*sizeof(T)index; --i) + data[i]=data[i-1]; + data[index]=entry; + } + + unsigned long max_size(void) const + { return ULONG_MAX/sizeof(T); } + + void pop_back(void) + { + assert(n>0); + --n; + } + + void push_back(const T& value) + { + if(n==max_n) grow(); + data[n++]=value; + } + + reverse_iterator rbegin(void) + { return reverse_iterator(end()); } + + const_reverse_iterator rbegin(void) const + { return const_reverse_iterator(end()); } + + reverse_iterator rend(void) + { return reverse_iterator(begin()); } + + const_reverse_iterator rend(void) const + { return const_reverse_iterator(begin()); } + + void reserve(unsigned long r) + { + if(r>ULONG_MAX/sizeof(T)) throw std::bad_alloc(); + T *new_data=(T*)std::realloc(data, r*sizeof(T)); + if(!new_data) throw std::bad_alloc(); + data=new_data; + max_n=r; + } + + void resize(unsigned long n_) + { + if(n_>max_n) reserve(n_); + n=n_; + } + + void resize(unsigned long n_, const T& value) + { + if(n_>max_n) reserve(n_); + if(n& x) + { + std::swap(n, x.n); + std::swap(max_n, x.max_n); + std::swap(data, x.data); + } + + // resize the array to avoid wasted space, without changing contents + // (Note: realloc, at least on some platforms, will not do the trick) + void trim(void) + { + if(n==max_n) return; + T *new_data=(T*)std::malloc(n*sizeof(T)); + if(!new_data) return; + std::memcpy(new_data, data, n*sizeof(T)); + std::free(data); + data=new_data; + max_n=n; + } +}; + +// some common arrays + +typedef Array1 Array1d; +typedef Array1 Array1f; +typedef Array1 Array1ll; +typedef Array1 Array1ull; +typedef Array1 Array1i; +typedef Array1 Array1ui; +typedef Array1 Array1s; +typedef Array1 Array1us; +typedef Array1 Array1c; +typedef Array1 Array1uc; + +//============================================================================ +template +struct WrapArray1 +{ + // STL-friendly typedefs + + typedef T* iterator; + typedef const T* const_iterator; + typedef unsigned long size_type; + typedef long difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // the actual representation + + unsigned long n; + unsigned long max_n; + T* data; + + // most of STL vector's interface, with a few changes + + WrapArray1(void) + : n(0), max_n(0), data(0) + {} + + WrapArray1(unsigned long n_, T* data_) + : n(n_), max_n(n_), data(data_) + { assert(data || max_n==0); } + + WrapArray1(unsigned long n_, T* data_, unsigned long max_n_) + : n(n_), max_n(max_n_), data(data_) + { + assert(n<=max_n); + assert(data || max_n==0); + } + + // Allow for simple shallow copies of existing arrays + // Note that if the underlying arrays change where their data is, the WrapArray may be screwed up + + WrapArray1(Array1& a) + : n(a.n), max_n(a.max_n), data(a.data) + {} + + WrapArray1(std::vector& a) + : n(a.size()), max_n(a.capacity()), data(&a[0]) + {} + + void init(unsigned long n_, T* data_, unsigned long max_n_) + { + assert(n_<=max_n_); + assert(data_ || max_n_==0); + n=n_; + max_n=max_n_; + data=data_; + } + + const T& operator[](unsigned long i) const + { return data[i]; } + + T& operator[](unsigned long i) + { return data[i]; } + + // these are range-checked (in debug mode) versions of operator[], like at() + const T& operator()(unsigned long i) const + { + assert(i& x) const + { + if(n!=x.n) return false; + for(unsigned long i=0; i& x) const + { + if(n!=x.n) return true; + for(unsigned long i=0; i& x) const + { + for(unsigned long i=0; i(const WrapArray1& x) const + { + for(unsigned long i=0; ix[i]) return true; + else if(x[i]>data[i]) return false; + } + return n>x.n; + } + + bool operator<=(const WrapArray1& x) const + { + for(unsigned long i=0; i=(const WrapArray1& x) const + { + for(unsigned long i=0; ix[i]) return true; + else if(x[i]>data[i]) return false; + } + return n>=x.n; + } + + void add_unique(const T& value) + { + for(unsigned long i=0; i + void assign(InputIterator first, InputIterator last) + { assign_(first, last, typename Array1IsIntegral::type()); } + + template + void assign_(InputIterator first, InputIterator last, Array1True check) + { fill(first, last); } + + template + void assign_(InputIterator first, InputIterator last, Array1False check) + { + unsigned long i=0; + InputIterator p=first; + for(; p!=last; ++p, ++i){ + assert(i0); + return data[n-1]; + } + + T& back(void) + { + assert(data && n>0); + return data[n-1]; + } + + const T* begin(void) const + { return data; } + + T* begin(void) + { return data; } + + unsigned long capacity(void) const + { return max_n; } + + void clear(void) + { n=0; } + + bool empty(void) const + { return n==0; } + + const T* end(void) const + { return data+n; } + + T* end(void) + { return data+n; } + + void erase(unsigned long index) + { + assert(index0); + return *data; + } + + T& front(void) + { + assert(n>0); + return *data; + } + + void insert(unsigned long index, const T& entry) + { + assert(index<=n); + push_back(back()); + for(unsigned long i=n-1; i>index; --i) + data[i]=data[i-1]; + data[index]=entry; + } + + unsigned long max_size(void) const + { return max_n; } + + void pop_back(void) + { + assert(n>0); + --n; + } + + void push_back(const T& value) + { + assert(n& x) + { + std::swap(n, x.n); + std::swap(max_n, x.max_n); + std::swap(data, x.data); + } +}; + +// some common arrays + +typedef WrapArray1 WrapArray1d; +typedef WrapArray1 WrapArray1f; +typedef WrapArray1 WrapArray1ll; +typedef WrapArray1 WrapArray1ull; +typedef WrapArray1 WrapArray1i; +typedef WrapArray1 WrapArray1ui; +typedef WrapArray1 WrapArray1s; +typedef WrapArray1 WrapArray1us; +typedef WrapArray1 WrapArray1c; +typedef WrapArray1 WrapArray1uc; + +#endif diff --git a/third/SDFGen/array3.h b/third/SDFGen/array3.h new file mode 100644 index 0000000..92028ae --- /dev/null +++ b/third/SDFGen/array3.h @@ -0,0 +1,272 @@ +#ifndef ARRAY3_H +#define ARRAY3_H + +#include "array1.h" +#include +#include +#include + +template > +struct Array3 +{ + // STL-friendly typedefs + + typedef typename ArrayT::iterator iterator; + typedef typename ArrayT::const_iterator const_iterator; + typedef typename ArrayT::size_type size_type; + typedef long difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef typename ArrayT::reverse_iterator reverse_iterator; + typedef typename ArrayT::const_reverse_iterator const_reverse_iterator; + + // the actual representation + + int ni, nj, nk; + ArrayT a; + + // the interface + + Array3(void) + : ni(0), nj(0), nk(0) + {} + + Array3(int ni_, int nj_, int nk_) + : ni(ni_), nj(nj_), nk(nk_), a(ni_*nj_*nk_) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + Array3(int ni_, int nj_, int nk_, ArrayT& a_) + : ni(ni_), nj(nj_), nk(nk_), a(a_) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + Array3(int ni_, int nj_, int nk_, const T& value) + : ni(ni_), nj(nj_), nk(nk_), a(ni_*nj_*nk_, value) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + Array3(int ni_, int nj_, int nk_, const T& value, size_type max_n_) + : ni(ni_), nj(nj_), nk(nk_), a(ni_*nj_*nk_, value, max_n_) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + Array3(int ni_, int nj_, int nk_, T* data_) + : ni(ni_), nj(nj_), nk(nk_), a(ni_*nj_*nk_, data_) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + Array3(int ni_, int nj_, int nk_, T* data_, size_type max_n_) + : ni(ni_), nj(nj_), nk(nk_), a(ni_*nj_*nk_, data_, max_n_) + { assert(ni_>=0 && nj_>=0 && nk_>=0); } + + ~Array3(void) + { +#ifndef NDEBUG + ni=nj=0; +#endif + } + + const T& operator()(int i, int j, int k) const + { + assert(i>=0 && i=0 && j=0 && k=0 && i=0 && j=0 && k& x) const + { return ni==x.ni && nj==x.nj && nk==x.nk && a==x.a; } + + bool operator!=(const Array3& x) const + { return ni!=x.ni || nj!=x.nj || nk!=x.nk || a!=x.a; } + + bool operator<(const Array3& x) const + { + if(nix.ni) return false; + if(njx.nj) return false; + if(nkx.nk) return false; + return a(const Array3& x) const + { + if(ni>x.ni) return true; else if(nix.nj) return true; else if(njx.nk) return true; else if(nkx.a; + } + + bool operator<=(const Array3& x) const + { + if(nix.ni) return false; + if(njx.nj) return false; + if(nkx.nk) return false; + return a<=x.a; + } + + bool operator>=(const Array3& x) const + { + if(ni>x.ni) return true; else if(nix.nj) return true; else if(njx.nk) return true; else if(nk=x.a; + } + + void assign(const T& value) + { a.assign(value); } + + void assign(int ni_, int nj_, int nk_, const T& value) + { + a.assign(ni_*nj_*nk_, value); + ni=ni_; + nj=nj_; + nk=nk_; + } + + void assign(int ni_, int nj_, int nk_, const T* copydata) + { + a.assign(ni_*nj_*nk_, copydata); + ni=ni_; + nj=nj_; + nk=nk_; + } + + const T& at(int i, int j, int k) const + { + assert(i>=0 && i=0 && j=0 && k=0 && i=0 && j=0 && k=0 && nj_>=0 && nk_>=0); + a.resize(ni_*nj_*nk_); + ni=ni_; + nj=nj_; + nk=nk_; + } + + void resize(int ni_, int nj_, int nk_, const T& value) + { + assert(ni_>=0 && nj_>=0 && nk_>=0); + a.resize(ni_*nj_*nk_, value); + ni=ni_; + nj=nj_; + nk=nk_; + } + + void set_zero(void) + { a.set_zero(); } + + size_type size(void) const + { return a.size(); } + + void swap(Array3& x) + { + std::swap(ni, x.ni); + std::swap(nj, x.nj); + std::swap(nk, x.nk); + a.swap(x.a); + } + + void trim(void) + { a.trim(); } +}; + +// some common arrays + +typedef Array3 > Array3d; +typedef Array3 > Array3f; +typedef Array3 > Array3ll; +typedef Array3 > Array3ull; +typedef Array3 > Array3i; +typedef Array3 > Array3ui; +typedef Array3 > Array3s; +typedef Array3 > Array3us; +typedef Array3 > Array3c; +typedef Array3 > Array3uc; + +#endif diff --git a/third/SDFGen/makelevelset3.cpp b/third/SDFGen/makelevelset3.cpp new file mode 100644 index 0000000..92f2139 --- /dev/null +++ b/third/SDFGen/makelevelset3.cpp @@ -0,0 +1,184 @@ +#include "makelevelset3.h" + +// find distance x0 is from segment x1-x2 +static float point_segment_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2) +{ + Vec3f dx(x2-x1); + double m2=mag2(dx); + // find parameter value of closest point on segment + float s12=(float)(dot(x2-x0, dx)/m2); + if(s12<0){ + s12=0; + }else if(s12>1){ + s12=1; + } + // and find the distance + return dist(x0, s12*x1+(1-s12)*x2); +} + +// find distance x0 is from triangle x1-x2-x3 +static float point_triangle_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2, const Vec3f &x3) +{ + // first find barycentric coordinates of closest point on infinite plane + Vec3f x13(x1-x3), x23(x2-x3), x03(x0-x3); + float m13=mag2(x13), m23=mag2(x23), d=dot(x13,x23); + float invdet=1.f/max(m13*m23-d*d,1e-30f); + float a=dot(x13,x03), b=dot(x23,x03); + // the barycentric coordinates themselves + float w23=invdet*(m23*a-d*b); + float w31=invdet*(m13*b-d*a); + float w12=1-w23-w31; + if(w23>=0 && w31>=0 && w12>=0){ // if we're inside the triangle + return dist(x0, w23*x1+w31*x2+w12*x3); + }else{ // we have to clamp to one of the edges + if(w23>0) // this rules out edge 2-3 for us + return min(point_segment_distance(x0,x1,x2), point_segment_distance(x0,x1,x3)); + else if(w31>0) // this rules out edge 1-3 + return min(point_segment_distance(x0,x1,x2), point_segment_distance(x0,x2,x3)); + else // w12 must be >0, ruling out edge 1-2 + return min(point_segment_distance(x0,x1,x3), point_segment_distance(x0,x2,x3)); + } +} + +static void check_neighbour(const std::vector &tri, const std::vector &x, + Array3f &phi, Array3i &closest_tri, + const Vec3f &gx, int i0, int j0, int k0, int i1, int j1, int k1) +{ + if(closest_tri(i1,j1,k1)>=0){ + unsigned int p, q, r; assign(tri[closest_tri(i1,j1,k1)], p, q, r); + float d=point_triangle_distance(gx, x[p], x[q], x[r]); + if(d &tri, const std::vector &x, + Array3f &phi, Array3i &closest_tri, const Vec3f &origin, float dx, + int di, int dj, int dk) +{ + int i0, i1; + if(di>0){ i0=1; i1=phi.ni; } + else{ i0=phi.ni-2; i1=-1; } + int j0, j1; + if(dj>0){ j0=1; j1=phi.nj; } + else{ j0=phi.nj-2; j1=-1; } + int k0, k1; + if(dk>0){ k0=1; k1=phi.nk; } + else{ k0=phi.nk-2; k1=-1; } + for(int k=k0; k!=k1; k+=dk) for(int j=j0; j!=j1; j+=dj) for(int i=i0; i!=i1; i+=di){ + Vec3f gx(i*dx+origin[0], j*dx+origin[1], k*dx+origin[2]); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i-di, j, k); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j-dj, k); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i-di, j-dj, k); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j, k-dk); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i-di, j, k-dk); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j-dj, k-dk); + check_neighbour(tri, x, phi, closest_tri, gx, i, j, k, i-di, j-dj, k-dk); + } +} + +// calculate twice signed area of triangle (0,0)-(x1,y1)-(x2,y2) +// return an SOS-determined sign (-1, +1, or 0 only if it's a truly degenerate triangle) +static int orientation(double x1, double y1, double x2, double y2, double &twice_signed_area) +{ + twice_signed_area=y1*x2-x1*y2; + if(twice_signed_area>0) return 1; + else if(twice_signed_area<0) return -1; + else if(y2>y1) return 1; + else if(y2x2) return 1; + else if(x1 &tri, const std::vector &x, + const Vec3f &origin, float dx, int ni, int nj, int nk, + Array3f &phi, const int exact_band) +{ + phi.resize(ni, nj, nk); + phi.assign((ni+nj+nk)*dx); // upper bound on distance + Array3i closest_tri(ni, nj, nk, -1); + Array3i intersection_count(ni, nj, nk, 0); // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k} + // we begin by initializing distances near the mesh, and figuring out intersection counts + Vec3f ijkmin, ijkmax; + for(unsigned int t=0; t &tri, const std::vector &x, + const Vec3f &origin, float dx, int nx, int ny, int nz, + Array3f &phi, const int exact_band=1); + +#endif diff --git a/third/SDFGen/util.h b/third/SDFGen/util.h new file mode 100644 index 0000000..c5758a1 --- /dev/null +++ b/third/SDFGen/util.h @@ -0,0 +1,470 @@ +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include +#include + +#ifndef M_PI +const double M_PI = 3.1415926535897932384626433832795; +#endif + +#ifdef WIN32 +#undef min +#undef max +#endif + +using std::min; +using std::max; +using std::swap; + +template +inline T sqr(const T& x) +{ return x*x; } + +template +inline T cube(const T& x) +{ return x*x*x; } + +template +inline T min(T a1, T a2, T a3) +{ return min(a1, min(a2, a3)); } + +template +inline T min(T a1, T a2, T a3, T a4) +{ return min(min(a1, a2), min(a3, a4)); } + +template +inline T min(T a1, T a2, T a3, T a4, T a5) +{ return min(min(a1, a2), min(a3, a4), a5); } + +template +inline T min(T a1, T a2, T a3, T a4, T a5, T a6) +{ return min(min(a1, a2), min(a3, a4), min(a5, a6)); } + +template +inline T max(T a1, T a2, T a3) +{ return max(a1, max(a2, a3)); } + +template +inline T max(T a1, T a2, T a3, T a4) +{ return max(max(a1, a2), max(a3, a4)); } + +template +inline T max(T a1, T a2, T a3, T a4, T a5) +{ return max(max(a1, a2), max(a3, a4), a5); } + +template +inline T max(T a1, T a2, T a3, T a4, T a5, T a6) +{ return max(max(a1, a2), max(a3, a4), max(a5, a6)); } + +template +inline void minmax(T a1, T a2, T& amin, T& amax) +{ + if(a1 +inline void minmax(T a1, T a2, T a3, T& amin, T& amax) +{ + if(a1 +inline void minmax(T a1, T a2, T a3, T a4, T& amin, T& amax) +{ + if(a1 +inline void minmax(T a1, T a2, T a3, T a4, T a5, T& amin, T& amax) +{ + //@@@ the logic could be shortcircuited a lot! + amin=min(a1,a2,a3,a4,a5); + amax=max(a1,a2,a3,a4,a5); +} + +template +inline void minmax(T a1, T a2, T a3, T a4, T a5, T a6, T& amin, T& amax) +{ + //@@@ the logic could be shortcircuited a lot! + amin=min(a1,a2,a3,a4,a5,a6); + amax=max(a1,a2,a3,a4,a5,a6); +} + +template +inline void update_minmax(T a1, T& amin, T& amax) +{ + if(a1amax) amax=a1; +} + +template +inline void sort(T &a, T &b, T &c) +{ + T temp; + if(a +inline T clamp(T a, T lower, T upper) +{ + if(aupper) return upper; + else return a; +} + +// only makes sense with T=float or double +template +inline T smooth_step(T r) +{ + if(r<0) return 0; + else if(r>1) return 1; + return r*r*r*(10+r*(-15+r*6)); +} + +// only makes sense with T=float or double +template +inline T smooth_step(T r, T r_lower, T r_upper, T value_lower, T value_upper) +{ return value_lower + smooth_step((r-r_lower)/(r_upper-r_lower)) * (value_upper-value_lower); } + +// only makes sense with T=float or double +template +inline T ramp(T r) +{ return smooth_step((r+1)/2)*2-1; } + +#ifdef WIN32 +inline int lround(double x) +{ + if(x>0) + return (x-floor(x)<0.5) ? (int)floor(x) : (int)ceil(x); + else + return (x-floor(x)<=0.5) ? (int)floor(x) : (int)ceil(x); +} + +inline double remainder(double x, double y) +{ + return x-std::floor(x/y+0.5)*y; +} +#endif + +inline unsigned int round_up_to_power_of_two(unsigned int n) +{ + int exponent=0; + --n; + while(n){ + ++exponent; + n>>=1; + } + return 1<1){ + ++exponent; + n>>=1; + } + return 1<>16); + i*=2654435769u; + i^=(i>>16); + i*=2654435769u; + return i; +} + +// the inverse of randhash +inline unsigned int unhash(unsigned int h) +{ + h*=340573321u; + h^=(h>>16); + h*=340573321u; + h^=(h>>16); + h*=340573321u; + h^=0xA3C59AC3u; + return h; +} + +// returns repeatable stateless pseudo-random number in [0,1] +inline double randhashd(unsigned int seed) +{ return randhash(seed)/(double)UINT_MAX; } +inline float randhashf(unsigned int seed) +{ return randhash(seed)/(float)UINT_MAX; } + +// returns repeatable stateless pseudo-random number in [a,b] +inline double randhashd(unsigned int seed, double a, double b) +{ return (b-a)*randhash(seed)/(double)UINT_MAX + a; } +inline float randhashf(unsigned int seed, float a, float b) +{ return ( (b-a)*randhash(seed)/(float)UINT_MAX + a); } + +inline int intlog2(int x) +{ + int exp=-1; + while(x){ + x>>=1; + ++exp; + } + return exp; +} + +template +inline void get_barycentric(T x, int& i, T& f, int i_low, int i_high) +{ + T s=std::floor(x); + i=(int)s; + if(ii_high-2){ + i=i_high-2; + f=1; + }else + f=(T)(x-s); +} + +template +inline S lerp(const S& value0, const S& value1, T f) +{ return (1-f)*value0 + f*value1; } + +template +inline S bilerp(const S& v00, const S& v10, + const S& v01, const S& v11, + T fx, T fy) +{ + return lerp(lerp(v00, v10, fx), + lerp(v01, v11, fx), + fy); +} + +template +inline S trilerp(const S& v000, const S& v100, + const S& v010, const S& v110, + const S& v001, const S& v101, + const S& v011, const S& v111, + T fx, T fy, T fz) +{ + return lerp(bilerp(v000, v100, v010, v110, fx, fy), + bilerp(v001, v101, v011, v111, fx, fy), + fz); +} + +template +inline S quadlerp(const S& v0000, const S& v1000, + const S& v0100, const S& v1100, + const S& v0010, const S& v1010, + const S& v0110, const S& v1110, + const S& v0001, const S& v1001, + const S& v0101, const S& v1101, + const S& v0011, const S& v1011, + const S& v0111, const S& v1111, + T fx, T fy, T fz, T ft) +{ + return lerp(trilerp(v0000, v1000, v0100, v1100, v0010, v1010, v0110, v1110, fx, fy, fz), + trilerp(v0001, v1001, v0101, v1101, v0011, v1011, v0111, v1111, fx, fy, fz), + ft); +} + +// f should be between 0 and 1, with f=0.5 corresponding to balanced weighting between w0 and w2 +template +inline void quadratic_bspline_weights(T f, T& w0, T& w1, T& w2) +{ + w0=T(0.5)*sqr(f-1); + w1=T(0.75)-sqr(f-T(0.5));; + w2=T(0.5)*sqr(f); +} + +// f should be between 0 and 1 +template +inline void cubic_interp_weights(T f, T& wneg1, T& w0, T& w1, T& w2) +{ + T f2(f*f), f3(f2*f); + wneg1=-T(1./3)*f+T(1./2)*f2-T(1./6)*f3; + w0=1-f2+T(1./2)*(f3-f); + w1=f+T(1./2)*(f2-f3); + w2=T(1./6)*(f3-f); +} + +template +inline S cubic_interp(const S& value_neg1, const S& value0, const S& value1, const S& value2, T f) +{ + T wneg1, w0, w1, w2; + cubic_interp_weights(f, wneg1, w0, w1, w2); + return wneg1*value_neg1 + w0*value0 + w1*value1 + w2*value2; +} + +template +void zero(std::vector& v) +{ for(int i=(int)v.size()-1; i>=0; --i) v[i]=0; } + +template +T abs_max(const std::vector& v) +{ + T m=0; + for(int i=(int)v.size()-1; i>=0; --i){ + if(std::fabs(v[i])>m) + m=std::fabs(v[i]); + } + return m; +} + +template +bool contains(const std::vector& a, T e) +{ + for(unsigned int i=0; i +void add_unique(std::vector& a, T e) +{ + for(unsigned int i=0; i +void insert(std::vector& a, unsigned int index, T e) +{ + a.push_back(a.back()); + for(unsigned int i=(unsigned int)a.size()-1; i>index; --i) + a[i]=a[i-1]; + a[index]=e; +} + +template +void erase(std::vector& a, unsigned int index) +{ + for(unsigned int i=index; i +void erase_swap(std::vector& a, unsigned int index) +{ + for(unsigned int i=index; i +void erase_unordered(std::vector& a, unsigned int index) +{ + a[index]=a.back(); + a.pop_back(); +} + +template +void erase_unordered_swap(std::vector& a, unsigned int index) +{ + swap(a[index], a.back()); + a.pop_back(); +} + +template +void find_and_erase_unordered(std::vector& a, const T& doomed_element) +{ + for(unsigned int i=0; i +void replace_once(std::vector& a, const T& old_element, const T& new_element) +{ + for(unsigned int i=0; i +void write_matlab(std::ostream& output, const std::vector& a, const char *variable_name, bool column_vector=true, int significant_digits=18) +{ + output< +#include +#include +#include "util.h" + +// Defines a thin wrapper around fixed size C-style arrays, using template parameters, +// which is useful for dealing with vectors of different dimensions. +// For example, float[3] is equivalent to Vec<3,float>. +// Entries in the vector are accessed with the overloaded [] operator, so +// for example if x is a Vec<3,float>, then the middle entry is x[1]. +// For convenience, there are a number of typedefs for abbreviation: +// Vec<3,float> -> Vec3f +// Vec<2,int> -> Vec2i +// and so on. +// Arithmetic operators are appropriately overloaded, and functions are defined +// for additional operations (such as dot-products, norms, cross-products, etc.) + +template +struct Vec +{ + T v[N]; + + Vec(void) + {} + + explicit Vec(T value_for_all) + { for(unsigned int i=0; i + explicit Vec(const S *source) + { for(unsigned int i=0; i + explicit Vec(const Vec& source) + { for(unsigned int i=0; i(T v0, T v1) + { + assert(N==2); + v[0]=v0; v[1]=v1; + } + + Vec(T v0, T v1, T v2) + { + assert(N==3); + v[0]=v0; v[1]=v1; v[2]=v2; + } + + Vec(T v0, T v1, T v2, T v3) + { + assert(N==4); + v[0]=v0; v[1]=v1; v[2]=v2; v[3]=v3; + } + + Vec(T v0, T v1, T v2, T v3, T v4) + { + assert(N==5); + v[0]=v0; v[1]=v1; v[2]=v2; v[3]=v3; v[4]=v4; + } + + Vec(T v0, T v1, T v2, T v3, T v4, T v5) + { + assert(N==6); + v[0]=v0; v[1]=v1; v[2]=v2; v[3]=v3; v[4]=v4; v[5]=v5; + } + + T &operator[](int index) + { + assert(0<=index && (unsigned int)index operator+=(const Vec &w) + { + for(unsigned int i=0; i operator+(const Vec &w) const + { + Vec sum(*this); + sum+=w; + return sum; + } + + Vec operator-=(const Vec &w) + { + for(unsigned int i=0; i operator-(void) const // unary minus + { + Vec negative; + for(unsigned int i=0; i operator-(const Vec &w) const // (binary) subtraction + { + Vec diff(*this); + diff-=w; + return diff; + } + + Vec operator*=(T a) + { + for(unsigned int i=0; i operator*(T a) const + { + Vec w(*this); + w*=a; + return w; + } + + Vec operator*=(const Vec &w) + { + for(unsigned int i=0; i operator*(const Vec &w) const + { + Vec componentwise_product; + for(unsigned int i=0; i operator/=(T a) + { + for(unsigned int i=0; i operator/(T a) const + { + Vec w(*this); + w/=a; + return w; + } +}; + +typedef Vec<2,double> Vec2d; +typedef Vec<2,float> Vec2f; +typedef Vec<2,int> Vec2i; +typedef Vec<2,unsigned int> Vec2ui; +typedef Vec<2,short> Vec2s; +typedef Vec<2,unsigned short> Vec2us; +typedef Vec<2,char> Vec2c; +typedef Vec<2,unsigned char> Vec2uc; + +typedef Vec<3,double> Vec3d; +typedef Vec<3,float> Vec3f; +typedef Vec<3,int> Vec3i; +typedef Vec<3,unsigned int> Vec3ui; +typedef Vec<3,short> Vec3s; +typedef Vec<3,unsigned short> Vec3us; +typedef Vec<3,char> Vec3c; +typedef Vec<3,unsigned char> Vec3uc; + +typedef Vec<4,double> Vec4d; +typedef Vec<4,float> Vec4f; +typedef Vec<4,int> Vec4i; +typedef Vec<4,unsigned int> Vec4ui; +typedef Vec<4,short> Vec4s; +typedef Vec<4,unsigned short> Vec4us; +typedef Vec<4,char> Vec4c; +typedef Vec<4,unsigned char> Vec4uc; + +typedef Vec<6,double> Vec6d; +typedef Vec<6,float> Vec6f; +typedef Vec<6,unsigned int> Vec6ui; +typedef Vec<6,int> Vec6i; +typedef Vec<6,short> Vec6s; +typedef Vec<6,unsigned short> Vec6us; +typedef Vec<6,char> Vec6c; +typedef Vec<6,unsigned char> Vec6uc; + + +template +T mag2(const Vec &a) +{ + T l=sqr(a.v[0]); + for(unsigned int i=1; i +T mag(const Vec &a) +{ return sqrt(mag2(a)); } + +template +inline T dist2(const Vec &a, const Vec &b) +{ + T d=sqr(a.v[0]-b.v[0]); + for(unsigned int i=1; i +inline T dist(const Vec &a, const Vec &b) +{ return std::sqrt(dist2(a,b)); } + +template +inline void normalize(Vec &a) +{ a/=mag(a); } + +template +inline Vec normalized(const Vec &a) +{ return a/mag(a); } + +template +inline T infnorm(const Vec &a) +{ + T d=std::fabs(a.v[0]); + for(unsigned int i=1; i +void zero(Vec &a) +{ + for(unsigned int i=0; i +std::ostream &operator<<(std::ostream &out, const Vec &v) +{ + out< +std::istream &operator>>(std::istream &in, Vec &v) +{ + in>>v.v[0]; + for(unsigned int i=1; i>v.v[i]; + return in; +} + +template +inline bool operator==(const Vec &a, const Vec &b) +{ + bool t = (a.v[0] == b.v[0]); + unsigned int i=1; + while(i +inline bool operator!=(const Vec &a, const Vec &b) +{ + bool t = (a.v[0] != b.v[0]); + unsigned int i=1; + while(i +inline Vec operator*(T a, const Vec &v) +{ + Vec w(v); + w*=a; + return w; +} + +template +inline T min(const Vec &a) +{ + T m=a.v[0]; + for(unsigned int i=1; i +inline Vec min_union(const Vec &a, const Vec &b) +{ + Vec m; + for(unsigned int i=0; i +inline Vec max_union(const Vec &a, const Vec &b) +{ + Vec m; + for(unsigned int i=0; i b.v[i]) ? m.v[i]=a.v[i] : m.v[i]=b.v[i]; + return m; +} + +template +inline T max(const Vec &a) +{ + T m=a.v[0]; + for(unsigned int i=1; im) m=a.v[i]; + return m; +} + +template +inline T dot(const Vec &a, const Vec &b) +{ + T d=a.v[0]*b.v[0]; + for(unsigned int i=1; i +inline Vec<2,T> rotate(const Vec<2,T>& a, float angle) +{ + T c = cos(angle); + T s = sin(angle); + return Vec<2,T>(c*a[0] - s*a[1],s*a[0] + c*a[1]); // counter-clockwise rotation +} + +template +inline Vec<2,T> perp(const Vec<2,T> &a) +{ return Vec<2,T>(-a.v[1], a.v[0]); } // counter-clockwise rotation by 90 degrees + +template +inline T cross(const Vec<2,T> &a, const Vec<2,T> &b) +{ return a.v[0]*b.v[1]-a.v[1]*b.v[0]; } + +template +inline Vec<3,T> cross(const Vec<3,T> &a, const Vec<3,T> &b) +{ return Vec<3,T>(a.v[1]*b.v[2]-a.v[2]*b.v[1], a.v[2]*b.v[0]-a.v[0]*b.v[2], a.v[0]*b.v[1]-a.v[1]*b.v[0]); } + +template +inline T triple(const Vec<3,T> &a, const Vec<3,T> &b, const Vec<3,T> &c) +{ return a.v[0]*(b.v[1]*c.v[2]-b.v[2]*c.v[1]) + +a.v[1]*(b.v[2]*c.v[0]-b.v[0]*c.v[2]) + +a.v[2]*(b.v[0]*c.v[1]-b.v[1]*c.v[0]); } + +template +inline unsigned int hash(const Vec &a) +{ + unsigned int h=a.v[0]; + for(unsigned int i=1; i +inline void assign(const Vec &a, T &a0, T &a1) +{ + assert(N==2); + a0=a.v[0]; a1=a.v[1]; +} + +template +inline void assign(const Vec &a, T &a0, T &a1, T &a2) +{ + assert(N==3); + a0=a.v[0]; a1=a.v[1]; a2=a.v[2]; +} + +template +inline void assign(const Vec &a, T &a0, T &a1, T &a2, T &a3) +{ + assert(N==4); + a0=a.v[0]; a1=a.v[1]; a2=a.v[2]; a3=a.v[3]; +} + +template +inline void assign(const Vec &a, T &a0, T &a1, T &a2, T &a3, T &a4, T &a5) +{ + assert(N==6); + a0=a.v[0]; a1=a.v[1]; a2=a.v[2]; a3=a.v[3]; a4=a.v[4]; a5=a.v[5]; +} + +template +inline Vec round(const Vec &a) +{ + Vec rounded; + for(unsigned int i=0; i +inline Vec floor(const Vec &a) +{ + Vec rounded; + for(unsigned int i=0; i +inline Vec ceil(const Vec &a) +{ + Vec rounded; + for(unsigned int i=0; i +inline Vec fabs(const Vec &a) +{ + Vec result; + for(unsigned int i=0; i +inline void minmax(const Vec &x0, const Vec &x1, Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i +inline void minmax(const Vec &x0, const Vec &x1, const Vec &x2, Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i +inline void minmax(const Vec &x0, const Vec &x1, const Vec &x2, const Vec &x3, + Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i +inline void minmax(const Vec &x0, const Vec &x1, const Vec &x2, const Vec &x3, const Vec &x4, + Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i +inline void minmax(const Vec &x0, const Vec &x1, const Vec &x2, const Vec &x3, const Vec &x4, + const Vec &x5, Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i +inline void update_minmax(const Vec &x, Vec &xmin, Vec &xmax) +{ + for(unsigned int i=0; i