diff --git a/src/mesh_fix/include/Kernel/basics.h b/src/mesh_fix/include/Kernel/basics.h index 809f81b391..a6cea20329 100644 --- a/src/mesh_fix/include/Kernel/basics.h +++ b/src/mesh_fix/include/Kernel/basics.h @@ -31,7 +31,9 @@ #ifndef _BASICS_H #define _BASICS_H +#include #include +#include #include #include #include @@ -138,163 +140,80 @@ inline void p_swap(void **a, void **b) {void *t = *a; *a = *b; *b = t;} ///////////////////////////////////////////////////////////////////////////////////////////// +typedef int64_t j_voidint; -template -class Primitive { -protected: - T value; - -public: - - // we must type cast to child to so - // a += 3 += 5 ... and etc.. work the same way - // as on primitives - Child &childRef(){ - return *((Child*)this); - } - - // you can overload to give a default value if you want - Primitive(){} - explicit Primitive(T v):value(v){} - - T get(){ - return value; - } - - #define OP(op) Child &operator op(Child const &v){\ - value op v.value; \ - return childRef(); \ - }\ - Child &operator op(T const &v){\ - value op v; \ - return childRef(); \ - } - - // all with equals - OP(+=) - OP(-=) - OP(*=) - OP(/=) - OP(<<=) - OP(>>=) - OP(|=) - OP(^=) - OP(&=) - OP(%=) - - #undef OP - - #define OP(p) Child operator p(Child const &v){\ - Child other = childRef();\ - other p ## = v;\ - return other;\ - }\ - Child operator p(T const &v){\ - Child other = childRef();\ - other p ## = v;\ - return other;\ - } - - OP(+) - OP(-) - OP(*) - OP(/) - OP(<<) - OP(>>) - OP(|) - OP(^) - OP(&) - OP(%) - - #undef OP - - - #define OP(p) bool operator p(Child const &v){\ - return value p v.value;\ - }\ - bool operator p(T const &v){\ - return value p v;\ - } - - OP(&&) - OP(||) - OP(<) - OP(<=) - OP(>) - OP(>=) - OP(==) - OP(!=) - - #undef OP - - Child operator +(){return Child(value);} - Child operator -(){return Child(-value);} - Child &operator ++(){++value; return childRef();} - Child operator ++(int){ - Child ret(value); - ++value; - return childRef(); - } - Child operator --(int){ - Child ret(value); - --value; - return childRef(); - } - - bool operator!(){return !value;} - Child operator~(){return Child(~value);} - -}; - - +// void* replacement class Data { -public: - virtual ~Data() = default; -}; + std::function delete_object_func = [](int64_t){}; + int64_t value = 0; // either pointer, or numeric value -class intWrapper: public Data { -private: - int val; - public: - intWrapper(int val = 0) : - val(val) { - } - operator int &() { - return val; - } - int* operator &() { - return &val; - } - operator int() const { - return val; - } - operator int*() { - return &val; - } -}; - -class doubleWrapper: public Data, public Primitive { public: - doubleWrapper(double val = 0) { - this->value = val; + Data() { + delete_object_func = [](int64_t){}; } - operator double &() { + + Data(void* ptr) = delete; + + template + Data(S* ptr) { + delete_object_func = [](int64_t p){ + delete reinterpret_cast(p); + }; + value = reinterpret_cast(ptr); + } + + operator void*() = delete; + + template + operator S*() const { + return reinterpret_cast(value); + } + + bool empty() const { + return value == 0; + } + + bool notEmpty() const { + return value != 0; + } + + + bool operator==(const Data &d) const { + return value == d.value; + } + + bool operator!=(const Data &d) const { + return value != d.value; + } + + template + bool operator!=(const S* ptr) const { + return value != reinterpret_cast(ptr); + } + + operator int64_t() const { return value; } - double* operator &() { - return &value; + + Data& operator=(int64_t val) { + delete_object_func = [](int64_t){}; + value = val; + return *this; } - operator double() const { - return value; + + void clear() { + if (value != 0) { + delete_object_func(value); + } + forget(); } - operator double*() { - return &value; + + void forget() { + delete_object_func = [](int64_t) {}; + value = 0; } }; -inline int to_int(Data *d) { - return static_cast(d)->operator int(); -} } //namespace T_MESH diff --git a/src/mesh_fix/include/Kernel/coordinates.h b/src/mesh_fix/include/Kernel/coordinates.h index d58d279c42..0d42228dfd 100644 --- a/src/mesh_fix/include/Kernel/coordinates.h +++ b/src/mesh_fix/include/Kernel/coordinates.h @@ -149,10 +149,10 @@ PM_Rational ceil(const PM_Rational& a); PM_Rational floor(const PM_Rational& a); PM_Rational round(const PM_Rational& a); -/**************** I/O operators ****************/ - -inline std::ostream & operator<<(std::ostream &o, const PM_Rational& c) { return o << c.toRational(); } -inline std::istream & operator>>(std::istream &i, PM_Rational& c) { EXACT_NT a; i >> a; c.setFromRational(a); return i; } +/**************** I/O operators ****************/ + +inline std::ostream & operator<<(std::ostream &o, const PM_Rational& c) { return o << c.toRational(); } +inline std::istream & operator>>(std::istream &i, PM_Rational& c) { EXACT_NT a; i >> a; c.setFromRational(a); return i; } #define TMESH_TO_DOUBLE(x) ((x).toDouble()) #define TMESH_TO_FLOAT(x) ((x).toFloat()) diff --git a/src/mesh_fix/include/Kernel/graph.h b/src/mesh_fix/include/Kernel/graph.h index 2fcd1f5968..91165a911e 100644 --- a/src/mesh_fix/include/Kernel/graph.h +++ b/src/mesh_fix/include/Kernel/graph.h @@ -39,7 +39,7 @@ namespace T_MESH //! Base class type for nodes of non-oriented graphs -class graphNode : public Data +class graphNode { public: @@ -56,13 +56,13 @@ class graphNode : public Data bool isIsolated() {return (edges.numels()==0);} //! Returns the edge connecting this with 'n'. NULL if not connected. O(degree). - class graphEdge *getEdge(graphNode *n); + class graphEdge *getEdge(graphNode *n); }; //! Base class type for edges of non-oriented graphs -class graphEdge : public Data +class graphEdge { public: diff --git a/src/mesh_fix/include/Kernel/heap.h b/src/mesh_fix/include/Kernel/heap.h index 4768089bf3..05328df4fe 100644 --- a/src/mesh_fix/include/Kernel/heap.h +++ b/src/mesh_fix/include/Kernel/heap.h @@ -54,10 +54,9 @@ namespace T_MESH class abstractHeap { protected: - Data **heap; //!< Heap data is stored here + Data *heap; //!< Heap data is stored here int numels; //!< Current number of elements int maxels; //!< Maximum number of elements - int *positions; //!< Optional pointer to an array of positions int upheap(int i); //!< Moves the i'th object up on the heap int downheap(int i); //!< Moves the i'th object down on the heap @@ -67,7 +66,7 @@ class abstractHeap //! This function must be implemented in the extended class. //! The return value must be <0 if a0 if a>b or 0 if a=b. - virtual int compare(const Data *a, const Data *b) = 0; + virtual int compare(const Data& a, const Data& b) = 0; public : @@ -81,11 +80,11 @@ class abstractHeap //! returned, otherwise the index position of the newly inserted element is //! returned. - int insert(Data *e); + int insert(const Data& e); int isEmpty() const {return (numels == 0);} //!< Returns TRUE if the heap is empty - Data *getHead() const {return heap[1];} //!< Returns the first element of the heap - Data *removeHead(); //!< Removes and returns the first element after rearranging the heap + Data getHead() const {return heap[1];} //!< Returns the first element of the heap + Data removeHead(); //!< Removes and returns the first element after rearranging the heap void flush() {numels=0;} //!< Removes all the elements }; diff --git a/src/mesh_fix/include/Kernel/jqsort.h b/src/mesh_fix/include/Kernel/jqsort.h index 57b4cc046d..a62074793e 100644 --- a/src/mesh_fix/include/Kernel/jqsort.h +++ b/src/mesh_fix/include/Kernel/jqsort.h @@ -41,10 +41,12 @@ //! less than, equal to, or greater than the second. If two members //! compare as equal, their order in the sorted array is undefined. //! See the manpage of the standard library qsort() function for further information. + +#include "basics.h" namespace T_MESH { -extern void jqsort(Data *v[], int numels, int (*comp)(const Data *, const Data *)); +extern void jqsort(Data *v, int numels, int (*comp)(const Data&, const Data&)); } //namespace T_MESH diff --git a/src/mesh_fix/include/Kernel/list.h b/src/mesh_fix/include/Kernel/list.h index ba2c77d723..81e154abf8 100644 --- a/src/mesh_fix/include/Kernel/list.h +++ b/src/mesh_fix/include/Kernel/list.h @@ -28,156 +28,155 @@ * * ****************************************************************************/ -#ifndef _JLIST_H -#define _JLIST_H - -#include -#include "basics.h" - -namespace T_MESH -{ - -///////////////////////////////////////////////////////////////////////////////////////////// - -//! Generic node of a doubly likned list. - -class Node -{ - friend class List; // This is to make methods in 'List' able to modify n_prev and n_next - - public : - Data *data; //!< Actual data stored in the node - - //! Creates an isolated node storing 'd' - Node(const void *d) {data=(Data *)d; n_prev=n_next=NULL;} - - //! Creates a new node storing 'd' and links it to a previous node 'p' and to a next one 'n'. - Node(const Node *p, const Data *d, const Node *n); - ~Node(); //!< Standard destructor - - inline Node *prev() const {return n_prev;} //!< Returns the previous node in the list, possibly NULL - inline Node *next() const {return n_next;} //!< Returns the next node in the list, possibly NULL - - protected: - Node *n_prev,*n_next; //!< Previous and next node pointers -}; - - -///////////////////////////////////////////////////////////////////////////////////////////// - -//! Doubly linked list. - - -class List : public Data -{ - protected : - - Node *l_head; //!< First node pointer - Node *l_tail; //!< Last node pointer - int l_numels; //!< Number of elements in the list - - public : - - //! Creates an empty list - List() {l_head = l_tail = NULL; l_numels = 0;} - - //! Creates a list containing an element 'd' (singleton) - List(const Data *d) {l_head = l_tail = new Node(d); l_numels = 1;} - - //! Creates a list out of an array 'd' made of 'n' elements. - List(const Data **d, int n); - - //! Creates a duplicated list. - List(List& l) {l_head = l_tail = NULL; l_numels = 0; appendList(&l);} - - //! Creates a duplicated list. - List(List* l) {l_head = l_tail = NULL; l_numels = 0; appendList(l);} - - //! Destructor - ~List(); - - Node *head() const {return l_head;} //!< Gets the first node, NULL if empty. \n O(1). - Node *tail() const {return l_tail;} //!< Gets the last node, NULL if empty. \n O(1). - int numels() const {return l_numels;} //!< Gets the number of elements. \n O(1). - - void appendHead(const Data *d); //!< Appends a new node storing 'd' to the head. \n O(1). - void appendTail(const Data *d); //!< Appends a new node storing 'd' to the tail. \n O(1). - void insertAfter(Node *n, const Data *d); //! Inserts a new node storing 'd' right after 'n'. \n O(1). - - //! Deletes and removes the node containing 'd'. Returns its position, 0 if 'd' is not in the list. \n O(numels()). - int removeNode(const Data *d); - - //! Deletes and i'th node (starting from 0). Returns 0 if the list has less than i+1 nodes. \n O(numels()). - int removeNode(int i); - - //! Returns the node at position 'i' (starting from 0). Returns NULL if the list has less than i+1 nodes. \n O(numels()). - Node *getNode(int i) const; - - //! Deletes and removes the node 'n' from the list. \n O(1). - void removeCell(Node *n); - - //! Appends a list 'l' to the head by duplicating nodes in 'l'. \n O(l->numels()). - void appendList(const List *l); - - //! Appends a list 'l' to the tail by linking the first node of 'l' to the last one of this list. 'l' becomes empty. \n O(1). - void joinTailList(List *l); - - //! Moves node 'n' from this list to the end of 'l'. \n O(1). - void moveNodeTo(Node *n, List *l); - - Data *popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1). - Data *popTail(); //!< Deletes and removes the last node. Returns its data. \n O(1). - - //! Deletes and removes the node 'n' from the list and frees data memory. \n O(1). +#ifndef _JLIST_H +#define _JLIST_H + +#include +#include "basics.h" + +namespace T_MESH +{ + +///////////////////////////////////////////////////////////////////////////////////////////// + +//! Generic node of a doubly likned list. + +class Node +{ + friend class List; // This is to make methods in 'List' able to modify n_prev and n_next + + public : + Data data; //!< Actual data stored in the node + + //! Creates an isolated node storing 'd' + Node(const Data& d) {data=d; n_prev=n_next=NULL;} + + //! Creates a new node storing 'd' and links it to a previous node 'p' and to a next one 'n'. + Node(const Node *p, const Data& d, const Node *n); + ~Node(); //!< Standard destructor + + inline Node *prev() const {return n_prev;} //!< Returns the previous node in the list, possibly NULL + inline Node *next() const {return n_next;} //!< Returns the next node in the list, possibly NULL + + protected: + Node *n_prev,*n_next; //!< Previous and next node pointers +}; + + +///////////////////////////////////////////////////////////////////////////////////////////// + +//! Doubly linked list. + + +class List +{ + protected : + + Node *l_head; //!< First node pointer + Node *l_tail; //!< Last node pointer + int l_numels; //!< Number of elements in the list + + public : + + //! Creates an empty list + List() {l_head = l_tail = NULL; l_numels = 0;} + + //! Creates a list containing an element 'd' (singleton) + List(const Data& d) {l_head = l_tail = new Node(d); l_numels = 1;} + + //! Creates a list out of an array 'd' made of 'n' elements. + List(const Data *d, int n); + + //! Creates a duplicated list. + List(List& l) {l_head = l_tail = NULL; l_numels = 0; appendList(&l);} + + //! Creates a duplicated list. + List(List* l) {l_head = l_tail = NULL; l_numels = 0; appendList(l);} + + //! Destructor + ~List(); + + Node *head() const {return l_head;} //!< Gets the first node, NULL if empty. \n O(1). + Node *tail() const {return l_tail;} //!< Gets the last node, NULL if empty. \n O(1). + int numels() const {return l_numels;} //!< Gets the number of elements. \n O(1). + + void appendHead(const Data& d); //!< Appends a new node storing 'd' to the head. \n O(1). + void appendTail(const Data& d); //!< Appends a new node storing 'd' to the tail. \n O(1). + void insertAfter(Node *n, const Data& d); //! Inserts a new node storing 'd' right after 'n'. \n O(1). + + //! Deletes and removes the node containing 'd'. Returns its position, 0 if 'd' is not in the list. \n O(numels()). + int removeNode(const Data& d); + + //! Deletes and i'th node (starting from 0). Returns 0 if the list has less than i+1 nodes. \n O(numels()). + int removeNode(int i); + + //! Returns the node at position 'i' (starting from 0). Returns NULL if the list has less than i+1 nodes. \n O(numels()). + Node *getNode(int i) const; + + //! Deletes and removes the node 'n' from the list. \n O(1). + void removeCell(Node *n); + + //! Appends a list 'l' to the head by duplicating nodes in 'l'. \n O(l->numels()). + void appendList(const List *l); + + //! Appends a list 'l' to the tail by linking the first node of 'l' to the last one of this list. 'l' becomes empty. \n O(1). + void joinTailList(List *l); + + //! Moves node 'n' from this list to the end of 'l'. \n O(1). + void moveNodeTo(Node *n, List *l); + + Data popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1). + Data popTail(); //!< Deletes and removes the last node. Returns its data. \n O(1). + + //! Deletes and removes the node 'n' from the list and frees data memory. \n O(1). + + //! Warning. This method uses the free() function to to dispose the memory space + //! used by the data stored in the node. This means that such data should have + //! been allocated through malloc(), calloc() or realloc(), and not through the + //! 'new' operator. On some systems, however, the 'delete' operator simply calls 'free()' + //! right after the execution of the proper object destructor so, if the object + //! does not need to free internally allocated memory, it is safe to dispose the + //! memory trhough free() although the object was allocated by 'new'. This works + //! on Linux Fedora Core 2 distributions. + void freeCell(Node *n); + + //! Deletes and removes the node storing 'd' and frees the memory occupied by 'd' itself. \n O(numels()). + + //! Warning. Read the comment for the method 'freeCell()' + void freeNode(const Data& d); + + //! Returns the node storing 'd'. NULL if not found. \n O(numels()). + Node *containsNode(const Data& d) const; + + //! Replaces old_n with new_n. The Node containing new_n is returned. \n O(numels()). + Node *replaceNode(const Data& old_n, const Data& new_n); + + //! Deletes and removes all the nodes and frees data memory. \n O(numels()). + + //! Warning. Read the comment for the method 'freeCell()' + void freeNodes(); + + void removeNodes(); //!< Deletes and removes all the nodes. \n O(numels()). + + Data *toArray() const; //!< Creates an array out of the list. \n O(numels()). + + //! Sorts the list using 'comp' as comparison function for two elements. \n O(numels()^2). + + //! This method uses the QuickSort algorithm for sorting, thus the complexity is N^2 in the + //! worst case, but it is actually much faster in the average case. If, however, there is + //! the need to have a guaranteed O(NlogN) complexity, it is possible to implement a heap + //! based on the 'abstractHeap' class. See the documentation of the standard 'qsort' library + //! function for details on the prototype of the comparison function 'comp'. + int sort(int (*comp)(const Data&, const Data&)); +}; + +//! Convenience macro to scan the nodes of a list. +#define FOREACHNODE(l, n) for ((n) = (l).head(); (n) != NULL; (n)=(n)->next()) + +//! Convenience macro to circulate around the nodes of a list 'l' starting from node 'm'. Must exit with break or return. +#define FOREACHNODECIRCULAR(l, m, n) for ((n) = (m); ; (n)=((n)!=(l).tail())?((n)->next()):((l).head())) - // NOTE: The following is not true after refactoring, void* has been replaced with Data* - //! Warning. This method uses the free() function to to dispose the memory space - //! used by the data stored in the node. This means that such data should have - //! been allocated through malloc(), calloc() or realloc(), and not through the - //! 'new' operator. On some systems, however, the 'delete' operator simply calls 'free()' - //! right after the execution of the proper object destructor so, if the object - //! does not need to free internally allocated memory, it is safe to dispose the - //! memory trhough free() although the object was allocated by 'new'. This works - //! on Linux Fedora Core 2 distributions. - void freeCell(Node *n); - - //! Deletes and removes the node storing 'd' and frees the memory occupied by 'd' itself. \n O(numels()). - - //! Warning. Read the comment for the method 'freeCell()' - void freeNode(Data *d); - - //! Returns the node storing 'd'. NULL if not found. \n O(numels()). - Node *containsNode(const Data *d) const; - - //! Replaces old_n with new_n. The Node containing new_n is returned. \n O(numels()). - Node *replaceNode(const Data *old_n, const Data *new_n); - - //! Deletes and removes all the nodes and frees data memory. \n O(numels()). - - //! Warning. Read the comment for the method 'freeCell()' - void freeNodes(); - - void removeNodes(); //!< Deletes and removes all the nodes. \n O(numels()). - - Data **toArray() const; //!< Creates an array out of the list. \n O(numels()). - - //! Sorts the list using 'comp' as comparison function for two elements. \n O(numels()^2). - - //! This method uses the QuickSort algorithm for sorting, thus the complexity is N^2 in the - //! worst case, but it is actually much faster in the average case. If, however, there is - //! the need to have a guaranteed O(NlogN) complexity, it is possible to implement a heap - //! based on the 'abstractHeap' class. See the documentation of the standard 'qsort' library - //! function for details on the prototype of the comparison function 'comp'. - int sort(int (*comp)(const Data *, const Data *)); -}; - -//! Convenience macro to scan the nodes of a list. -#define FOREACHNODE(l, n) for ((n) = (l).head(); (n) != NULL; (n)=(n)->next()) - -//! Convenience macro to circulate around the nodes of a list 'l' starting from node 'm'. Must exit with break or return. -#define FOREACHNODECIRCULAR(l, m, n) for ((n) = (m); ; (n)=((n)!=(l).tail())?((n)->next()):((l).head())) - } //namespace T_MESH - -#endif // _JLIST_H - + +#endif // _JLIST_H + diff --git a/src/mesh_fix/include/Kernel/point.h b/src/mesh_fix/include/Kernel/point.h index c35dbcb38f..b216ea4350 100644 --- a/src/mesh_fix/include/Kernel/point.h +++ b/src/mesh_fix/include/Kernel/point.h @@ -28,272 +28,272 @@ * * ****************************************************************************/ -#ifndef _POINT_H -#define _POINT_H - -#include "basics.h" - -namespace T_MESH -{ - -//! Orientation predicates using filtering on doubles -extern "C" double orient2d(double *, double *, double *); -extern "C" double orient3d(double *, double *, double *, double *); - -//! Orientation predicates on PM_Rationals +#ifndef _POINT_H +#define _POINT_H + +#include "basics.h" + +namespace T_MESH +{ + +//! Orientation predicates using filtering on doubles +extern "C" double orient2d(double *, double *, double *); +extern "C" double orient3d(double *, double *, double *, double *); + +//! Orientation predicates on PM_Rationals // orient2D: >0 =0 <0 if (p,q,r) are CCW, aligned, CW respectively PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry); - - -//! Geometric point definition - -//! This class represents a point in the Euclidean 3D space. It can be used -//! to represent 3D vectors originating at (0,0,0) and terminating at the -//! corresponding point. Several methods of this class are intended to -//! manipulate vectors rather than points; for example, a call of the -//! method normalize is an actual normalization if the object is a vector, -//! but it has to be intended as a projection on the unit sphere if the -//! object is intended to be a point. An object of type Point is a triplet -//! (x,y,z) of coordinates endowed with a pointer 'info' to possible additional -//! information. Each coordinate is a number of type 'coord' which, by -//! default, is a standard double. Operations on points include addition, -//! subtraction, cross and dot product, and many others. This class implements -//! several useful operations using vector arithmethic. For example, -//! the simple piece of code "A = B*C;" assignes to A the value of the dot -//! product of B and C. -//! Nearly zero or nearly flat angles are automatically snapped to -//! exactly zero and exactly flat angles if the difference is smaller -//! than the global variable _acos_tolerance. This is the very basic application -//! of our version of the epsilon geometry for robust computation. - - -class Point : public Data -{ - public : - coord x,y,z; //!< Coordinates - Data *info; //!< Further information - - //! Creates a new point with coordinates (0,0,0). - Point() {x = y = z = 0; info = NULL;} - - //! Creates a new point with the same coordinates as 's'. The info field is not copied. - Point(const Point *s) {x = s->x; y = s->y; z = s->z; info = NULL;} - - //! Creates a new point with the same coordinates as 's'. The info field is not copied. - Point(const Point& s) {x = s.x; y = s.y; z = s.z; info = NULL;} - - //! Creates a new point with coordinates (a,b,c). - Point(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c; info = NULL;} - - //! Do not remove this. It makes the compiler produce a vtable for this object. - TMESH_VIRTUAL bool isPoint() const { return true; } - - //! Set the coordinates to (a,b,c). - void setValue(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c;} - - //! Set the coordinates as those of 'p' - void setValue(const Point& p) {x = p.x; y = p.y; z = p.z;} - - //! Set the coordinates as those of '*p' - void setValue(const Point *p) {x = p->x; y = p->y; z = p->z;} - - //! Returns the vector difference - Point operator-(const Point& p) const {return Point(x-p.x, y-p.y, z-p.z);} - - //! Returns the vector sum - Point operator+(const Point& p) const {return Point(x+p.x, y+p.y, z+p.z);} - - //! Sums another point - void operator+=(const Point& p) {x+=p.x; y+=p.y; z+=p.z;} - - //! Subtracts another point - void operator-=(const Point& p) {x-=p.x; y-=p.y; z-=p.z;} - - //! Returns the Cross Product - Point operator&(const Point& p) const {return Point(y*p.z-z*p.y, z*p.x-x*p.z, x*p.y-y*p.x);} - - //! Returns the Dot Product - coord operator*(const Point& p) const {return (x*p.x+y*p.y+z*p.z);} - - //! Returns the product with a scalar - Point operator*(const coord& d) const {return Point(x*d,y*d,z*d);} - - //! Multiplies by a scalar - void operator*=(const coord& m) { x *= m; y *= m; z *= m; } - - //! Divides by a scalar - void operator/=(const coord& m) { x /= m; y /= m; z /= m; } - - //! Returns the vector divided by the scalar - Point operator/(const coord& d) const { return Point(x / d, y / d, z / d); } - - //! TRUE iff coordinates are equal - bool operator==(const Point& p) const {return (x==p.x && y==p.y && z==p.z);} - - //! FALSE iff coordinates are equal - bool operator!=(const Point& p) const {return (x!=p.x || y!=p.y || z!=p.z);} - - //! TRUE iff this is lexycographically smaller than s - bool operator<(const Point& s) const; - - //! Returns the i'th coordinate - inline coord& at(unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } - - //! Returns the i'th coordinate - inline coord& operator[](unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } - - //! Returns the inverse vector - Point inverse() const {return Point(-x,-y,-z);} - - //! Inverts the vector - void invert() {x=-x; y=-y; z=-z;} - - //! TRUE if vector is (0,0,0) - bool isNull() const {return (x==0 && y==0 && z==0);} - - //! Squared distance from origin - coord squaredLength() const {return (x*x + y*y + z*z);} - - //! Squared distance from '*b' - coord squaredDistance(const Point *b) const { return (((*(this)) - (*b)).squaredLength()); } - - //! Returns the solution of the linear system Ax = d, where A is a 3x3 matrix whose rows are row1, row2 and row3, d = this - Point linearSystem(const Point& row1, const Point& row2, const Point& row3); - - - //! Projects the vector on the plane with normal 'n' passing through the origin. - void project(const Point *n); - - //! Returns the projection of the point on the straight line though 'a' and 'b'. - Point projection(const Point *a, const Point *b) const; - - //! Prints the coordinates of the point to a file handler. stdout is the default. - void printPoint(FILE *fp = stdout) const { fprintf(fp, "%f %f %f,\n", TMESH_TO_FLOAT(x), TMESH_TO_FLOAT(y), TMESH_TO_FLOAT(z)); } // Debug - - - //! Exact orientation test. - //! Return value is positive iff the tetrahedron (this,a,b,c) has a positive volume; - //! It is negative iff the tetrahedron (this,a,b,c) has a negative volume; - //! It is zero iff the tetrahedron (this,a,b,c) has a zero volume. - coord exactOrientation(const Point *a, const Point *b, const Point *c) const; - coord side3D(const Point *p1, const Point *p2, const Point *p3) const { return exactOrientation(p1, p2, p3); } - - - //! Exact misalignment test. Returns TRUE iff points are not aligned. - bool exactMisalignment(const Point *a, const Point *b) const; - bool notAligned(const Point *a, const Point *b) const { return exactMisalignment(a,b); } - - //! Exact planar side test. Returns TRUE iff 'this', Q, A and B are coplanar - //! and 'this' and Q are (properly) on the same side of A-B. - //! Warning! Coplanarity is not checked, result is undetermined if - //! 'this', Q, A and B are not coplanar. - bool exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const; - - //! Itersection point between lines p-q and r-s. Return INFINITE_POINT if lineas are either parallel or degenerate. + + +//! Geometric point definition + +//! This class represents a point in the Euclidean 3D space. It can be used +//! to represent 3D vectors originating at (0,0,0) and terminating at the +//! corresponding point. Several methods of this class are intended to +//! manipulate vectors rather than points; for example, a call of the +//! method normalize is an actual normalization if the object is a vector, +//! but it has to be intended as a projection on the unit sphere if the +//! object is intended to be a point. An object of type Point is a triplet +//! (x,y,z) of coordinates endowed with a pointer 'info' to possible additional +//! information. Each coordinate is a number of type 'coord' which, by +//! default, is a standard double. Operations on points include addition, +//! subtraction, cross and dot product, and many others. This class implements +//! several useful operations using vector arithmethic. For example, +//! the simple piece of code "A = B*C;" assignes to A the value of the dot +//! product of B and C. +//! Nearly zero or nearly flat angles are automatically snapped to +//! exactly zero and exactly flat angles if the difference is smaller +//! than the global variable _acos_tolerance. This is the very basic application +//! of our version of the epsilon geometry for robust computation. + + +class Point +{ + public : + coord x,y,z; //!< Coordinates + Data info; //!< Further information + + //! Creates a new point with coordinates (0,0,0). + Point() {x = y = z = 0; info.forget();} + + //! Creates a new point with the same coordinates as 's'. The info field is not copied. + Point(const Point *s) {x = s->x; y = s->y; z = s->z; info.forget();} + + //! Creates a new point with the same coordinates as 's'. The info field is not copied. + Point(const Point& s) {x = s.x; y = s.y; z = s.z; info.forget();} + + //! Creates a new point with coordinates (a,b,c). + Point(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c; info.forget();} + + //! Do not remove this. It makes the compiler produce a vtable for this object. + TMESH_VIRTUAL bool isPoint() const { return true; } + + //! Set the coordinates to (a,b,c). + void setValue(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c;} + + //! Set the coordinates as those of 'p' + void setValue(const Point& p) {x = p.x; y = p.y; z = p.z;} + + //! Set the coordinates as those of '*p' + void setValue(const Point *p) {x = p->x; y = p->y; z = p->z;} + + //! Returns the vector difference + Point operator-(const Point& p) const {return Point(x-p.x, y-p.y, z-p.z);} + + //! Returns the vector sum + Point operator+(const Point& p) const {return Point(x+p.x, y+p.y, z+p.z);} + + //! Sums another point + void operator+=(const Point& p) {x+=p.x; y+=p.y; z+=p.z;} + + //! Subtracts another point + void operator-=(const Point& p) {x-=p.x; y-=p.y; z-=p.z;} + + //! Returns the Cross Product + Point operator&(const Point& p) const {return Point(y*p.z-z*p.y, z*p.x-x*p.z, x*p.y-y*p.x);} + + //! Returns the Dot Product + coord operator*(const Point& p) const {return (x*p.x+y*p.y+z*p.z);} + + //! Returns the product with a scalar + Point operator*(const coord& d) const {return Point(x*d,y*d,z*d);} + + //! Multiplies by a scalar + void operator*=(const coord& m) { x *= m; y *= m; z *= m; } + + //! Divides by a scalar + void operator/=(const coord& m) { x /= m; y /= m; z /= m; } + + //! Returns the vector divided by the scalar + Point operator/(const coord& d) const { return Point(x / d, y / d, z / d); } + + //! TRUE iff coordinates are equal + bool operator==(const Point& p) const {return (x==p.x && y==p.y && z==p.z);} + + //! FALSE iff coordinates are equal + bool operator!=(const Point& p) const {return (x!=p.x || y!=p.y || z!=p.z);} + + //! TRUE iff this is lexycographically smaller than s + bool operator<(const Point& s) const; + + //! Returns the i'th coordinate + inline coord& at(unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } + + //! Returns the i'th coordinate + inline coord& operator[](unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } + + //! Returns the inverse vector + Point inverse() const {return Point(-x,-y,-z);} + + //! Inverts the vector + void invert() {x=-x; y=-y; z=-z;} + + //! TRUE if vector is (0,0,0) + bool isNull() const {return (x==0 && y==0 && z==0);} + + //! Squared distance from origin + coord squaredLength() const {return (x*x + y*y + z*z);} + + //! Squared distance from '*b' + coord squaredDistance(const Point *b) const { return (((*(this)) - (*b)).squaredLength()); } + + //! Returns the solution of the linear system Ax = d, where A is a 3x3 matrix whose rows are row1, row2 and row3, d = this + Point linearSystem(const Point& row1, const Point& row2, const Point& row3); + + + //! Projects the vector on the plane with normal 'n' passing through the origin. + void project(const Point *n); + + //! Returns the projection of the point on the straight line though 'a' and 'b'. + Point projection(const Point *a, const Point *b) const; + + //! Prints the coordinates of the point to a file handler. stdout is the default. + void printPoint(FILE *fp = stdout) const { fprintf(fp, "%f %f %f,\n", TMESH_TO_FLOAT(x), TMESH_TO_FLOAT(y), TMESH_TO_FLOAT(z)); } // Debug + + + //! Exact orientation test. + //! Return value is positive iff the tetrahedron (this,a,b,c) has a positive volume; + //! It is negative iff the tetrahedron (this,a,b,c) has a negative volume; + //! It is zero iff the tetrahedron (this,a,b,c) has a zero volume. + coord exactOrientation(const Point *a, const Point *b, const Point *c) const; + coord side3D(const Point *p1, const Point *p2, const Point *p3) const { return exactOrientation(p1, p2, p3); } + + + //! Exact misalignment test. Returns TRUE iff points are not aligned. + bool exactMisalignment(const Point *a, const Point *b) const; + bool notAligned(const Point *a, const Point *b) const { return exactMisalignment(a,b); } + + //! Exact planar side test. Returns TRUE iff 'this', Q, A and B are coplanar + //! and 'this' and Q are (properly) on the same side of A-B. + //! Warning! Coplanarity is not checked, result is undetermined if + //! 'this', Q, A and B are not coplanar. + bool exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const; + + //! Itersection point between lines p-q and r-s. Return INFINITE_POINT if lineas are either parallel or degenerate. static Point lineLineIntersection(const Point& p, const Point& q, const Point& r, const Point& s); - //! Itersection point between line p-q and plane r-s-t. Return INFINITE_POINT for parallel/degenerate args. + //! Itersection point between line p-q and plane r-s-t. Return INFINITE_POINT for parallel/degenerate args. static Point linePlaneIntersection(const Point& p, const Point& q, const Point& r, const Point& s, const Point& t); - //! Squared area of the triangle p-q-r. + //! Squared area of the triangle p-q-r. static coord squaredTriangleArea3D(const Point& p, const Point& q, const Point& r); - - //! true if 'p' is a point of the segment v1-v2 (endpoints excluded) - static bool pointInInnerSegment(const Point *p, const Point *v1, const Point *v2); - - //! true if 'p' is a point of the segment v1-v2 (endpoints included) - static bool pointInSegment(const Point *p, const Point *v1, const Point *v2); - - //! true if the coplanar point 'p' is in the inner area of v1-v2-v3. - //! Undetermined if points are not coplanar. - static bool pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3); - - //! true if the coplanar point 'p' is either in the inner area of v1-v2-v3 or on its border. - //! Undetermined if points are not coplanar. - static bool pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3); - - //! true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). - //! Collinear overlapping segments are not considered to be properly intersecting. - static bool segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2); - - //! true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). - //! Collinear overlapping segments are not considered to be properly intersecting. - static bool innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2); - - //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). - static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3); - - //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). - //! Accelerated version - relative orientations are passed as parameters. - static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& o1, const coord& o2); - - - - - // FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS - - - - //! Distance from origin - double length() const { return sqrt(TMESH_TO_DOUBLE((x*x + y*y + z*z))); } - - //! Divides the vector by its length. If isNull() the application exits with an error. - void normalize(); - - //! Rotates the vector around 'axis' by 'ang' radians ccw. - void rotate(const Point& axis, const double& ang); - - //! Distance from 'b' - double distance(const Point& b) const {return (((*(this))-(b)).length());} - - //! Distance from '*b' - double distance(const Point *b) const { return (((*(this)) - (*b)).length()); } - - //! Distance from straight line through 'a' and 'b' - double distanceFromLine(const Point *a, const Point *b) const; - - //! Distance from straight line through 'a' and 'b'. *cc is set to the closest line point. - double distanceFromLine(const Point *a, const Point *b, Point *cc) const; - - double distanceFromEdge(const Point *a, const Point *b) const; //!< Distance from segment a-b - - //! Distance from segment a-b. *cc is set to the closest edge point. - double distanceFromEdge(const Point *a, const Point *b, Point *cc) const; - - //! Distance between the straight lines through (this) - l1_p2 and l2_p1 - l2_p2. - double distanceLineLine(const Point *l1_p2, const Point *l2_p1, const Point *l2_p2) const; - - //!< Angle between this vector and 'v' in radians. - double getAngle(const Point& v) const; - - //! Angle defined by in radians. - double getAngle(const Point& a, const Point& b) const { return (a - (*this)).getAngle(b - (*this)); } - - //! Angle defined by <*a, *this, *b> in radians. - double getAngle(const Point *a, const Point *b) const { return ((*a) - (*this)).getAngle((*b) - (*this)); } - - - //! Line-line closest point computation. - //! I SUSPECT THIS CAN BE MADE EXACT... - - //! Computes the closest points of the line passing through this and this2, - //! and the line passing through p1 and p2. The computed points are used to - //! initialize the coordinates of cpOnThis and cpOnOther. The method - //! returns 0 if the lines are parallel, 1 otherwise. - int closestPoints(const Point *this2, const Point *p1, const Point *p2, Point *cpOnThis, Point *cpOnOther) const; -}; - -//! Lexycographic comparison to be used with jqsort() or abstractHeap. -int xyzCompare(const Data *p1, const Data *p2); - -//! Static point with DBL_MAX coordinates. -extern const Point INFINITE_POINT; - -//! Checks whether a point is INFINITE_POINT. -#define IS_FINITE_POINT(p) ((p).x < DBL_MAX) - + + //! true if 'p' is a point of the segment v1-v2 (endpoints excluded) + static bool pointInInnerSegment(const Point *p, const Point *v1, const Point *v2); + + //! true if 'p' is a point of the segment v1-v2 (endpoints included) + static bool pointInSegment(const Point *p, const Point *v1, const Point *v2); + + //! true if the coplanar point 'p' is in the inner area of v1-v2-v3. + //! Undetermined if points are not coplanar. + static bool pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3); + + //! true if the coplanar point 'p' is either in the inner area of v1-v2-v3 or on its border. + //! Undetermined if points are not coplanar. + static bool pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3); + + //! true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). + //! Collinear overlapping segments are not considered to be properly intersecting. + static bool segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2); + + //! true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). + //! Collinear overlapping segments are not considered to be properly intersecting. + static bool innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2); + + //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). + static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3); + + //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). + //! Accelerated version - relative orientations are passed as parameters. + static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& o1, const coord& o2); + + + + + // FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS + + + + //! Distance from origin + double length() const { return sqrt(TMESH_TO_DOUBLE((x*x + y*y + z*z))); } + + //! Divides the vector by its length. If isNull() the application exits with an error. + void normalize(); + + //! Rotates the vector around 'axis' by 'ang' radians ccw. + void rotate(const Point& axis, const double& ang); + + //! Distance from 'b' + double distance(const Point& b) const {return (((*(this))-(b)).length());} + + //! Distance from '*b' + double distance(const Point *b) const { return (((*(this)) - (*b)).length()); } + + //! Distance from straight line through 'a' and 'b' + double distanceFromLine(const Point *a, const Point *b) const; + + //! Distance from straight line through 'a' and 'b'. *cc is set to the closest line point. + double distanceFromLine(const Point *a, const Point *b, Point *cc) const; + + double distanceFromEdge(const Point *a, const Point *b) const; //!< Distance from segment a-b + + //! Distance from segment a-b. *cc is set to the closest edge point. + double distanceFromEdge(const Point *a, const Point *b, Point *cc) const; + + //! Distance between the straight lines through (this) - l1_p2 and l2_p1 - l2_p2. + double distanceLineLine(const Point *l1_p2, const Point *l2_p1, const Point *l2_p2) const; + + //!< Angle between this vector and 'v' in radians. + double getAngle(const Point& v) const; + + //! Angle defined by in radians. + double getAngle(const Point& a, const Point& b) const { return (a - (*this)).getAngle(b - (*this)); } + + //! Angle defined by <*a, *this, *b> in radians. + double getAngle(const Point *a, const Point *b) const { return ((*a) - (*this)).getAngle((*b) - (*this)); } + + + //! Line-line closest point computation. + //! I SUSPECT THIS CAN BE MADE EXACT... + + //! Computes the closest points of the line passing through this and this2, + //! and the line passing through p1 and p2. The computed points are used to + //! initialize the coordinates of cpOnThis and cpOnOther. The method + //! returns 0 if the lines are parallel, 1 otherwise. + int closestPoints(const Point *this2, const Point *p1, const Point *p2, Point *cpOnThis, Point *cpOnOther) const; +}; + +//! Lexycographic comparison to be used with jqsort() or abstractHeap. +int xyzCompare(const Data &p1, const Data &p2); + +//! Static point with DBL_MAX coordinates. +extern const Point INFINITE_POINT; + +//! Checks whether a point is INFINITE_POINT. +#define IS_FINITE_POINT(p) ((p).x < DBL_MAX) + } //namespace T_MESH - -#endif // _POINT_H - + +#endif // _POINT_H + diff --git a/src/mesh_fix/include/TMesh/detectIntersections.h b/src/mesh_fix/include/TMesh/detectIntersections.h index 9659890cf2..13870a00b6 100644 --- a/src/mesh_fix/include/TMesh/detectIntersections.h +++ b/src/mesh_fix/include/TMesh/detectIntersections.h @@ -38,7 +38,7 @@ namespace T_MESH #define DI_MAX_NUMBER_OF_CELLS 10000 #define DI_EPSILON_POINT Point(1.0e-9, 1.0e-9, 1.0e-9) -class di_cell : public Data +class di_cell { public: Point mp, Mp; diff --git a/src/mesh_fix/include/TMesh/edge.h b/src/mesh_fix/include/TMesh/edge.h index 89b8bf5ed0..cd3ea2309e 100644 --- a/src/mesh_fix/include/TMesh/edge.h +++ b/src/mesh_fix/include/TMesh/edge.h @@ -28,113 +28,113 @@ * * ****************************************************************************/ -#ifndef _EDGE_H -#define _EDGE_H - -#include "basics.h" -#include "vertex.h" - -namespace T_MESH -{ - -//! Edge of a Basic_TMesh. - -//! This class represents an edge of a triangulation. An Edge is the main -//! part of the Basic_TMesh data structure. Each edge has an orientation -//! (i.e. from v1 to v2) which forces the order in which incident triangles -//! (t1 and t2) are stored in the class. When looking the edge so that it -//! points "upwards", if the normal of t1 points towards the observer then -//! t1 must be on the left of the edge. The field mask is useful for -//! assigning up to 256 different states to the edge. - - -class Edge : public Data -{ - public : - - Vertex *v1,*v2; //!< End-points - class Triangle *t1,*t2; //!< Incident triangles - unsigned char mask; //!< bit-mask for marking purposes - Data *info; //!< Further information - - - Edge(); //!< AMF_ADD 1.1-2 > - Edge(Vertex *s, Vertex *d); //!< Constructor - ~Edge(); //!< Destructor - - //! Returns true only if object is a basic Edge. All the reimplementations must return false. - TMESH_VIRTUAL bool isBaseType() const { return true; } - - //! TRUE iff edge is properly linked to a Basic_TMesh. - bool isLinked() const {return (v1 != NULL);} - - //! TRUE iff 'v' is an end-point of the edge. - bool hasVertex(const Vertex *v) const {return (v1==v || v2==v);} - - //! TRUE iff 't' is incident to the edge. - bool hasTriangle(const Triangle *t) const {return (t1==t || t2==t);} - - //! TRUE if both 'va' and 'vb' are vertices of the edge. - bool hasVertices(const Vertex *va, const Vertex *vb) const {return ((v1==va && v2==vb) || (v2==va && v1==vb));} - - //! Squared length of the edge. - coord squaredLength() const {return v1->squaredDistance(v2);} - - //! Convert to vector v2-v1. - Point toVector() const {return (*v2)-(*v1);} - - //! Return the edge's mid-point. - Point getMidPoint() const {return ((*v1)+(*v2))/2.0;} - - //! Invert the edge's orientation. - TMESH_VIRTUAL void invert() {p_swap((void **)(&v1), (void **)(&v2)); p_swap((void **)(&t1), (void **)(&t2));} //!< AMF_CHANGE 1.1-2> - - //! Triangle on the left of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge. - Triangle *leftTriangle(const Vertex *v) const {return ((v1 == v)?(t1):((v2 == v)?(t2):(NULL)));} - - //! Triangle on the right of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge. - Triangle *rightTriangle(const Vertex *v) const {return ((v1 == v)?(t2):((v2 == v)?(t1):(NULL)));} - - //! Vertex opposite to 'v'. NULL if 'v' is not a vertex of the edge. - Vertex *oppositeVertex(const Vertex *v) const {return ((v1 == v)?(v2):((v2 == v)?(v1):(NULL)));} - - //! Incident triangle opposite to 't'. NULL if 't' is not incident to the edge. - Triangle *oppositeTriangle(const Triangle *t) const {return ((t1 == t)?(t2):((t2 == t)?(t1):(NULL)));} - - //! Replace vertex 'a' with vertex 'b' in the edge and return TRUE. If 'a' is not a vertex of the edge return FALSE. - bool replaceVertex(const Vertex *a, Vertex *b) {if (v1==a) v1=b; else if (v2==a) v2=b; else return 0; return 1;} - - //! Replace incident triangle 'a' with 'b' and return TRUE. If 'a' is not incident to the edge return FALSE. - bool replaceTriangle(const Triangle *a, Triangle *b) {if (t1==a) t1=b; else if (t2==a) t2=b; else return 0; return 1;} - - //! Vertex shared with edge 'b'. NULL if this and 'b' do not share any vertex. - Vertex *commonVertex(const Edge *b) const {return ((v1 == b->v1 || v1 == b->v2)?(v1):((v2 == b->v1 || v2 == b->v2)?(v2):(NULL)));} - - //! TRUE iff edge is on the boundary (i.e., one of the two incident triangles is NULL). - bool isOnBoundary() const {return (t1 == NULL || t2 == NULL);} - - //! TRUE iff edge is isolated (i.e., both the two incident triangles are NULL). - bool isIsolated() const {return (t1 == NULL && t2 == NULL);} - - //! TRUE iff the two endpoints coincide exactly - bool isDegenerate() const {return ((*v1)==(*v2));} - - //! If the edge is on boundary return its only incident triangle. NULL otherwise. - Triangle *getBoundaryTriangle() const {return (t2 == NULL)?(t1):((t1 == NULL)?(t2):(NULL));} - - //! Print the coordinates of the end-ponts to the file handler pointed to by 'f' (stdout by default). - void printEdge(FILE *f =stdout) const {v1->printPoint(f); v2->printPoint(f);} - - //! Combinatorial edge-swap. - - //! Vertices of the edge are replaced with vertices of the two incident triangles which are opposite to this edge. - //! Connectivity information is updated properly. - //! If the edge is on boundary or if the edge after the swap already exists return FALSE and do not change anything. - //! Return TRUE on success. - //! If 'fast' is set, no topological check is performed. - TMESH_VIRTUAL bool swap(const bool fast=0); - - //! Edge collapse. +#ifndef _EDGE_H +#define _EDGE_H + +#include "basics.h" +#include "vertex.h" + +namespace T_MESH +{ + +//! Edge of a Basic_TMesh. + +//! This class represents an edge of a triangulation. An Edge is the main +//! part of the Basic_TMesh data structure. Each edge has an orientation +//! (i.e. from v1 to v2) which forces the order in which incident triangles +//! (t1 and t2) are stored in the class. When looking the edge so that it +//! points "upwards", if the normal of t1 points towards the observer then +//! t1 must be on the left of the edge. The field mask is useful for +//! assigning up to 256 different states to the edge. + + +class Edge +{ + public : + + Vertex *v1,*v2; //!< End-points + class Triangle *t1,*t2; //!< Incident triangles + unsigned char mask; //!< bit-mask for marking purposes + Data info; //!< Further information + + + Edge(); //!< AMF_ADD 1.1-2 > + Edge(Vertex *s, Vertex *d); //!< Constructor + ~Edge(); //!< Destructor + + //! Returns true only if object is a basic Edge. All the reimplementations must return false. + TMESH_VIRTUAL bool isBaseType() const { return true; } + + //! TRUE iff edge is properly linked to a Basic_TMesh. + bool isLinked() const {return (v1 != NULL);} + + //! TRUE iff 'v' is an end-point of the edge. + bool hasVertex(const Vertex *v) const {return (v1==v || v2==v);} + + //! TRUE iff 't' is incident to the edge. + bool hasTriangle(const Triangle *t) const {return (t1==t || t2==t);} + + //! TRUE if both 'va' and 'vb' are vertices of the edge. + bool hasVertices(const Vertex *va, const Vertex *vb) const {return ((v1==va && v2==vb) || (v2==va && v1==vb));} + + //! Squared length of the edge. + coord squaredLength() const {return v1->squaredDistance(v2);} + + //! Convert to vector v2-v1. + Point toVector() const {return (*v2)-(*v1);} + + //! Return the edge's mid-point. + Point getMidPoint() const {return ((*v1)+(*v2))/2.0;} + + //! Invert the edge's orientation. + TMESH_VIRTUAL void invert() {p_swap((void **)(&v1), (void **)(&v2)); p_swap((void **)(&t1), (void **)(&t2));} //!< AMF_CHANGE 1.1-2> + + //! Triangle on the left of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge. + Triangle *leftTriangle(const Vertex *v) const {return ((v1 == v)?(t1):((v2 == v)?(t2):(NULL)));} + + //! Triangle on the right of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge. + Triangle *rightTriangle(const Vertex *v) const {return ((v1 == v)?(t2):((v2 == v)?(t1):(NULL)));} + + //! Vertex opposite to 'v'. NULL if 'v' is not a vertex of the edge. + Vertex *oppositeVertex(const Vertex *v) const {return ((v1 == v)?(v2):((v2 == v)?(v1):(NULL)));} + + //! Incident triangle opposite to 't'. NULL if 't' is not incident to the edge. + Triangle *oppositeTriangle(const Triangle *t) const {return ((t1 == t)?(t2):((t2 == t)?(t1):(NULL)));} + + //! Replace vertex 'a' with vertex 'b' in the edge and return TRUE. If 'a' is not a vertex of the edge return FALSE. + bool replaceVertex(const Vertex *a, Vertex *b) {if (v1==a) v1=b; else if (v2==a) v2=b; else return 0; return 1;} + + //! Replace incident triangle 'a' with 'b' and return TRUE. If 'a' is not incident to the edge return FALSE. + bool replaceTriangle(const Triangle *a, Triangle *b) {if (t1==a) t1=b; else if (t2==a) t2=b; else return 0; return 1;} + + //! Vertex shared with edge 'b'. NULL if this and 'b' do not share any vertex. + Vertex *commonVertex(const Edge *b) const {return ((v1 == b->v1 || v1 == b->v2)?(v1):((v2 == b->v1 || v2 == b->v2)?(v2):(NULL)));} + + //! TRUE iff edge is on the boundary (i.e., one of the two incident triangles is NULL). + bool isOnBoundary() const {return (t1 == NULL || t2 == NULL);} + + //! TRUE iff edge is isolated (i.e., both the two incident triangles are NULL). + bool isIsolated() const {return (t1 == NULL && t2 == NULL);} + + //! TRUE iff the two endpoints coincide exactly + bool isDegenerate() const {return ((*v1)==(*v2));} + + //! If the edge is on boundary return its only incident triangle. NULL otherwise. + Triangle *getBoundaryTriangle() const {return (t2 == NULL)?(t1):((t1 == NULL)?(t2):(NULL));} + + //! Print the coordinates of the end-ponts to the file handler pointed to by 'f' (stdout by default). + void printEdge(FILE *f =stdout) const {v1->printPoint(f); v2->printPoint(f);} + + //! Combinatorial edge-swap. + + //! Vertices of the edge are replaced with vertices of the two incident triangles which are opposite to this edge. + //! Connectivity information is updated properly. + //! If the edge is on boundary or if the edge after the swap already exists return FALSE and do not change anything. + //! Return TRUE on success. + //! If 'fast' is set, no topological check is performed. + TMESH_VIRTUAL bool swap(const bool fast=0); + + //! Edge collapse. //! This method collapses the edge and updates the connectivity of the //! neighboring elements consistently. The edge will be contracted into its @@ -148,105 +148,105 @@ class Edge : public Data //! the method removeUnlinkedElements(). Vertex *collapseOnV1(); Vertex *collapseOnV2(); - - //! This method collapses the edge and updates the connectivity of the - //! neighboring elements consistently. The edge will be transformed into a - //! vertex with the coordinates of 'p'. - //! This method returns TRUE on success, FALSE otherwise. - //! Failure occurs when the collapse would produce an invalid connectivity graph. - //! Caution! If the collapse succeeds the - //! edge, its incident triangles and the second vertex are unlinked, but - //! they are still present in the lists of the Basic_TMesh. - //! The calling function is responsible of removing them from the lists using - //! the method removeUnlinkedElements(). - bool collapse(const Point& p); - - //! Edge collapse. - - //! This method collapses the edge and updates the connectivity of the - //! neighboring elements consistently. The edge will be transformed into a - //! vertex placed at the edge's mid-point. - //! This method returns TRUE on success, FALSE otherwise. - //! Failure occurs when the collapse would produce an invalid connectivity graph. - //! Caution! If the collapse succeeds the - //! edge, its incident triangles and the second vertex are unlinked, but - //! they are still present in the lists of the Basic_TMesh. - //! The calling function is responsible of removing them from the lists using - //! the method removeUnlinkedElements(). - bool collapse(); - - //! Merge with another boundary edge. - - //! If both this and 'e' are boundary edges, the edge 'e' is identified with - //! this one, and the connectivity of the neighboring elements is updated consistently. - //! This method returns TRUE on success, FALSE otherwise. - //! Failure occurs when the merge would produce an invalid connectivity graph (i.e., non orientable). - //! Caution! If the merge succeeds the edge 'e' and its two end-points - //! are unlinked, but they are still present in the lists of the - //! Basic_TMesh. It's responsibility of the calling function to remove - //! them from the lists using the method removeUnlinkedElements(). - bool merge(Edge *e); - - //! Stitching primitive. - - //! If there is a copy of this edge incident to one of the end-points, - //! identify it with this edge, and update the connectivity properly. - //! This method returns TRUE on success, FALSE otherwise. - //! Caution! If the stitch succeeds, the duplicated edge - //! is unlinked, but it is still present in the lists of the - //! Basic_TMesh. It's responsibility of the calling function to remove - //! it from the lists using the method removeEdges(). - bool stitch(); - - //! Returns TRUE if edge is not on boundary and its two incident triangles overlap - bool overlaps() const; - - //! true if this edge itersects 't' other than on common subsimplexes - bool intersects(const Triangle *t) const; - - //! Returns a positive value if dihedral angle is less than flat (convex), 0 if flat, - //! negative if more than flat (concave). Returns DBL_MAX if edge is on boundary. - coord getConvexity() const; - - // FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS - - - - //! Euclidean length of the edge. - double length() const { return v1->distance(v2); } - - //! Convert to normalized vector (v2-v1)/|v2-v1|. - Point toUnitVector() const; - - //! Return the normal at the edge as the average of the normals of the two incident triangles. - //! A null (0,0,0) vector is returned if the edge is on boundary. - Point getNormal() const; - - //! Return the minimum among the six angles of the two incident triangles.2PI if on boundary. - double delaunayMinAngle() const; - - //! Dihedral angle at the edge. - double dihedralAngle() const; - - //! Angle between the normals of the two incident triangles. - - //! Angle between the normals of the two incident triangles. If - //! the edge is on boundary or one or both the incident triangles are - //! degenerate, return -1. - double curvature() const; -}; - -//! Edge comparison based on length to be used with jqsort() or abstractHeap. -int edgeCompare(const Data *a, const Data *b); - -//! Lexycographic edge comparison to be used with jqsort() or abstractHeap. -int lexEdgeCompare(const Data *a, const Data *b); - -//! Vertex-based edge comparison for qsort. -//! Duplicated edges are contiguous in this sorting. -int vtxEdgeCompare(const Data *a, const Data *b); - + + //! This method collapses the edge and updates the connectivity of the + //! neighboring elements consistently. The edge will be transformed into a + //! vertex with the coordinates of 'p'. + //! This method returns TRUE on success, FALSE otherwise. + //! Failure occurs when the collapse would produce an invalid connectivity graph. + //! Caution! If the collapse succeeds the + //! edge, its incident triangles and the second vertex are unlinked, but + //! they are still present in the lists of the Basic_TMesh. + //! The calling function is responsible of removing them from the lists using + //! the method removeUnlinkedElements(). + bool collapse(const Point& p); + + //! Edge collapse. + + //! This method collapses the edge and updates the connectivity of the + //! neighboring elements consistently. The edge will be transformed into a + //! vertex placed at the edge's mid-point. + //! This method returns TRUE on success, FALSE otherwise. + //! Failure occurs when the collapse would produce an invalid connectivity graph. + //! Caution! If the collapse succeeds the + //! edge, its incident triangles and the second vertex are unlinked, but + //! they are still present in the lists of the Basic_TMesh. + //! The calling function is responsible of removing them from the lists using + //! the method removeUnlinkedElements(). + bool collapse(); + + //! Merge with another boundary edge. + + //! If both this and 'e' are boundary edges, the edge 'e' is identified with + //! this one, and the connectivity of the neighboring elements is updated consistently. + //! This method returns TRUE on success, FALSE otherwise. + //! Failure occurs when the merge would produce an invalid connectivity graph (i.e., non orientable). + //! Caution! If the merge succeeds the edge 'e' and its two end-points + //! are unlinked, but they are still present in the lists of the + //! Basic_TMesh. It's responsibility of the calling function to remove + //! them from the lists using the method removeUnlinkedElements(). + bool merge(Edge *e); + + //! Stitching primitive. + + //! If there is a copy of this edge incident to one of the end-points, + //! identify it with this edge, and update the connectivity properly. + //! This method returns TRUE on success, FALSE otherwise. + //! Caution! If the stitch succeeds, the duplicated edge + //! is unlinked, but it is still present in the lists of the + //! Basic_TMesh. It's responsibility of the calling function to remove + //! it from the lists using the method removeEdges(). + bool stitch(); + + //! Returns TRUE if edge is not on boundary and its two incident triangles overlap + bool overlaps() const; + + //! true if this edge itersects 't' other than on common subsimplexes + bool intersects(const Triangle *t) const; + + //! Returns a positive value if dihedral angle is less than flat (convex), 0 if flat, + //! negative if more than flat (concave). Returns DBL_MAX if edge is on boundary. + coord getConvexity() const; + + // FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS + + + + //! Euclidean length of the edge. + double length() const { return v1->distance(v2); } + + //! Convert to normalized vector (v2-v1)/|v2-v1|. + Point toUnitVector() const; + + //! Return the normal at the edge as the average of the normals of the two incident triangles. + //! A null (0,0,0) vector is returned if the edge is on boundary. + Point getNormal() const; + + //! Return the minimum among the six angles of the two incident triangles.2PI if on boundary. + double delaunayMinAngle() const; + + //! Dihedral angle at the edge. + double dihedralAngle() const; + + //! Angle between the normals of the two incident triangles. + + //! Angle between the normals of the two incident triangles. If + //! the edge is on boundary or one or both the incident triangles are + //! degenerate, return -1. + double curvature() const; +}; + +//! Edge comparison based on length to be used with jqsort() or abstractHeap. +int edgeCompare(const Data &a, const Data &b); + +//! Lexycographic edge comparison to be used with jqsort() or abstractHeap. +int lexEdgeCompare(const Data &a, const Data &b); + +//! Vertex-based edge comparison for qsort. +//! Duplicated edges are contiguous in this sorting. +int vtxEdgeCompare(const Data &a, const Data &b); + } //namespace T_MESH - -#endif //_EDGE_H - + +#endif //_EDGE_H + diff --git a/src/mesh_fix/include/TMesh/marchIntersections.h b/src/mesh_fix/include/TMesh/marchIntersections.h index 37a575fb70..37b327548a 100644 --- a/src/mesh_fix/include/TMesh/marchIntersections.h +++ b/src/mesh_fix/include/TMesh/marchIntersections.h @@ -42,7 +42,7 @@ namespace T_MESH // /////////////////////////////////////////////////////////////// -class mc_ints : public Data +class mc_ints { public: @@ -54,7 +54,7 @@ class mc_ints : public Data mc_ints(coord a, unsigned char b, Triangle *s) { ic = a; sg = b; v = NULL; source = s; } ~mc_ints() { if (v) delete(v); } - static int compare(const Data *e1, const Data *e2); + static int compare(const Data &e1, const Data &e2); }; @@ -64,7 +64,7 @@ class mc_ints : public Data // /////////////////////////////////////////////////////////////// -class mc_cell : public Data +class mc_cell { public: int x,y,z; // Coordinates (i.e. cell's position) @@ -77,7 +77,7 @@ class mc_cell : public Data } void polygonize(Basic_TMesh *tin); - static int compare(const Data *e1, const Data *e2); + static int compare(const Data &e1, const Data &e2); void merge(mc_cell *m); @@ -94,7 +94,7 @@ private: // /////////////////////////////////////////////////////////////// -class mc_grid : public Data +class mc_grid { Point origin; // Origin for normalization coord norm; // Normalization factor diff --git a/src/mesh_fix/include/TMesh/tin.h b/src/mesh_fix/include/TMesh/tin.h index e53814954b..62c0416a5b 100644 --- a/src/mesh_fix/include/TMesh/tin.h +++ b/src/mesh_fix/include/TMesh/tin.h @@ -104,15 +104,7 @@ class Basic_TMesh Basic_TMesh(const Triangle *t, const bool keep_ref = false); void init(const Triangle *t, const bool keep_ref = false); - //FIXED: //! Destructor. Frees the memory allocated for all the mesh elements. - //! Warning! This method uses the freeNodes() method of the class List, - //! which is not guaranteed to work correctly on systems other than - //! Linux (see the documentation of List for details). - //! Assuming that the method works correctly, however, the calling - //! function is responsible of freeing the memory that was possibly - //! allocated for objects pointed to by the 'info' field of mesh - //! elements. Clearly, this must be done before calling the destructor. ~Basic_TMesh(); //! Returns true only if object is a basic Basic_TMesh. All the reimplementations must return false. diff --git a/src/mesh_fix/include/TMesh/triangle.h b/src/mesh_fix/include/TMesh/triangle.h index 832679fee4..025bbf475f 100644 --- a/src/mesh_fix/include/TMesh/triangle.h +++ b/src/mesh_fix/include/TMesh/triangle.h @@ -46,12 +46,12 @@ namespace T_MESH //! assigning up to 256 different states to the edge. -class Triangle : public Data +class Triangle { public : Edge *e1, *e2, *e3; //!< Edges of the triangle - Data* info; //!< Further information + Data info; //!< Further information unsigned char mask; //!< bit-mask for marking purposes Triangle(); diff --git a/src/mesh_fix/src/Algorithms/checkAndRepair.cpp b/src/mesh_fix/src/Algorithms/checkAndRepair.cpp index 263046a1d3..cf7cc1eba3 100644 --- a/src/mesh_fix/src/Algorithms/checkAndRepair.cpp +++ b/src/mesh_fix/src/Algorithms/checkAndRepair.cpp @@ -188,15 +188,15 @@ Vertex *Basic_TMesh::checkGeometry() double ang, minda = 0; Triangle *t; Edge *e; - Vertex **varr = (Vertex **)V.toArray(); - Edge **evarr; + Data *varr = V.toArray(); + Data *evarr; Vertex *v1, *v2; Node *n; if (varr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident vertices.\n"); else { - jqsort((Data **)varr, V.numels(), xyzCompare); + jqsort(varr, V.numels(), xyzCompare); for (i=0; i<(V.numels()-1); i++) { v1 = ((Vertex *)varr[i]); @@ -216,11 +216,11 @@ Vertex *Basic_TMesh::checkGeometry() free(varr); } - evarr = (Edge **)E.toArray(); + evarr = E.toArray(); if (evarr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident edges.\n"); else { - jqsort((Data **)evarr, E.numels(), lexEdgeCompare); + jqsort(evarr, E.numels(), lexEdgeCompare); for (i=0; i<(E.numels()-1); i++) { if (!lexEdgeCompare(evarr[i], evarr[i+1])) @@ -278,11 +278,11 @@ int Basic_TMesh::mergeCoincidentEdges() FOREACHEDGE(e, n) { - if (e->v1->info != e->v1) e->v1 = (Vertex *)e->v1->info; - if (e->v2->info != e->v2) e->v2 = (Vertex *)e->v2->info; + if (e->v1->info.operator !=(e->v1)) e->v1 = (Vertex *)e->v1->info; + if (e->v2->info.operator !=(e->v2)) e->v2 = (Vertex *)e->v2->info; e->v1->e0 = e->v2->e0 = e; } - removeVertices(); + int rv = removeVertices(); // At this point the mesh should no longer have duplicated vertices, but may have duplicated edges E.sort(&vtxEdgeCompare); @@ -292,10 +292,11 @@ int Basic_TMesh::mergeCoincidentEdges() if (!e->isOnBoundary() || vtxEdgeCompare(e, pe)) pe = e; e->info = pe; } - FOREACHEDGE(e, n) if (e->info != e) + FOREACHEDGE(e, n) if (e->info.operator !=(e)) { Triangle *t1 = e->getBoundaryTriangle(); Edge *f = ((Edge *)e->info); + Triangle *t2 = f->getBoundaryTriangle(); t1->replaceEdge(e, f); ((f->t1 == NULL) ? (f->t1) : (f->t2)) = t1; e->v1 = e->v2 = NULL; @@ -343,8 +344,8 @@ bool Basic_TMesh::rebuildConnectivity(bool fixconnectivity) //!< AMF_CHANGE 1.1> Edge *e; FOREACHEDGE(e, n) { - if (e->v1->info != e->v1) e->v1 = (Vertex *)e->v1->info; - if (e->v2->info != e->v2) e->v2 = (Vertex *)e->v2->info; + if (e->v1->info.operator !=(e->v1)) e->v1 = (Vertex *)e->v1->info; + if (e->v2->info.operator !=(e->v2)) e->v2 = (Vertex *)e->v2->info; e->v1->e0 = e->v2->e0 = e; } int rv = removeVertices(); @@ -354,14 +355,14 @@ bool Basic_TMesh::rebuildConnectivity(bool fixconnectivity) //!< AMF_CHANGE 1.1> Triangle *t; ExtVertex **var = new ExtVertex *[V.numels()]; int i=0; - FOREACHVERTEX(v, n) { v->e0 = NULL; var[i] = new ExtVertex(v); v->info = new intWrapper(i); i++; } + FOREACHVERTEX(v, n) { v->e0 = NULL; var[i] = new ExtVertex(v); v->info = i; i++; } int nt = T.numels(); int *triangles = new int[nt*3]; i = 0; FOREACHTRIANGLE(t, n) { - triangles[i * 3] = ((intWrapper*)t->v1()->info)->operator int(); - triangles[i*3+1] = ((intWrapper*)t->v2()->info)->operator int(); - triangles[i*3+2] = ((intWrapper*)t->v3()->info)->operator int(); + triangles[i * 3] = (j_voidint)t->v1()->info; + triangles[i*3+1] = (j_voidint)t->v2()->info; + triangles[i*3+2] = (j_voidint)t->v3()->info; i++; } T.freeNodes(); @@ -449,7 +450,7 @@ int multiSplitEdge(Basic_TMesh *tin, Edge *e) while (splitVertices.numels()) { coord ad, mind = DBL_MAX; - Vertex *gv = nullptr; + Vertex *gv; FOREACHVVVERTEX((&splitVertices), v, n) if ((ad = v->squaredDistance(e->v2)) < mind) { gv = v; mind = ad; } splitVertices.removeNode(gv); tin->splitEdge(e, gv); diff --git a/src/mesh_fix/src/Algorithms/detectIntersections.cpp b/src/mesh_fix/src/Algorithms/detectIntersections.cpp index 24444997f1..01740dbac6 100644 --- a/src/mesh_fix/src/Algorithms/detectIntersections.cpp +++ b/src/mesh_fix/src/Algorithms/detectIntersections.cpp @@ -33,60 +33,60 @@ #include #include "jqsort.h" -namespace T_MESH -{ - di_cell::di_cell(Basic_TMesh *tin, bool useAll) - { - Node *n; - Vertex *v; - Triangle *t; - Mp.x = -DBL_MAX, mp.x = DBL_MAX; - Mp.y = -DBL_MAX, mp.y = DBL_MAX; - Mp.z = -DBL_MAX, mp.z = DBL_MAX; - FOREACHVVVERTEX((&(tin->V)), v, n) if (useAll || IS_BIT(v,5)) - { - if (v->x < mp.x) mp.x = v->x; - if (v->x > Mp.x) Mp.x = v->x; - if (v->y < mp.y) mp.y = v->y; - if (v->y > Mp.y) Mp.y = v->y; - if (v->z < mp.z) mp.z = v->z; - if (v->z > Mp.z) Mp.z = v->z; - } - - mp -= DI_EPSILON_POINT; - Mp += DI_EPSILON_POINT; - - FOREACHVTTRIANGLE((&(tin->T)), t, n) if (useAll || IS_VISITED(t)) triangles.appendTail(t); - } - - bool di_cell::is_triangleBB_in_cell(Triangle *t) const - { - Vertex *v1 = t->v1(), *v2 = t->v2(), *v3 = t->v3(); - coord mx = MIN(v1->x, MIN(v2->x, v3->x)); - coord Mx = MAX(v1->x, MAX(v2->x, v3->x)); - coord my = MIN(v1->y, MIN(v2->y, v3->y)); - coord My = MAX(v1->y, MAX(v2->y, v3->y)); - coord mz = MIN(v1->z, MIN(v2->z, v3->z)); - coord Mz = MAX(v1->z, MAX(v2->z, v3->z)); - - // Triangle BB is not entirely out of cell - if (!(MxMp.x || MyMp.y || MzMp.z)) return true; - else return false; - } - - di_cell *di_cell::fork() - { - Node *n; - Triangle *t; - Point e = Mp - mp; - di_cell *nc = new di_cell; - char which_coord = 2; - - if (e.x >= e.y && e.x >= e.z) which_coord = 0; - else if (e.y >= e.x && e.y >= e.z) which_coord = 1; - nc->mp = mp; nc->Mp = Mp; - nc->Mp[which_coord] -= (e[which_coord] / 2); mp[which_coord] = nc->Mp[which_coord]; - +namespace T_MESH +{ + di_cell::di_cell(Basic_TMesh *tin, bool useAll) + { + Node *n; + Vertex *v; + Triangle *t; + Mp.x = -DBL_MAX, mp.x = DBL_MAX; + Mp.y = -DBL_MAX, mp.y = DBL_MAX; + Mp.z = -DBL_MAX, mp.z = DBL_MAX; + FOREACHVVVERTEX((&(tin->V)), v, n) if (useAll || IS_BIT(v,5)) + { + if (v->x < mp.x) mp.x = v->x; + if (v->x > Mp.x) Mp.x = v->x; + if (v->y < mp.y) mp.y = v->y; + if (v->y > Mp.y) Mp.y = v->y; + if (v->z < mp.z) mp.z = v->z; + if (v->z > Mp.z) Mp.z = v->z; + } + + mp -= DI_EPSILON_POINT; + Mp += DI_EPSILON_POINT; + + FOREACHVTTRIANGLE((&(tin->T)), t, n) if (useAll || IS_VISITED(t)) triangles.appendTail(t); + } + + bool di_cell::is_triangleBB_in_cell(Triangle *t) const + { + Vertex *v1 = t->v1(), *v2 = t->v2(), *v3 = t->v3(); + coord mx = MIN(v1->x, MIN(v2->x, v3->x)); + coord Mx = MAX(v1->x, MAX(v2->x, v3->x)); + coord my = MIN(v1->y, MIN(v2->y, v3->y)); + coord My = MAX(v1->y, MAX(v2->y, v3->y)); + coord mz = MIN(v1->z, MIN(v2->z, v3->z)); + coord Mz = MAX(v1->z, MAX(v2->z, v3->z)); + + // Triangle BB is not entirely out of cell + if (!(MxMp.x || MyMp.y || MzMp.z)) return true; + else return false; + } + + di_cell *di_cell::fork() + { + Node *n; + Triangle *t; + Point e = Mp - mp; + di_cell *nc = new di_cell; + char which_coord = 2; + + if (e.x >= e.y && e.x >= e.z) which_coord = 0; + else if (e.y >= e.x && e.y >= e.z) which_coord = 1; + nc->mp = mp; nc->Mp = Mp; + nc->Mp[which_coord] -= (e[which_coord] / 2); mp[which_coord] = nc->Mp[which_coord]; + n = triangles.head(); while (n != NULL) { @@ -96,37 +96,37 @@ namespace T_MESH { triangles.moveNodeTo((n != NULL) ? (n->prev()) : triangles.tail(), &(nc->triangles)); } - else if (nc->is_triangleBB_in_cell(t)) nc->triangles.appendHead(t); + else if (nc->is_triangleBB_in_cell(t)) nc->triangles.appendHead(t); } - - return nc; - } - - - // Brute force all-with-all intersection test of the triangles in 'triangles'. - void di_cell::selectIntersections(bool justproper) - { - Triangle *t, *y; - Node *n, *m; - List *ts; - - for (n = triangles.head(); n != NULL; n = n->next()) - for (m = n->next(); m != NULL; m = m->next()) - { - t = (Triangle *)n->data; - y = (Triangle *)m->data; // For any pair (t,y) of triangles in the cell - // The same triangle pair can be in different cells. The following avoids redoing the check. - if (t->info == NULL || y->info == NULL || (((List *)t->info)->containsNode(y) == NULL)) - { - if (t->intersects(y, justproper)) - { - MARK_VISIT(t); MARK_VISIT(y); - ts = ((t->info != NULL) ? ((List *)t->info) : (new List)); ts->appendTail(y); t->info = ts; - ts = ((y->info != NULL) ? ((List *)y->info) : (new List)); ts->appendTail(t); y->info = ts; - } - } - } - } + + return nc; + } + + + // Brute force all-with-all intersection test of the triangles in 'triangles'. + void di_cell::selectIntersections(bool justproper) + { + Triangle *t, *y; + Node *n, *m; + List *ts; + + for (n = triangles.head(); n != NULL; n = n->next()) + for (m = n->next(); m != NULL; m = m->next()) + { + t = (Triangle *)n->data; + y = (Triangle *)m->data; // For any pair (t,y) of triangles in the cell + // The same triangle pair can be in different cells. The following avoids redoing the check. + if (t->info.empty() || y->info.empty() || (((List *)t->info)->containsNode(y) == NULL)) + { + if (t->intersects(y, justproper)) + { + MARK_VISIT(t); MARK_VISIT(y); + ts = ((t->info.notEmpty()) ? ((List *)t->info) : (new List)); ts->appendTail(y); t->info = ts; + ts = ((y->info.notEmpty()) ? ((List *)y->info) : (new List)); ts->appendTail(t); y->info = ts; + } + } + } + } ///////////////////////////////////////////////////////////////////////// @@ -177,7 +177,7 @@ int Basic_TMesh::selectIntersectingTriangles(UINT16 tris_per_cell, bool justprop // Deselect everything and select only intersecting triangles deselectTriangles(); - FOREACHTRIANGLE(t, n) t->info = NULL; + FOREACHTRIANGLE(t, n) t->info.forget(); i=0; FOREACHNODE(cells, n) { (((di_cell *)n->data)->selectIntersections(justproper)); @@ -187,7 +187,7 @@ int Basic_TMesh::selectIntersectingTriangles(UINT16 tris_per_cell, bool justprop TMesh::end_progress(); // Dispose memory allocated for cells - FOREACHVTTRIANGLE(selT, t, n) { if (t->info!=NULL) delete((List *)t->info); t->info = NULL; } + FOREACHVTTRIANGLE(selT, t, n) t->info.clear(); while (cells.numels()) delete((di_cell *)cells.popHead()); // Count selected triangles for final report and delete stored normals diff --git a/src/mesh_fix/src/Algorithms/holeFilling.cpp b/src/mesh_fix/src/Algorithms/holeFilling.cpp index c19557ec6e..ca09e75bab 100644 --- a/src/mesh_fix/src/Algorithms/holeFilling.cpp +++ b/src/mesh_fix/src/Algorithms/holeFilling.cpp @@ -28,12 +28,12 @@ * * ****************************************************************************/ -#include "tin.h" -#include - -namespace T_MESH -{ - +#include "tin.h" +#include + +namespace T_MESH +{ + ////////////////////////////////////////////////////////////////// // // // T R I A N G U L A T I O N M E T H O D S // @@ -432,366 +432,366 @@ int Basic_TMesh::retriangulateVT(Vertex *v) return 1; } - -////////// Generic method for patching holes. Heuristic. ///////////// -////////// Small angles are patched first, if possible. ///////////// - -int Basic_TMesh::TriangulateHole(Edge *e) -{ - if (!e->isOnBoundary()) return 0; - - List bvs; - Node *n, *gn = NULL; - Edge *e1, *e2; - Vertex *v, *v1, *v2; - double ang, gang; - int nt = 0; - Triangle *t; - v = e->v1; - - t = (e->t1!=NULL)?(e->t1):(e->t2); - if (t->nextEdge(e)->isOnBoundary() && t->prevEdge(e)->isOnBoundary()) return 0; - - do - { - bvs.appendHead(v); - v = v->nextOnBoundary(); - } while (v != e->v1); - - while (bvs.numels() > 2) - { - gang = DBL_MAX; - FOREACHVVVERTEX((&bvs), v, n) - if (!IS_BIT(v, 5) && v->e0 && (ang = v->getAngleForTriangulation()) < gang) - {gang = ang; gn = n;} - if (gang == DBL_MAX) - { - TMesh::warning("TriangulateHole: Can't complete the triangulation.\n"); - FOREACHVVVERTEX((&bvs), v, n) UNMARK_BIT(v, 5); - int i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else unlinkTriangle(t); - removeUnlinkedElements(); - return 0; - } - v = ((Vertex *)gn->data); - v1 = (Vertex *)((gn->next() != NULL)?(gn->next()):(bvs.head()))->data; - v2 = (Vertex *)((gn->prev() != NULL)?(gn->prev()):(bvs.tail()))->data; - e1 = v->getEdge(v1); - e2 = v->getEdge(v2); - if ((t=EulerEdgeTriangle(e1,e2))==NULL) MARK_BIT(v, 5); - else { bvs.removeCell(gn); UNMARK_BIT(v1, 5); UNMARK_BIT(v2, 5); MARK_VISIT(t); nt++; } - } - - return nt; -} - - -// Fills the hole identified by 'e' and leaves the new triangle selected. -// 'refine' is for internal vertex insertion. - -void Basic_TMesh::FillHole(Edge *e, bool refine) -{ - int i, nt; - Node *n; - Triangle *t; - Vertex *v; - - deselectTriangles(); - FOREACHVERTEX(v, n) UNMARK_BIT(v, 5); - nt = TriangulateHole(e); - if (!nt) return; - - i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else MARK_VISIT(t); - - if (refine) - refineSelectedHolePatches((Triangle *)T.head()->data); -} - -//// Triangulate Small Boundaries (with less than 'nbe' edges) ///// - -int Basic_TMesh::fillSmallBoundaries(int nbe, bool refine_patches) -{ - if (nbe == 0) nbe = E.numels(); - Vertex *v,*w; - Triangle *t; - Node *n; - int grd, is_selection=0, tbds = 0, pct = 100; - List bdrs; - - TMesh::begin_progress(); - TMesh::report_progress("0%% done "); - - FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) {is_selection=1; break;} - - if (is_selection) { - FOREACHTRIANGLE(t, n) if (!IS_VISITED(t)) - { - MARK_BIT(t->v1(), 6); MARK_BIT(t->v2(), 6); MARK_BIT(t->v3(), 6); - } - } - else FOREACHVERTEX(v, n) UNMARK_BIT(v, 6); - - FOREACHVERTEX(v, n) - { - grd = 0; - if (!IS_BIT(v, 6) && v->isOnBoundary()) - { - tbds++; - w = v; - do - { - if (IS_BIT(w, 6)) grd=nbe+1; - MARK_BIT(w, 6); - grd++; - w = w->nextOnBoundary(); - } while (w != v); - if (grd <= nbe) bdrs.appendHead(w->nextBoundaryEdge()); - } - } - FOREACHVERTEX(v, n) { UNMARK_BIT(v, 5); UNMARK_BIT(v, 6); } - - deselectTriangles(); - - pct=0; FOREACHNODE(bdrs, n) - { - if (TriangulateHole((Edge *)n->data) && refine_patches) - { - t = (Triangle *)T.head()->data; - refineSelectedHolePatches(t); - } - TMesh::report_progress("%d%% done ",((++pct)*100)/bdrs.numels()); - } - - grd = bdrs.numels(); - - TMesh::end_progress(); - - return grd; -} - - -// Inserts new vertices in the current selection so as -// to reflect the density of the surrounding mesh. -// This method assumes that the selection has no internal vertices. - -int Basic_TMesh::refineSelectedHolePatches(Triangle *t0) -{ - Node *n, *m; - Triangle *t, *t1, *t2; - Edge *e, *f; - Vertex *v; - List *ve, toswap, reg, all_edges, interior_edges, boundary_edges, boundary_vertices, interior_vertices; - doubleWrapper sigma, l, sv1, sv2, sv3, dv1, dv2, dv3; - int swaps, totits, nee, ntb, nnt=-1, pnnt, gits=0; - const double alpha = sqrt(2.0); - Point vc; - - if (t0 != NULL) - { - if (!IS_VISITED(t0)) TMesh::error("refineSelectedHolePatches: unexpected unselected t0 !"); - UNMARK_VISIT(t0); toswap.appendHead(t0); - while ((t=(Triangle *)toswap.popHead()) != NULL) - { - reg.appendHead(t); - t1=t->t1(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} - t1=t->t2(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} - t1=t->t3(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} - } - FOREACHVTTRIANGLE((®), t, n) MARK_VISIT(t); - } - else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t); - - printf("%d\n",reg.numels()); - - FOREACHVTTRIANGLE((®), t, n) - { - e = t->e1; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); - e = t->e2; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); - e = t->e3; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); - } - - while (all_edges.numels()) - { - e = (Edge *)all_edges.popHead(); - if (IS_BIT(e, 5)) { boundary_edges.appendHead(e); UNMARK_BIT(e, 5); } - else { interior_edges.appendHead(e); MARK_BIT(e, 5); } - } - - FOREACHVEEDGE((&boundary_edges), e, n) - { - v = e->v1; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);} - v = e->v2; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);} - } - - FOREACHVVVERTEX((&boundary_vertices), v, n) UNMARK_BIT(v, 5); - - // Due to the above definitions, interior edges are BIT - - FOREACHVVVERTEX((&boundary_vertices), v, n) - { - ve = v->VE(); - sigma=0; nee=0; FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e, 5)) {nee++; sigma += e->length();} - sigma /= double(nee); v->info = new doubleWrapper(sigma); - delete(ve); - } - - FOREACHVEEDGE((&interior_edges), e, n) UNMARK_BIT(e, 5); - FOREACHVEEDGE((&boundary_edges), e, n) MARK_BIT(e, 6); - - do - { - pnnt=nnt; - nnt=0; - FOREACHVTTRIANGLE((®), t, n) - { - vc = t->getCenter(); - sv1 = (*(doubleWrapper *)t->v1()->info); - sv2 = (*(doubleWrapper *)t->v2()->info); - sv3 = (*(doubleWrapper *)t->v3()->info); - sigma = (sv1+sv2+sv3)/3.0; - dv1 = alpha*(t->v1()->distance(&vc)); - dv2 = alpha*(t->v2()->distance(&vc)); - dv3 = alpha*(t->v3()->distance(&vc)); - if (dv1>sigma && dv1>sv1 && dv2>sigma && dv2>sv2 && dv3>sigma && dv3>sv3) - { - ntb = T.numels(); - v = splitTriangle(t,&vc,1); - nnt += (T.numels()-ntb); - if (T.numels() == ntb+2) - { - v->info = new doubleWrapper(sigma); - interior_vertices.appendHead(v); - interior_edges.appendHead(v->e0); - interior_edges.appendHead(v->e0->leftTriangle(v)->prevEdge(v->e0)); - interior_edges.appendHead(v->e0->rightTriangle(v)->nextEdge(v->e0)); - t1 = ((Triangle *)T.head()->data); - t2 = ((Triangle *)T.head()->next()->data); - t1->mask = t2->mask = t->mask; - reg.appendHead(t1); reg.appendHead(t2); - } - } - } - - FOREACHVEEDGE((&interior_edges), e, n) {MARK_BIT(e, 5); toswap.appendHead(e);} - totits=0; swaps=1; - while (swaps && totits++ < 10) - { - swaps = 0; - while ((e=(Edge *)toswap.popHead())!=NULL) - { - UNMARK_BIT(e, 5); - l = e->squaredLength(); - if (e->swap()) - { - if (e->squaredLength() >= l*0.999999) e->swap(1); - else - { - swaps++; - toswap.appendTail(e); - f = e->t1->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } - f = e->t1->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } - f = e->t2->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } - f = e->t2->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } - } - } - } - } - - if (pnnt==nnt) gits++; - } while (nnt && gits<10); - - //FOREACHVEEDGE((&boundary_edges), e, n) UNMARK_BIT(e, 6); - FOREACHVVVERTEX((&boundary_vertices), v, n) { delete((Data *)v->info); v->info = NULL; MARK_BIT(v, 5);} - FOREACHVVVERTEX((&interior_vertices), v, n) { delete((Data *)v->info); v->info = NULL; MARK_BIT(v, 6);} - - if (gits>=10) {TMesh::warning("Fill holes: Refinement stage failed to converge. Breaking.\n"); return 1;} - - return 0; -} - -// Joins the two boundary vertices gv and gw through an edge. A pair of triangles is -// added to properly change the topology of the mesh. -// On success, the return value is the new edge connecting the two vertices. -// NULL is returned on failure. -// Failure occurs if gv and gw are not both on boundary. -// If 'justconnect' is false, the remaining hole is filled with new triangles, unless -// gv and gw are contiguous on the boundary loop (failure). -// If 'justconnect' is true, gv and gw must not belong to the same boundary loop (failure). -// If 'refine', the patching triangles are refined to reproduce neighboring density. - -Edge *Basic_TMesh::joinBoundaryLoops(Vertex *gv, Vertex *gw, bool justconnect, bool refine) -{ - Vertex *v, *gvn, *gwn; - Edge *e, *gve, *gwe; - Triangle *t; - Node *n; - double tl1 = 0.0, tl2 = 0.0, pl1, pl2; - - if (gv == NULL || gw == NULL || !gv->isOnBoundary() || !gw->isOnBoundary()) return NULL; - - FOREACHVERTEX(v, n) UNMARK_VISIT(v); - deselectTriangles(); - - v = gv; - if (!justconnect) - { - do { v = v->nextOnBoundary(); if (v == gw) return NULL; } while (v != gv); - } else - { - gvn = gv->nextOnBoundary(); gwn = gv->prevOnBoundary(); - if (gw == gvn || gw == gwn) return NULL; - if (gw == gvn->nextOnBoundary()) - { - t = EulerEdgeTriangle(gvn->prevBoundaryEdge(), gvn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gvn); - } - if (gw == gwn->prevOnBoundary()) - { - t = EulerEdgeTriangle(gwn->prevBoundaryEdge(), gwn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gwn); - } - } - - gve = gv->prevBoundaryEdge(); - gvn = gve->oppositeVertex(gv); - gwe = gw->nextBoundaryEdge(); - gwn = gwe->oppositeVertex(gw); - - Edge *je = CreateEdge(gv, gw); - Edge *je1 = CreateEdge(gv, gwn); - Edge *je2 = CreateEdge(gwn, gvn); - - t = CreateTriangle(je, gwe, je1); MARK_VISIT(t); - t = CreateTriangle(je1, je2, gve); MARK_VISIT(t); - - if (justconnect) return je; - - v = gv; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl1 += e->length(); } while (v != gv); - v = gw; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl2 += e->length(); } while (v != gw); - pl1 = tl1; pl2 = tl2; - - double c1, c2; - - e = je; - while (e->isOnBoundary()) - { - gv = (e->t2 != NULL) ? (e->v2) : (e->v1); gve = gv->nextBoundaryEdge(); - gw = (e->t1 != NULL) ? (e->v2) : (e->v1); gwe = gw->prevBoundaryEdge(); - c1 = fabs((pl1 - gve->length())*tl2 - pl2*tl1); - c2 = fabs((pl2 - gwe->length())*tl1 - pl1*tl2); - if (c1length(); - e = t->nextEdge(gve); - } else - { - t = EulerEdgeTriangle(gwe, e); MARK_VISIT(t); - pl2 -= gwe->length(); - e = t->prevEdge(gwe); - } - } - - if (refine) refineSelectedHolePatches(); - - return je; -} - + +////////// Generic method for patching holes. Heuristic. ///////////// +////////// Small angles are patched first, if possible. ///////////// + +int Basic_TMesh::TriangulateHole(Edge *e) +{ + if (!e->isOnBoundary()) return 0; + + List bvs; + Node *n, *gn = NULL; + Edge *e1, *e2; + Vertex *v, *v1, *v2; + double ang, gang; + int nt = 0; + Triangle *t; + v = e->v1; + + t = (e->t1!=NULL)?(e->t1):(e->t2); + if (t->nextEdge(e)->isOnBoundary() && t->prevEdge(e)->isOnBoundary()) return 0; + + do + { + bvs.appendHead(v); + v = v->nextOnBoundary(); + } while (v != e->v1); + + while (bvs.numels() > 2) + { + gang = DBL_MAX; + FOREACHVVVERTEX((&bvs), v, n) + if (!IS_BIT(v, 5) && v->e0 && (ang = v->getAngleForTriangulation()) < gang) + {gang = ang; gn = n;} + if (gang == DBL_MAX) + { + TMesh::warning("TriangulateHole: Can't complete the triangulation.\n"); + FOREACHVVVERTEX((&bvs), v, n) UNMARK_BIT(v, 5); + int i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else unlinkTriangle(t); + removeUnlinkedElements(); + return 0; + } + v = ((Vertex *)gn->data); + v1 = (Vertex *)((gn->next() != NULL)?(gn->next()):(bvs.head()))->data; + v2 = (Vertex *)((gn->prev() != NULL)?(gn->prev()):(bvs.tail()))->data; + e1 = v->getEdge(v1); + e2 = v->getEdge(v2); + if ((t=EulerEdgeTriangle(e1,e2))==NULL) MARK_BIT(v, 5); + else { bvs.removeCell(gn); UNMARK_BIT(v1, 5); UNMARK_BIT(v2, 5); MARK_VISIT(t); nt++; } + } + + return nt; +} + + +// Fills the hole identified by 'e' and leaves the new triangle selected. +// 'refine' is for internal vertex insertion. + +void Basic_TMesh::FillHole(Edge *e, bool refine) +{ + int i, nt; + Node *n; + Triangle *t; + Vertex *v; + + deselectTriangles(); + FOREACHVERTEX(v, n) UNMARK_BIT(v, 5); + nt = TriangulateHole(e); + if (!nt) return; + + i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else MARK_VISIT(t); + + if (refine) + refineSelectedHolePatches((Triangle *)T.head()->data); +} + +//// Triangulate Small Boundaries (with less than 'nbe' edges) ///// + +int Basic_TMesh::fillSmallBoundaries(int nbe, bool refine_patches) +{ + if (nbe == 0) nbe = E.numels(); + Vertex *v,*w; + Triangle *t; + Node *n; + int grd, is_selection=0, tbds = 0, pct = 100; + List bdrs; + + TMesh::begin_progress(); + TMesh::report_progress("0%% done "); + + FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) {is_selection=1; break;} + + if (is_selection) { + FOREACHTRIANGLE(t, n) if (!IS_VISITED(t)) + { + MARK_BIT(t->v1(), 6); MARK_BIT(t->v2(), 6); MARK_BIT(t->v3(), 6); + } + } + else FOREACHVERTEX(v, n) UNMARK_BIT(v, 6); + + FOREACHVERTEX(v, n) + { + grd = 0; + if (!IS_BIT(v, 6) && v->isOnBoundary()) + { + tbds++; + w = v; + do + { + if (IS_BIT(w, 6)) grd=nbe+1; + MARK_BIT(w, 6); + grd++; + w = w->nextOnBoundary(); + } while (w != v); + if (grd <= nbe) bdrs.appendHead(w->nextBoundaryEdge()); + } + } + FOREACHVERTEX(v, n) { UNMARK_BIT(v, 5); UNMARK_BIT(v, 6); } + + deselectTriangles(); + + pct=0; FOREACHNODE(bdrs, n) + { + if (TriangulateHole((Edge *)n->data) && refine_patches) + { + t = (Triangle *)T.head()->data; + refineSelectedHolePatches(t); + } + TMesh::report_progress("%d%% done ",((++pct)*100)/bdrs.numels()); + } + + grd = bdrs.numels(); + + TMesh::end_progress(); + + return grd; +} + + +// Inserts new vertices in the current selection so as +// to reflect the density of the surrounding mesh. +// This method assumes that the selection has no internal vertices. + +int Basic_TMesh::refineSelectedHolePatches(Triangle *t0) +{ + Node *n, *m; + Triangle *t, *t1, *t2; + Edge *e, *f; + Vertex *v; + List *ve, toswap, reg, all_edges, interior_edges, boundary_edges, boundary_vertices, interior_vertices; + coord sigma, l, sv1, sv2, sv3, dv1, dv2, dv3; + int swaps, totits, nee, ntb, nnt=-1, pnnt, gits=0; + const double alpha = sqrt(2.0); + Point vc; + + if (t0 != NULL) + { + if (!IS_VISITED(t0)) TMesh::error("refineSelectedHolePatches: unexpected unselected t0 !"); + UNMARK_VISIT(t0); toswap.appendHead(t0); + while ((t=(Triangle *)toswap.popHead()) != NULL) + { + reg.appendHead(t); + t1=t->t1(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} + t1=t->t2(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} + t1=t->t3(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);} + } + FOREACHVTTRIANGLE((®), t, n) MARK_VISIT(t); + } + else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t); + + printf("%d\n",reg.numels()); + + FOREACHVTTRIANGLE((®), t, n) + { + e = t->e1; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); + e = t->e2; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); + e = t->e3; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5); + } + + while (all_edges.numels()) + { + e = (Edge *)all_edges.popHead(); + if (IS_BIT(e, 5)) { boundary_edges.appendHead(e); UNMARK_BIT(e, 5); } + else { interior_edges.appendHead(e); MARK_BIT(e, 5); } + } + + FOREACHVEEDGE((&boundary_edges), e, n) + { + v = e->v1; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);} + v = e->v2; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);} + } + + FOREACHVVVERTEX((&boundary_vertices), v, n) UNMARK_BIT(v, 5); + + // Due to the above definitions, interior edges are BIT + + FOREACHVVVERTEX((&boundary_vertices), v, n) + { + ve = v->VE(); + sigma=0; nee=0; FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e, 5)) {nee++; sigma += e->length();} + sigma /= nee; v->info = new coord(sigma); + delete(ve); + } + + FOREACHVEEDGE((&interior_edges), e, n) UNMARK_BIT(e, 5); + FOREACHVEEDGE((&boundary_edges), e, n) MARK_BIT(e, 6); + + do + { + pnnt=nnt; + nnt=0; + FOREACHVTTRIANGLE((®), t, n) + { + vc = t->getCenter(); + sv1 = (*(coord *)t->v1()->info); + sv2 = (*(coord *)t->v2()->info); + sv3 = (*(coord *)t->v3()->info); + sigma = (sv1+sv2+sv3)/3.0; + dv1 = alpha*(t->v1()->distance(&vc)); + dv2 = alpha*(t->v2()->distance(&vc)); + dv3 = alpha*(t->v3()->distance(&vc)); + if (dv1>sigma && dv1>sv1 && dv2>sigma && dv2>sv2 && dv3>sigma && dv3>sv3) + { + ntb = T.numels(); + v = splitTriangle(t,&vc,1); + nnt += (T.numels()-ntb); + if (T.numels() == ntb+2) + { + v->info = new coord(sigma); + interior_vertices.appendHead(v); + interior_edges.appendHead(v->e0); + interior_edges.appendHead(v->e0->leftTriangle(v)->prevEdge(v->e0)); + interior_edges.appendHead(v->e0->rightTriangle(v)->nextEdge(v->e0)); + t1 = ((Triangle *)T.head()->data); + t2 = ((Triangle *)T.head()->next()->data); + t1->mask = t2->mask = t->mask; + reg.appendHead(t1); reg.appendHead(t2); + } + } + } + + FOREACHVEEDGE((&interior_edges), e, n) {MARK_BIT(e, 5); toswap.appendHead(e);} + totits=0; swaps=1; + while (swaps && totits++ < 10) + { + swaps = 0; + while ((e=(Edge *)toswap.popHead())!=NULL) + { + UNMARK_BIT(e, 5); + l = e->squaredLength(); + if (e->swap()) + { + if (e->squaredLength() >= l*0.999999) e->swap(1); + else + { + swaps++; + toswap.appendTail(e); + f = e->t1->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } + f = e->t1->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } + f = e->t2->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } + f = e->t2->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); } + } + } + } + } + + if (pnnt==nnt) gits++; + } while (nnt && gits<10); + + //FOREACHVEEDGE((&boundary_edges), e, n) UNMARK_BIT(e, 6); + FOREACHVVVERTEX((&boundary_vertices), v, n) { v->info.clear(); MARK_BIT(v, 5);} + FOREACHVVVERTEX((&interior_vertices), v, n) { v->info.clear(); MARK_BIT(v, 6);} + + if (gits>=10) {TMesh::warning("Fill holes: Refinement stage failed to converge. Breaking.\n"); return 1;} + + return 0; +} + +// Joins the two boundary vertices gv and gw through an edge. A pair of triangles is +// added to properly change the topology of the mesh. +// On success, the return value is the new edge connecting the two vertices. +// NULL is returned on failure. +// Failure occurs if gv and gw are not both on boundary. +// If 'justconnect' is false, the remaining hole is filled with new triangles, unless +// gv and gw are contiguous on the boundary loop (failure). +// If 'justconnect' is true, gv and gw must not belong to the same boundary loop (failure). +// If 'refine', the patching triangles are refined to reproduce neighboring density. + +Edge *Basic_TMesh::joinBoundaryLoops(Vertex *gv, Vertex *gw, bool justconnect, bool refine) +{ + Vertex *v, *gvn, *gwn; + Edge *e, *gve, *gwe; + Triangle *t; + Node *n; + double tl1 = 0.0, tl2 = 0.0, pl1, pl2; + + if (gv == NULL || gw == NULL || !gv->isOnBoundary() || !gw->isOnBoundary()) return NULL; + + FOREACHVERTEX(v, n) UNMARK_VISIT(v); + deselectTriangles(); + + v = gv; + if (!justconnect) + { + do { v = v->nextOnBoundary(); if (v == gw) return NULL; } while (v != gv); + } else + { + gvn = gv->nextOnBoundary(); gwn = gv->prevOnBoundary(); + if (gw == gvn || gw == gwn) return NULL; + if (gw == gvn->nextOnBoundary()) + { + t = EulerEdgeTriangle(gvn->prevBoundaryEdge(), gvn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gvn); + } + if (gw == gwn->prevOnBoundary()) + { + t = EulerEdgeTriangle(gwn->prevBoundaryEdge(), gwn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gwn); + } + } + + gve = gv->prevBoundaryEdge(); + gvn = gve->oppositeVertex(gv); + gwe = gw->nextBoundaryEdge(); + gwn = gwe->oppositeVertex(gw); + + Edge *je = CreateEdge(gv, gw); + Edge *je1 = CreateEdge(gv, gwn); + Edge *je2 = CreateEdge(gwn, gvn); + + t = CreateTriangle(je, gwe, je1); MARK_VISIT(t); + t = CreateTriangle(je1, je2, gve); MARK_VISIT(t); + + if (justconnect) return je; + + v = gv; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl1 += e->length(); } while (v != gv); + v = gw; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl2 += e->length(); } while (v != gw); + pl1 = tl1; pl2 = tl2; + + double c1, c2; + + e = je; + while (e->isOnBoundary()) + { + gv = (e->t2 != NULL) ? (e->v2) : (e->v1); gve = gv->nextBoundaryEdge(); + gw = (e->t1 != NULL) ? (e->v2) : (e->v1); gwe = gw->prevBoundaryEdge(); + c1 = fabs((pl1 - gve->length())*tl2 - pl2*tl1); + c2 = fabs((pl2 - gwe->length())*tl1 - pl1*tl2); + if (c1length(); + e = t->nextEdge(gve); + } else + { + t = EulerEdgeTriangle(gwe, e); MARK_VISIT(t); + pl2 -= gwe->length(); + e = t->prevEdge(gwe); + } + } + + if (refine) refineSelectedHolePatches(); + + return je; +} + } //namespace T_MESH diff --git a/src/mesh_fix/src/Algorithms/marchIntersections.cpp b/src/mesh_fix/src/Algorithms/marchIntersections.cpp index 8da0f440c3..d478131bdb 100644 --- a/src/mesh_fix/src/Algorithms/marchIntersections.cpp +++ b/src/mesh_fix/src/Algorithms/marchIntersections.cpp @@ -27,16 +27,16 @@ * based on a proper licensing contract. * * * ****************************************************************************/ - + #include "marchIntersections.h" namespace T_MESH { -int mc_ints::compare(const Data *e1, const Data *e2) +int mc_ints::compare(const Data &e1, const Data &e2) { - mc_ints *a = (mc_ints *)e1; - mc_ints *b = (mc_ints *)e2; + mc_ints* a = (mc_ints*)e1; + mc_ints* b = (mc_ints*)e2; coord& l1 = a->ic; coord& l2 = b->ic; if (l1 < l2) return -1; @@ -134,7 +134,7 @@ UBYTE mc_cell::lookdown() return i; } -int mc_cell::compare(const Data *e1, const Data *e2) +int mc_cell::compare(const Data &e1, const Data &e2) { mc_cell *a = (mc_cell *)e1; mc_cell *b = (mc_cell *)e2; @@ -680,7 +680,7 @@ void mc_cell::merge(mc_cell *m) List *mc_grid::createCells() { - int i,j,k=numrays+1; + int i,j,k,numcells=numrays+1; mc_ints *m; Node *n; List *ac = new List; @@ -821,9 +821,9 @@ void mc_grid::remesh(bool simplify_result) Triangle *t; Node *n; Basic_TMesh ntin; - ntin.V.joinTailList(&(tin->V)); - ntin.E.joinTailList(&(tin->E)); - ntin.T.joinTailList(&(tin->T)); + ntin.V.joinTailList(&(tin->V)); + ntin.E.joinTailList(&(tin->E)); + ntin.T.joinTailList(&(tin->T)); FOREACHVVVERTEX((&(ntin.V)), v, n) v->setValue(((*v)-origin)/norm); // Shift and normalize @@ -831,7 +831,7 @@ void mc_grid::remesh(bool simplify_result) int i=0; FOREACHVTTRIANGLE((&ntin.T), t, n) { - sample_triangle(t); t->info=NULL; + sample_triangle(t); t->info.forget(); if (!((i++)%1000)) TMesh::report_progress("%d %% done ",(i*50)/ntin.T.numels()); } @@ -866,9 +866,9 @@ void mc_grid::remesh(bool simplify_result) FOREACHVVVERTEX((&tin->V), v, n){ - v->info = NULL; + v->info.forget(); } - FOREACHVTTRIANGLE((&ntin.T), t, n) if (t->info) { delete ((Point *)t->info); t->info = NULL; } + FOREACHVTTRIANGLE((&ntin.T), t, n) t->info.clear(); TMesh::end_progress(); } @@ -904,46 +904,46 @@ bool mc_safeCollapse(Edge *e) return (n == NULL && e->collapse(orig)); } -//void mi_saveVRMLBorders(const char *filename, Basic_TMesh& tin) -//{ -// FILE *fp; -// int i; -// if ((fp = fopen(filename, "w")) == NULL) { TMesh::warning("Couldn't save graph!\n"); return; } -// -// fprintf(fp, "#VRML V1.0 ascii\nSeparator {\nMaterial { diffuseColor 1 0 0 }\nCoordinate3 {\npoint [\n"); -// Node *n; -// Edge *e; -// Vertex *v; -// i = 0; -// FOREACHVVVERTEX((&tin.V), v, n) -// { -// v->printPoint(fp); -// v->info = (void *)i; -// i++; -// } -// fprintf(fp, "]\n}\n"); -// -// fprintf(fp, "Material { diffuseColor 0.7 0.7 1 }\n"); -// fprintf(fp, "IndexedLineSet {\ncoordIndex [\n"); -// FOREACHVEEDGE((&tin.E), e, n) if (!IS_SHARPEDGE(e)) -// fprintf(fp, "%ld, %ld, -1,\n", (j_voidint)e->v1->info, (j_voidint)e->v2->info); -// fprintf(fp, "]\n}\n"); -// -// fprintf(fp, "Material { diffuseColor 1 0 0 }\n"); -// fprintf(fp, "IndexedLineSet {\ncoordIndex [\n"); -// FOREACHVEEDGE((&tin.E), e, n) if (IS_SHARPEDGE(e)) -// fprintf(fp, "%ld, %ld, -1,\n", (j_voidint)e->v1->info, (j_voidint)e->v2->info); -// fprintf(fp, "]\n}\n"); -// -// fprintf(fp, "Material { diffuseColor 0 1 0 }\nDrawStyle { pointSize 4 }\n"); -// -// fprintf(fp, "Separator {\nCoordinate3 {\npoint [\n"); -// FOREACHVVVERTEX((&tin.V), v, n) if (IS_VISITED2(v)) v->printPoint(fp); -// fprintf(fp, "]\n}\nPointSet {}\n}\n"); -// -// fprintf(fp, "}\n"); -// fclose(fp); -//} +//void mi_saveVRMLBorders(const char *filename, Basic_TMesh& tin) +//{ +// FILE *fp; +// int i; +// if ((fp = fopen(filename, "w")) == NULL) { TMesh::warning("Couldn't save graph!\n"); return; } +// +// fprintf(fp, "#VRML V1.0 ascii\nSeparator {\nMaterial { diffuseColor 1 0 0 }\nCoordinate3 {\npoint [\n"); +// Node *n; +// Edge *e; +// Vertex *v; +// i = 0; +// FOREACHVVVERTEX((&tin.V), v, n) +// { +// v->printPoint(fp); +// v->info = (void *)i; +// i++; +// } +// fprintf(fp, "]\n}\n"); +// +// fprintf(fp, "Material { diffuseColor 0.7 0.7 1 }\n"); +// fprintf(fp, "IndexedLineSet {\ncoordIndex [\n"); +// FOREACHVEEDGE((&tin.E), e, n) if (!IS_SHARPEDGE(e)) +// fprintf(fp, "%ld, %ld, -1,\n", (j_voidint)e->v1->info, (j_voidint)e->v2->info); +// fprintf(fp, "]\n}\n"); +// +// fprintf(fp, "Material { diffuseColor 1 0 0 }\n"); +// fprintf(fp, "IndexedLineSet {\ncoordIndex [\n"); +// FOREACHVEEDGE((&tin.E), e, n) if (IS_SHARPEDGE(e)) +// fprintf(fp, "%ld, %ld, -1,\n", (j_voidint)e->v1->info, (j_voidint)e->v2->info); +// fprintf(fp, "]\n}\n"); +// +// fprintf(fp, "Material { diffuseColor 0 1 0 }\nDrawStyle { pointSize 4 }\n"); +// +// fprintf(fp, "Separator {\nCoordinate3 {\npoint [\n"); +// FOREACHVVVERTEX((&tin.V), v, n) if (IS_VISITED2(v)) v->printPoint(fp); +// fprintf(fp, "]\n}\nPointSet {}\n}\n"); +// +// fprintf(fp, "}\n"); +// fclose(fp); +//} //bool mi_getCenterPosition(Triangle *t, Vertex **cp) //{ @@ -993,7 +993,7 @@ void mc_grid::simplify() FOREACHVVVERTEX((&tin->V), v, n) { t = ((Triangle *)v->info); - if (t->info != NULL) nnor = (Point *)t->info; + if (t->info.notEmpty()) nnor = (Point *)t->info; else t->info = nnor = new Point(t->getVector()); v->info = nnor; nnor->info = t; @@ -1036,4 +1036,4 @@ void mc_grid::simplify() FOREACHVVVERTEX((&tin->V), v, n) v->mask = 0; } -} //namespace T_MESH +} //namespace T_MESH diff --git a/src/mesh_fix/src/Kernel/graph.cpp b/src/mesh_fix/src/Kernel/graph.cpp index d8fc5b0843..b8b9de5383 100644 --- a/src/mesh_fix/src/Kernel/graph.cpp +++ b/src/mesh_fix/src/Kernel/graph.cpp @@ -28,192 +28,192 @@ * * ****************************************************************************/ -#include "graph.h" - -namespace T_MESH -{ - -graphEdge *graphNode::getEdge(graphNode *gn) -{ - graphEdge *ge; - Node *n = edges.head(); - while (n!=NULL) - if ((ge=((graphEdge *)n->data))->oppositeNode(this)==gn) return ge; - else n=n->next(); - return NULL; -} - -graphEdge::graphEdge(graphNode *a, graphNode *b) -{ - n1=a; n2=b; - n1->edges.appendHead(this); - n2->edges.appendHead(this); -} - - -graphEdge *Graph::createEdge(graphNode *n1, graphNode *n2) -{ - Node *n; - FOREACHNODE(n1->edges, n) - if (((graphEdge *)n->data)->hasNode(n2)) - return (graphEdge *)n->data; - - edges.appendHead(new graphEdge(n1, n2)); - return (graphEdge *)edges.head()->data; -} - - -void graphEdge::collapse() -{ - Node *n; - graphEdge *e; - graphNode *nx; - - while ((e = (graphEdge *)n2->edges.popHead()) != NULL) - if (e != this) - { - ((e->n1 == n2)?(e->n1):(e->n2)) = n1; - n1->edges.appendHead(e); - } - - FOREACHNODE(n1->edges, n) - { - e = (graphEdge *)n->data; - if (!e->isUnlinked()) e->oppositeNode(n1)->mask = 0; - } - - n2->mask = 1; - FOREACHNODE(n1->edges, n) - { - e = (graphEdge *)n->data; - if (e != this) - { - nx = e->oppositeNode(n1); - if (nx->mask) {nx->edges.removeNode(e); e->makeUnlinked();} - nx->mask = 1; - } - } - - n = n1->edges.head(); - while (n != NULL) - { - e = (graphEdge *)n->data; - n = n->next(); - if (e->isUnlinked()) n1->edges.removeCell((n!=NULL)?(n->prev()):n1->edges.tail()); - } - - FOREACHNODE(n1->edges, n) - ((graphEdge *)n->data)->oppositeNode(n1)->mask = 0; - - n1->edges.removeNode(this); - - makeUnlinked(); -} - - -Graph::~Graph() -{ - graphNode *gn; - graphEdge *ge; - while ((gn=(graphNode *)nodes.popHead())!=NULL) delete gn; - while ((ge=(graphEdge *)edges.popHead())!=NULL) delete ge; -} - -void Graph::deleteUnlinkedElements() -{ - Node *n; - graphNode *gn; - graphEdge *ge; - - n = nodes.head(); - while (n != NULL) - { - gn = (graphNode *)n->data; - n = n->next(); - if (gn->isIsolated()) - { - nodes.removeCell((n!=NULL)?(n->prev()):nodes.tail()); - delete(gn); - } - } - - n = edges.head(); - while (n != NULL) - { - ge = (graphEdge *)n->data; - n = n->next(); - if (ge->isUnlinked()) - { - edges.removeCell((n!=NULL)?(n->prev()):edges.tail()); - delete(ge); - } - } -} - -void Graph::unlinkEdge(graphEdge *e) -{ - e->n1->edges.removeNode(e); - e->n2->edges.removeNode(e); - e->makeUnlinked(); -} - -void Graph::destroyEdge(graphEdge *e) -{ - unlinkEdge(e); - edges.removeNode(e); - delete e; -} - -graphNode *Graph::unlinkNode(graphNode *a) -{ - graphEdge *e; - while ((e = (graphEdge *)a->edges.popHead())!=NULL) unlinkEdge(e); - return a; -} - -void graphEdge::invert() -{ - graphNode *tmp = n1; - n1 = n2; - n2 = tmp; -} - -bool Graph::isConnected() -{ - if (nodes.numels() < 2) return true; - - unsigned char *nmask = new unsigned char[nodes.numels()]; - Node *n; - graphNode *p, *q; - int i; - - for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++) - { - p = (graphNode *)n->data; - nmask[i]=p->mask; - p->mask=0; - } - - p = (graphNode *)nodes.head()->data; - List todo(p); p->mask = 1; - while ((p = (graphNode *)todo.popHead())!=NULL) - { - for (n=p->edges.head(); n!=NULL; n=n->next()) - { - q = ((graphEdge *)n->data)->oppositeNode(p); - if (q->mask==0) {todo.appendTail(q); q->mask=1;} - } - } - - bool is_connected = true; - for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++) - { - p = (graphNode *)n->data; - if (p->mask==0) is_connected=false; - p->mask = nmask[i]; - } - - return is_connected; -} - +#include "graph.h" + +namespace T_MESH +{ + +graphEdge *graphNode::getEdge(graphNode *gn) +{ + graphEdge *ge; + Node *n = edges.head(); + while (n!=NULL) + if ((ge=((graphEdge *)n->data))->oppositeNode(this)==gn) return ge; + else n=n->next(); + return NULL; +} + +graphEdge::graphEdge(graphNode *a, graphNode *b) +{ + n1=a; n2=b; + n1->edges.appendHead(this); + n2->edges.appendHead(this); +} + + +graphEdge *Graph::createEdge(graphNode *n1, graphNode *n2) +{ + Node *n; + FOREACHNODE(n1->edges, n) + if (((graphEdge *)n->data)->hasNode(n2)) + return (graphEdge *)n->data; + + edges.appendHead(new graphEdge(n1, n2)); + return (graphEdge *)edges.head()->data; +} + + +void graphEdge::collapse() +{ + Node *n; + graphEdge *e; + graphNode *nx; + + while ((e = (graphEdge *)n2->edges.popHead()) != NULL) + if (e != this) + { + ((e->n1 == n2)?(e->n1):(e->n2)) = n1; + n1->edges.appendHead(e); + } + + FOREACHNODE(n1->edges, n) + { + e = (graphEdge *)n->data; + if (!e->isUnlinked()) e->oppositeNode(n1)->mask = 0; + } + + n2->mask = 1; + FOREACHNODE(n1->edges, n) + { + e = (graphEdge *)n->data; + if (e != this) + { + nx = e->oppositeNode(n1); + if (nx->mask) {nx->edges.removeNode(e); e->makeUnlinked();} + nx->mask = 1; + } + } + + n = n1->edges.head(); + while (n != NULL) + { + e = (graphEdge *)n->data; + n = n->next(); + if (e->isUnlinked()) n1->edges.removeCell((n!=NULL)?(n->prev()):n1->edges.tail()); + } + + FOREACHNODE(n1->edges, n) + ((graphEdge *)n->data)->oppositeNode(n1)->mask = 0; + + n1->edges.removeNode(this); + + makeUnlinked(); +} + + +Graph::~Graph() +{ + graphNode *gn; + graphEdge *ge; + while ((gn=(graphNode *)nodes.popHead())!=NULL) delete gn; + while ((ge=(graphEdge *)edges.popHead())!=NULL) delete ge; +} + +void Graph::deleteUnlinkedElements() +{ + Node *n; + graphNode *gn; + graphEdge *ge; + + n = nodes.head(); + while (n != NULL) + { + gn = (graphNode *)n->data; + n = n->next(); + if (gn->isIsolated()) + { + nodes.removeCell((n!=NULL)?(n->prev()):nodes.tail()); + delete(gn); + } + } + + n = edges.head(); + while (n != NULL) + { + ge = (graphEdge *)n->data; + n = n->next(); + if (ge->isUnlinked()) + { + edges.removeCell((n!=NULL)?(n->prev()):edges.tail()); + delete(ge); + } + } +} + +void Graph::unlinkEdge(graphEdge *e) +{ + e->n1->edges.removeNode(e); + e->n2->edges.removeNode(e); + e->makeUnlinked(); +} + +void Graph::destroyEdge(graphEdge *e) +{ + unlinkEdge(e); + edges.removeNode(e); + delete e; +} + +graphNode *Graph::unlinkNode(graphNode *a) +{ + graphEdge *e; + while ((e = (graphEdge *)a->edges.popHead())!=NULL) unlinkEdge(e); + return a; +} + +void graphEdge::invert() +{ + graphNode *tmp = n1; + n1 = n2; + n2 = tmp; +} + +bool Graph::isConnected() +{ + if (nodes.numels() < 2) return true; + + unsigned char *nmask = new unsigned char[nodes.numels()]; + Node *n; + graphNode *p, *q; + int i; + + for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++) + { + p = (graphNode *)n->data; + nmask[i]=p->mask; + p->mask=0; + } + + p = (graphNode *)nodes.head()->data; + List todo(p); p->mask = 1; + while ((p = (graphNode *)todo.popHead())!=NULL) + { + for (n=p->edges.head(); n!=NULL; n=n->next()) + { + q = ((graphEdge *)n->data)->oppositeNode(p); + if (q->mask==0) {todo.appendTail(q); q->mask=1;} + } + } + + bool is_connected = true; + for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++) + { + p = (graphNode *)n->data; + if (p->mask==0) is_connected=false; + p->mask = nmask[i]; + } + + return is_connected; +} + } //namespace T_MESH diff --git a/src/mesh_fix/src/Kernel/heap.cpp b/src/mesh_fix/src/Kernel/heap.cpp index 59fc5a4185..7f2bd815b7 100644 --- a/src/mesh_fix/src/Kernel/heap.cpp +++ b/src/mesh_fix/src/Kernel/heap.cpp @@ -37,10 +37,9 @@ namespace T_MESH abstractHeap::abstractHeap(int size) { - heap = new Data *[size+1]; + heap = new Data[size+1]; numels = 0; maxels = size; - positions = NULL; } abstractHeap::~abstractHeap() @@ -52,19 +51,15 @@ int abstractHeap::upheap(int k) { if (k < 2) return k; - Data *t = heap[k]; + Data t = heap[k]; int fk = (k%2)?((k-1)/2):(k/2); - Data *f = heap[fk]; + Data f = heap[fk]; if (compare(t, f) <= 0) { heap[k] = f; heap[fk] = t; - if (positions != NULL) - { - positions[to_int(f)] = k; - positions[to_int(t)] = fk; - } + return upheap(fk); } return k; @@ -74,45 +69,38 @@ int abstractHeap::downheap(int k) { int j; - Data *t = heap[k]; + Data t = heap[k]; int fk = (numels%2)?((numels-1)/2):(numels/2); if (k > fk) return k; j = k+k; if (j < numels && compare(heap[j], heap[j+1]) >= 0) j++; - Data *f = heap[j]; + Data f = heap[j]; if (compare(t, f) >= 0) { heap[k] = f; heap[j] = t; - if (positions != NULL) - { - positions[to_int(f)] = k; - positions[to_int(t)] = j; - } + return downheap(j); } return k; } -int abstractHeap::insert(Data *t) +int abstractHeap::insert(const Data& t) { if (numels == maxels) return -1; heap[++numels] = t; - if (positions != NULL) positions[to_int(t)] = numels; return upheap(numels); } -Data *abstractHeap::removeHead() +Data abstractHeap::removeHead() { - Data *t = heap[1]; - if (positions != NULL) positions[to_int(t)] = 0; + Data t = heap[1]; heap[1] = heap[numels--]; if (numels) { - if (positions != NULL) positions[to_int(heap[1])] = 1; downheap(1); } diff --git a/src/mesh_fix/src/Kernel/jqsort.cpp b/src/mesh_fix/src/Kernel/jqsort.cpp index 554cbc9e5e..78122ce814 100644 --- a/src/mesh_fix/src/Kernel/jqsort.cpp +++ b/src/mesh_fix/src/Kernel/jqsort.cpp @@ -34,8 +34,7 @@ #include #include #endif - -#include "basics.h" +#include "jqsort.h" namespace T_MESH { @@ -70,15 +69,15 @@ void jqsort(void *v[], int numels, int(*comp)(const void *, const void *)) class compobj { - int(*comp)(const Data *, const Data *); + int(*comp)(const Data&, const Data&); public: - compobj(int(*c)(const Data *, const Data *)) { comp = c; } + compobj(int(*c)(const Data&, const Data&)) { comp = c; } - bool operator()(Data *a, Data *b) { return (comp(a, b) < 0); } + bool operator()(const Data& a, const Data& b) { return (comp(a, b) < 0); } }; -void jqsort(Data *v[], int numels, int(*comp)(const Data *, const Data *)) +void jqsort(Data *v, int numels, int(*comp)(const Data&, const Data&)) { compobj a(comp); std::sort(v, v + numels, a); diff --git a/src/mesh_fix/src/Kernel/list.cpp b/src/mesh_fix/src/Kernel/list.cpp index d5a0e37645..d768c8d92d 100644 --- a/src/mesh_fix/src/Kernel/list.cpp +++ b/src/mesh_fix/src/Kernel/list.cpp @@ -39,9 +39,9 @@ namespace T_MESH // Create a new node containing 'd', and link it to // // 'p' on the left (prev) and to 'n' on the right (next). // -Node::Node(const Node *p, const Data *d, const Node *n) +Node::Node(const Node *p, const Data& d, const Node *n) { - data=(Data *)d; + data=d; if ((n_prev=(Node *)p) != NULL) n_prev->n_next = this; if ((n_next=(Node *)n) != NULL) n_next->n_prev = this; } @@ -58,7 +58,7 @@ Node::~Node() /////////// Constructor from list /////////////////// -List::List(const Data **d, int n) +List::List(const Data *d, int n) { l_head = l_tail = NULL; l_numels = 0; for (int i=0; inext()); if (b == l_tail) l_tail = nn; @@ -141,25 +141,25 @@ void List::moveNodeTo(Node *n, List *l) //// Removes the first node and returns the corresponding data ///// -Data *List::popHead() +Data List::popHead() { - Data *data = (l_head != NULL)?(l_head->data):(NULL); + Data data = (l_head != NULL)?(l_head->data):(Data()); if (l_head != NULL) removeCell(l_head); return data; } //// Removes the last node and returns the corresponding data ///// -Data *List::popTail() +Data List::popTail() { - Data *data = (l_tail != NULL)?(l_tail->data):(NULL); + Data data = (l_tail != NULL)?(l_tail->data):(Data()); if (l_tail != NULL) removeCell(l_tail); return data; } //////////////////// Removes an element ////////////////// -int List::removeNode(const Data *d) +int List::removeNode(const Data& d) { Node *tmp = l_head; int i=1; @@ -216,19 +216,17 @@ void List::removeCell(Node *n) void List::freeCell(Node *n) { - delete(n->data); removeCell(n); } -void List::freeNode(Data *d) +void List::freeNode(const Data& d) { - delete(d); removeNode(d); } //////////////////// Belonging check ///////////////// -Node *List::containsNode(const Data *d) const +Node *List::containsNode(const Data& d) const { Node *tmp = l_head; @@ -241,10 +239,10 @@ Node *List::containsNode(const Data *d) const //////////////////// Replaces a node ///////////////// -Node *List::replaceNode(const Data *od, const Data *nd) +Node *List::replaceNode(const Data& od, const Data& nd) { Node *tmp = containsNode(od); - if (tmp != NULL) { tmp->data = (Data *)nd; return tmp;} + if (tmp != NULL) {tmp->data = nd; return tmp;} appendTail(nd); return l_tail; } @@ -266,14 +264,14 @@ void List::removeNodes() ///// Conversion to array /////// -Data **List::toArray() const +Data *List::toArray() const { Node *n = l_head; int i; - Data **array; + Data *array; if (l_numels == 0) return NULL; - array = (Data **)malloc(sizeof(Data *)*l_numels); + array = new Data[l_numels]; if (array == NULL) return NULL; for (i=0; in_next) array[i] = n->data; @@ -282,9 +280,9 @@ Data **List::toArray() const ///// Sorts the list ///////// -int List::sort(int (*comp)(const Data *, const Data *)) +int List::sort(int (*comp)(const Data&, const Data&)) { - Data **array; + Data *array; int ne = l_numels-1; if (l_numels < 2) return 0; @@ -293,7 +291,7 @@ int List::sort(int (*comp)(const Data *, const Data *)) jqsort(array, l_numels, comp); removeNodes(); for (; ne >= 0; ne--) appendHead(array[ne]); - free(array); + delete [] array; return 0; } diff --git a/src/mesh_fix/src/Kernel/matrix.cpp b/src/mesh_fix/src/Kernel/matrix.cpp index 0ff18e249e..5d8affec43 100644 --- a/src/mesh_fix/src/Kernel/matrix.cpp +++ b/src/mesh_fix/src/Kernel/matrix.cpp @@ -28,714 +28,713 @@ * * ****************************************************************************/ -#include -#include "matrix.h" - -namespace T_MESH -{ - -#define FABS(a) (((a)<0)?(-(a)):((a))) - -////////////////////////////////////////////////////////////////////////// -// -// Generic 3x3 matrix -// -////////////////////////////////////////////////////////////////////////// - -// Plain constructor - -Matrix3x3::Matrix3x3(const double& a11, const double& a12, const double& a13, - const double& a21, const double& a22, const double& a23, - const double& a31, const double& a32, const double& a33) -{ - M[0] = a11; M[1] = a12; M[2] = a13; - M[3] = a21; M[4] = a22; M[5] = a23; - M[6] = a31; M[7] = a32; M[8] = a33; -} - - -// Matrix T(v1,v2,v3)*(w1,w2,w3). - +#include +#include "matrix.h" + +namespace T_MESH +{ + + +////////////////////////////////////////////////////////////////////////// +// +// Generic 3x3 matrix +// +////////////////////////////////////////////////////////////////////////// + +// Plain constructor + +Matrix3x3::Matrix3x3(const double& a11, const double& a12, const double& a13, + const double& a21, const double& a22, const double& a23, + const double& a31, const double& a32, const double& a33) +{ + M[0] = a11; M[1] = a12; M[2] = a13; + M[3] = a21; M[4] = a22; M[5] = a23; + M[6] = a31; M[7] = a32; M[8] = a33; +} + + +// Matrix T(v1,v2,v3)*(w1,w2,w3). + Matrix3x3::Matrix3x3(const double& v1, const double& v2, const double& v3, - const double& w1, const double& w2, const double& w3) -{ - M[0] = v1*w1; M[1] = v1*w2; M[2] = v1*w3; - M[3] = v2*w1; M[4] = v2*w2; M[5] = v2*w3; - M[6] = v3*w1; M[7] = v3*w2; M[8] = v3*w3; -} - - -// Symmetric matrix T(x,y,z)*(x,y,z) - -Matrix3x3::Matrix3x3(const double& x, const double& y, const double& z) -{ - M[0] = x*x; M[1] = x*y; M[2] = x*z; - M[3] = M[1]; M[4] = y*y; M[5] = y*z; - M[6] = M[2]; M[7] = M[5]; M[8] = z*z; -} - - -// Self-sum - -void Matrix3x3::operator+=(const Matrix3x3& s) -{ - M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2]; - M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5]; - M[6] += s.M[6]; M[7] += s.M[7]; M[8] += s.M[8]; -} - - -// Self-subtraction - -void Matrix3x3::operator-=(const Matrix3x3& s) -{ - M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2]; - M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5]; - M[6] -= s.M[6]; M[7] -= s.M[7]; M[8] -= s.M[8]; -} - - -// Self-multiplication - -void Matrix3x3::operator*=(const double& d) -{ - M[0] *= d; M[1] *= d; M[2] *= d; - M[3] *= d; M[4] *= d; M[5] *= d; - M[6] *= d; M[7] *= d; M[8] *= d; -} - - -// Sum - -Matrix3x3 Matrix3x3::operator+(const Matrix3x3& s) const -{ - return Matrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2], - M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5], - M[6]+s.M[6], M[7]+s.M[7], M[8]+s.M[8]); -} - - -// Scalar Multiplication - -Matrix3x3 Matrix3x3::operator*(const double& d) const -{ - return Matrix3x3(M[0]*d, M[1]*d, M[2]*d, - M[3]*d, M[4]*d, M[5]*d, - M[6]*d, M[7]*d, M[8]*d); -} - - -// Matrix multiplication - -Matrix3x3 Matrix3x3::operator*(const Matrix3x3& q) const -{ - return Matrix3x3( - M[0]*q.M[0]+M[1]*q.M[3]+M[2]*q.M[6], M[0]*q.M[1]+M[1]*q.M[4]+M[2]*q.M[7], M[0]*q.M[2]+M[1]*q.M[5]+M[2]*q.M[8], - M[3]*q.M[0]+M[4]*q.M[3]+M[5]*q.M[6], M[3]*q.M[1]+M[4]*q.M[4]+M[5]*q.M[7], M[3]*q.M[2]+M[4]*q.M[5]+M[5]*q.M[8], - M[6]*q.M[0]+M[7]*q.M[3]+M[8]*q.M[6], M[6]*q.M[1]+M[7]*q.M[4]+M[8]*q.M[7], M[6]*q.M[2]+M[7]*q.M[5]+M[8]*q.M[8] - ); -} - - -// Matrix transpose - -Matrix3x3 Matrix3x3::operator~() const -{ - return Matrix3x3(M[0],M[3],M[6],M[1],M[4],M[7],M[2],M[5],M[8]); -} - - -// Computes (x,y,z)*M*(x,y,z) - -double Matrix3x3::lrMultiply(const double& x, const double& y, const double& z) const -{ - return (x*(x*M[0] + y*M[3] + z*M[6]) + y*(x*M[1] + y*M[4] + z*M[7]) + z*(x*M[2] + y*M[5] + z*M[8])); -} - - -// Computes v*M*w + const double& w1, const double& w2, const double& w3) +{ + M[0] = v1*w1; M[1] = v1*w2; M[2] = v1*w3; + M[3] = v2*w1; M[4] = v2*w2; M[5] = v2*w3; + M[6] = v3*w1; M[7] = v3*w2; M[8] = v3*w3; +} + + +// Symmetric matrix T(x,y,z)*(x,y,z) + +Matrix3x3::Matrix3x3(const double& x, const double& y, const double& z) +{ + M[0] = x*x; M[1] = x*y; M[2] = x*z; + M[3] = M[1]; M[4] = y*y; M[5] = y*z; + M[6] = M[2]; M[7] = M[5]; M[8] = z*z; +} + + +// Self-sum + +void Matrix3x3::operator+=(const Matrix3x3& s) +{ + M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2]; + M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5]; + M[6] += s.M[6]; M[7] += s.M[7]; M[8] += s.M[8]; +} + + +// Self-subtraction + +void Matrix3x3::operator-=(const Matrix3x3& s) +{ + M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2]; + M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5]; + M[6] -= s.M[6]; M[7] -= s.M[7]; M[8] -= s.M[8]; +} + + +// Self-multiplication + +void Matrix3x3::operator*=(const double& d) +{ + M[0] *= d; M[1] *= d; M[2] *= d; + M[3] *= d; M[4] *= d; M[5] *= d; + M[6] *= d; M[7] *= d; M[8] *= d; +} + + +// Sum + +Matrix3x3 Matrix3x3::operator+(const Matrix3x3& s) const +{ + return Matrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2], + M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5], + M[6]+s.M[6], M[7]+s.M[7], M[8]+s.M[8]); +} + + +// Scalar Multiplication + +Matrix3x3 Matrix3x3::operator*(const double& d) const +{ + return Matrix3x3(M[0]*d, M[1]*d, M[2]*d, + M[3]*d, M[4]*d, M[5]*d, + M[6]*d, M[7]*d, M[8]*d); +} + + +// Matrix multiplication + +Matrix3x3 Matrix3x3::operator*(const Matrix3x3& q) const +{ + return Matrix3x3( + M[0]*q.M[0]+M[1]*q.M[3]+M[2]*q.M[6], M[0]*q.M[1]+M[1]*q.M[4]+M[2]*q.M[7], M[0]*q.M[2]+M[1]*q.M[5]+M[2]*q.M[8], + M[3]*q.M[0]+M[4]*q.M[3]+M[5]*q.M[6], M[3]*q.M[1]+M[4]*q.M[4]+M[5]*q.M[7], M[3]*q.M[2]+M[4]*q.M[5]+M[5]*q.M[8], + M[6]*q.M[0]+M[7]*q.M[3]+M[8]*q.M[6], M[6]*q.M[1]+M[7]*q.M[4]+M[8]*q.M[7], M[6]*q.M[2]+M[7]*q.M[5]+M[8]*q.M[8] + ); +} + + +// Matrix transpose + +Matrix3x3 Matrix3x3::operator~() const +{ + return Matrix3x3(M[0],M[3],M[6],M[1],M[4],M[7],M[2],M[5],M[8]); +} + + +// Computes (x,y,z)*M*(x,y,z) + +double Matrix3x3::lrMultiply(const double& x, const double& y, const double& z) const +{ + return (x*(x*M[0] + y*M[3] + z*M[6]) + y*(x*M[1] + y*M[4] + z*M[7]) + z*(x*M[2] + y*M[5] + z*M[8])); +} + + +// Computes v*M*w double Matrix3x3::lrMultiply(const double& v1, const double& v2, const double& v3, const double& w1, const double& w2, const double& w3) const { - return (w1*(v1*M[0] + v2*M[3] + v3*M[6]) + w2*(v1*M[1] + v2*M[4] + v3*M[7]) + w3*(v1*M[2] + v2*M[5] + v3*M[8])); -} - -Matrix3x3 Matrix3x3::transpose() const -{ - return Matrix3x3(M[0], M[3], M[6], - M[1], M[4], M[7], - M[2], M[5], M[8]); -} - -////////////////////////////////////////////////////////////////////////// -// -// Symmetric 3x3 matrix -// -////////////////////////////////////////////////////////////////////////// - -// Plain constructor - -SymMatrix3x3::SymMatrix3x3(const double&a11, const double&a12, const double&a22, - const double&a13, const double&a23, const double&a33) -{ - M[0] = a11; M[1] = a12; M[3] = a13; - M[2] = a22; M[4] = a23; - M[5] = a33; -} - - -// Symmetric matrix T(x,y,z)*(x,y,z) - -SymMatrix3x3::SymMatrix3x3(const double& x, const double& y, const double& z) -{ - M[0] = x*x; M[1] = x*y; M[3] = x*z; - M[2] = y*y; M[4] = y*z; - M[5] = z*z; -} - - -// Constructor from generic matrix - -SymMatrix3x3::SymMatrix3x3(const Matrix3x3& q) -{ - M[0] = q.M[0]; M[1] = q.M[1]; M[3] = q.M[2]; - M[2] = q.M[4]; M[4] = q.M[5]; - M[5] = q.M[8]; -} - - -// Self-sum - -void SymMatrix3x3::operator+=(const SymMatrix3x3& s) -{ - M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2]; - M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5]; -} - - -// Self-subtraction - -void SymMatrix3x3::operator-=(const SymMatrix3x3& s) -{ - M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2]; - M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5]; -} - - -// Self-multiplication - -void SymMatrix3x3::operator*=(const double& d) -{ - M[0] *= d; M[1] *= d; M[2] *= d; - M[3] *= d; M[4] *= d; M[5] *= d; -} - - -// Sum - -SymMatrix3x3 SymMatrix3x3::operator+(const SymMatrix3x3& s) const -{ - return SymMatrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2], - M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5]); -} - - -// Multiplication - -SymMatrix3x3 SymMatrix3x3::operator*(const double& d) const -{ - return SymMatrix3x3(M[0]*d, M[1]*d, M[2]*d, M[3]*d, M[4]*d, M[5]*d); -} - - -// Computes (x,y,z)*M*(x,y,z) - -double SymMatrix3x3::lrMultiply(const double& x, const double& y, const double& z) const -{ - double a,b,c; - a = x*M[0] + y*M[1] + z*M[3]; - b = x*M[1] + y*M[2] + z*M[4]; - c = x*M[3] + y*M[4] + z*M[5]; - return (x*a + y*b + z*c); -} - - - -// Computes v*M*w + return (w1*(v1*M[0] + v2*M[3] + v3*M[6]) + w2*(v1*M[1] + v2*M[4] + v3*M[7]) + w3*(v1*M[2] + v2*M[5] + v3*M[8])); +} + +Matrix3x3 Matrix3x3::transpose() const +{ + return Matrix3x3(M[0], M[3], M[6], + M[1], M[4], M[7], + M[2], M[5], M[8]); +} + +////////////////////////////////////////////////////////////////////////// +// +// Symmetric 3x3 matrix +// +////////////////////////////////////////////////////////////////////////// + +// Plain constructor + +SymMatrix3x3::SymMatrix3x3(const double&a11, const double&a12, const double&a22, + const double&a13, const double&a23, const double&a33) +{ + M[0] = a11; M[1] = a12; M[3] = a13; + M[2] = a22; M[4] = a23; + M[5] = a33; +} + + +// Symmetric matrix T(x,y,z)*(x,y,z) + +SymMatrix3x3::SymMatrix3x3(const double& x, const double& y, const double& z) +{ + M[0] = x*x; M[1] = x*y; M[3] = x*z; + M[2] = y*y; M[4] = y*z; + M[5] = z*z; +} + + +// Constructor from generic matrix + +SymMatrix3x3::SymMatrix3x3(const Matrix3x3& q) +{ + M[0] = q.M[0]; M[1] = q.M[1]; M[3] = q.M[2]; + M[2] = q.M[4]; M[4] = q.M[5]; + M[5] = q.M[8]; +} + + +// Self-sum + +void SymMatrix3x3::operator+=(const SymMatrix3x3& s) +{ + M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2]; + M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5]; +} + + +// Self-subtraction + +void SymMatrix3x3::operator-=(const SymMatrix3x3& s) +{ + M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2]; + M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5]; +} + + +// Self-multiplication + +void SymMatrix3x3::operator*=(const double& d) +{ + M[0] *= d; M[1] *= d; M[2] *= d; + M[3] *= d; M[4] *= d; M[5] *= d; +} + + +// Sum + +SymMatrix3x3 SymMatrix3x3::operator+(const SymMatrix3x3& s) const +{ + return SymMatrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2], + M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5]); +} + + +// Multiplication + +SymMatrix3x3 SymMatrix3x3::operator*(const double& d) const +{ + return SymMatrix3x3(M[0]*d, M[1]*d, M[2]*d, M[3]*d, M[4]*d, M[5]*d); +} + + +// Computes (x,y,z)*M*(x,y,z) + +double SymMatrix3x3::lrMultiply(const double& x, const double& y, const double& z) const +{ + double a,b,c; + a = x*M[0] + y*M[1] + z*M[3]; + b = x*M[1] + y*M[2] + z*M[4]; + c = x*M[3] + y*M[4] + z*M[5]; + return (x*a + y*b + z*c); +} + + + +// Computes v*M*w double SymMatrix3x3::lrMultiply(const double& v1, const double& v2, const double& v3, const double& w1, const double& w2, const double& w3) const { - return (w1*(v1*M[0] + v2*M[1] + v3*M[3]) + w2*(v1*M[1] + v2*M[2] + v3*M[4]) + w3*(v1*M[3] + v2*M[4] + v3*M[5])); -} - -// Invert the matrix. If singular return FALSE - -bool SymMatrix3x3::invert() -{ - double det, pos, neg, t, out[6]; - - pos = neg = 0.0; - t = M[0]*M[2]*M[5]; ((t >= 0.0)?(pos):(neg)) += t; - t = M[1]*M[4]*M[3]; ((t >= 0.0)?(pos):(neg)) += t; - t = M[3]*M[1]*M[4]; ((t >= 0.0)?(pos):(neg)) += t; - t = -M[3]*M[2]*M[3]; ((t >= 0.0)?(pos):(neg)) += t; - t = -M[1]*M[1]*M[5]; ((t >= 0.0)?(pos):(neg)) += t; - t = -M[0]*M[4]*M[4]; ((t >= 0.0)?(pos):(neg)) += t; - det = pos+neg; - - t = det/(pos-neg); - if (FABS(t) >= 1.0e-15) - { - out[0] = (M[2] * M[5] - M[4] * M[4]) /det; - out[1] = -(M[1] * M[5] - M[4] * M[3]) /det; - out[2] = (M[0] * M[5] - M[3] * M[3]) /det; - out[3] = (M[1] * M[4] - M[2] * M[3]) /det; - out[4] = -(M[0] * M[4] - M[1] * M[3]) /det; - out[5] = (M[0] * M[2] - M[1] * M[1]) /det; - M[0] = out[0]; M[1] = out[1]; M[2] = out[2]; - M[3] = out[3]; M[4] = out[4]; M[5] = out[5]; - return 1; - } - - return 0; -} - - -// Compute eigenvalues and eigenvectors of the matrix (JACOBI method). -// The calling function is responsible of verifying that the matrix -// is diagonalizable. -// -// This routine was inspired from a software to estimate curvature -// tensors developed at INRIA. Visit the following link for details: -// http://www-sop.inria.fr/geometrica/team/Pierre.Alliez/demos/curvature/ -// -// This version has been slightly optimized. -// - -void SymMatrix3x3::diagonalize(double *eigen_val, double *eigen_vec) const -{ - static const double EPS = 0.00001; - static const double cos_pi_4 = 0.70710678; - static const int MAX_ITER = 100; - double a_P[6], v_P[9]; - double *a = a_P, *v = v_P; - double a_norm,a_normEPS,thr,thr_nn; - int nb_iter = 0; - int i,j,k,ij,jj,ik,l,m,lm,mq,lq,ll,mm,imv,im,iq,ilv,il; - int index_P[3]; - int *index = index_P; - double a_ij,a_lm,a_ll,a_mm,a_im,a_il,a_lm_2,v_ilv,v_imv,x; - double sinx,sinx_2,cosx,cosx_2,sincos,delta; - - a[0] = M[0]; a[1] = M[1]; a[2] = M[2]; - a[3] = M[3]; a[4] = M[4]; a[5] = M[5]; - a--; - - // Step 2 : Init diagonalization matrix as the unit matrix - - for (ij=0, i=0; i<3; i++) for (j=0; j<3; j++) v[ij++] = (i==j)?(1.0):(0.0); - v--; - - // Step 3 : compute the weight of the non diagonal terms - - a_norm = 0.0; - for (i=1, ij=1; i<=3; i++) for (j=1; j<=i; j++, ij++) if( i!=j ) {a_ij = a[ij]; a_norm += a_ij*a_ij;} - - if( a_norm != 0.0 ) - { - a_normEPS = a_norm*EPS; - thr = a_norm ; - - // Step 4 : rotations - while (thr > a_normEPS && nb_iter < MAX_ITER) - { - nb_iter++; - thr_nn = thr / 6; - - for (l=1; l<3; l++) - for (m=l+1; m<=3; m++) - { - // compute sinx and cosx - - lq = (l*l-l)/2; mq = (m*m-m)/2; - lm = l+mq; a_lm = a[lm]; - a_lm_2 = a_lm*a_lm; - - if( a_lm_2 < thr_nn ) continue; - - ll = l+lq; mm = m+mq; - a_ll = a[ll]; a_mm = a[mm]; - delta = a_ll - a_mm; - - if (delta==0.0) {sinx = -cos_pi_4; cosx = cos_pi_4;} - else {x = -atan( (a_lm+a_lm) / delta )/2.0; sinx=sin(x); cosx=cos(x);} - - sinx_2 = sinx*sinx; - cosx_2 = cosx*cosx; - sincos = sinx*cosx; - - // rotate L and M columns - - ilv = 3*(l-1); imv = 3*(m-1); - - for( i=1; i<=3;i++ ) - { - if( (i!=l) && (i!=m) ) - { - iq = (i*i-i)/2; - im = (i1.0e-12) {*L1 = *L2 = *L3 = a11; return;} // Evecs = (1,0,0), (0,1,0), (0,0,1) - - double l1, l2, l3; // Eigenvalues to be computed - - if (Q>=0) {double p=(b>0)?(pow(b/2, 1.0/3.0)):(0); l1=l2=((c2/3.0)+p); l3=((c2/3.0)-2.0*p);} - else - { - double t = atan2(sqrt(-Q), -b/2.0)/3.0, r = pow(((b*b)/4.0)-Q, 1.0/6.0); - double cos_t = cos(t), sin_t = sin(t); - const double sq3 = sqrt(3.0); - l1 = l2 = l3 = (c2/3.0); - l1 += (2*r*cos_t); - l2 -= r*(cos_t+sq3*sin_t); - l3 -= r*(cos_t-sq3*sin_t); - } - - if (l1<=l2 && l1<=l3) {*L1=l1; *L2=(l2=l2 && l1>=l3) {c0=u11; c1=u12; c2=u13; l=l1;} - else if (l2>=l1 && l2>=l3) {c0=u12; c1=u22; c2=u23; l=l2;} - else {c0=u13; c1=u23; c2=u33; l=l3;} - - l1 = sqrt(l); *x = c0/l1; *y = c1/l1; *z = c2/l1; - - return l; -} - - -// Computes the eigenvector corresp. to the maximum eigenvalue - -void SymMatrix3x3::getMaxEigenvector(double *x, double *y, double *z) const -{ - SymMatrix3x3(-M[0], -M[1], -M[2], -M[3], -M[4], -M[5]).getMinEigenvector(x, y, z); -} - -// Prints the matrix values - -void SymMatrix3x3::print(FILE *fp) const -{ - fprintf(fp,"%e %e %e\n",M[0],M[1],M[3]); - fprintf(fp,"%e %e %e\n",M[1],M[2],M[4]); - fprintf(fp,"%e %e %e\n",M[3],M[4],M[5]); -} - - -////////////////////////////////////////////////////////////////////////// -// -// Symmetric 4x4 matrix -// -////////////////////////////////////////////////////////////////////////// - -// Extend a 3x3 matrix - -SymMatrix4x4::SymMatrix4x4(const SymMatrix3x3& q) -{ - a2 = q.M[0]; ab = q.M[1]; ac = q.M[3]; ad = 0; - b2 = q.M[2]; bc = q.M[4]; bd = 0; - c2 = q.M[5]; cd = 0; d2 = 1; -} - - -// Build a quadric - -SymMatrix4x4::SymMatrix4x4(const coord& a, const coord& b, const coord& c, const coord& d) -{ - a2 = a*a; ab = a*b; ac = a*c; ad = a*d; - b2 = b*b; bc = b*c; bd = b*d; - c2 = c*c; cd = c*d; d2 = d*d; -} - -// True iff equal - -bool SymMatrix4x4::operator==(const SymMatrix4x4& q) -{ - return ( - a2 == q.a2 && ab == q.ab && ac == q.ac && ad == q.ad &&\ - b2 == q.b2 && bc == q.bc && bd == q.bd &&\ - c2 == q.c2 && cd == q.cd && d2 == q.d2); -} - -// True iff different - -bool SymMatrix4x4::operator!=(const SymMatrix4x4& q) -{ - return ( - a2 != q.a2 || ab != q.ab || ac != q.ac || ad != q.ad ||\ - b2 != q.b2 || bc != q.bc || bd != q.bd ||\ - c2 != q.c2 || cd != q.cd || d2 != q.d2); -} - -// Sum the matrix 'q' to the current matrix - -void SymMatrix4x4::operator+=(const SymMatrix4x4& q) -{ - a2 += q.a2; ab += q.ab; ac += q.ac; ad += q.ad; - b2 += q.b2; bc += q.bc; bd += q.bd; - c2 += q.c2; cd += q.cd; d2 += q.d2; -} - -// Returns the sum of the matrix with another matrix 'q' - -SymMatrix4x4 SymMatrix4x4::operator+(const SymMatrix4x4& q) const -{ - SymMatrix4x4 n; - - n.a2=a2+q.a2; n.ab=ab+q.ab; n.ac=ac+q.ac; n.ad=ad+q.ad; - n.b2=b2+q.b2; n.bc=bc+q.bc; n.bd=bd+q.bd; - n.c2=c2+q.c2; n.cd=cd+q.cd; n.d2=d2+q.d2; - - return n; -} - -// Returns the product of the matrix with a scalar - -SymMatrix4x4 SymMatrix4x4::operator*(const coord& d) const -{ - SymMatrix4x4 n; - - n.a2=a2*d; n.ab=ab*d; n.ac=ac*d; n.ad=ad*d; - n.b2=b2*d; n.bc=bc*d; n.bd=bd*d; - n.c2=c2*d; n.cd=cd*d; n.d2=d2*d; - - return n; -} - -void SymMatrix4x4::add(const coord& a, const coord& b, const coord& c, const coord& d) -{ - a2 += a*a; ab += a*b; ac += a*c; ad += a*d; - b2 += b*b; bc += b*c; bd += b*d; - c2 += c*c; cd += c*d; d2 += d*d; -} - - -// Computes (a,b,c,w)*M*(a,b,c,w) - -coord SymMatrix4x4::lrMultiply(const coord& x, const coord& y, const coord& z, const coord& w) const -{ - coord a,b,c,d; - a = x*a2 + y*ab + z*ac + w*ad; - b = x*ab + y*b2 + z*bc + w*bd; - c = x*ac + y*bc + z*c2 + w*cd; - d = x*ad + y*bd + z*cd + w*d2; - return (x*a + y*b + z*c + w*d); -} - -// Computes (a,b,c) s.t. (a,b,c,1)*M*(a,b,c,1) is minimized -// Returns FALSE if the minimizer is not unique - -bool SymMatrix4x4::getMinimizer(coord *a, coord *b, coord *c) const -{ - coord det, pos, neg, t; - - pos = neg = 0.0; - t = a2*b2*c2; ((t >= 0.0)?(pos):(neg)) += t; - t = ab*bc*ac; ((t >= 0.0)?(pos):(neg)) += t; - t = ac*ab*bc; ((t >= 0.0)?(pos):(neg)) += t; - t = -ac*b2*ac; ((t >= 0.0)?(pos):(neg)) += t; - t = -ab*ab*c2; ((t >= 0.0)?(pos):(neg)) += t; - t = -a2*bc*bc; ((t >= 0.0)?(pos):(neg)) += t; - det = pos+neg; - - if (pos == neg) return 0; - - t = det/(pos-neg); - if ( -#ifdef USE_HYBRID_KERNEL - (coord::isUsingRationals() && t!=0) || -#endif - (FABS(t) >= 1.0e-15)) - { - *a = -(ad*( (b2*c2 - bc*bc)) + bd*(-(ab*c2 - bc*ac)) + cd*( (ab*bc - b2*ac)))/det; - *b = -(ad*(-(ab*c2 - ac*bc)) + bd*( (a2*c2 - ac*ac)) + cd*(-(a2*bc - ab*ac)))/det; - *c = -(ad*( (ab*bc - ac*b2)) + bd*(-(a2*bc - ac*ab)) + cd*( (a2*b2 - ab*ab)))/det; - return 1; - } - - return 0; -} - - -// Invert a symmetric 4x4 matrix using L*D*L^T decomposition. -// The calling function is responsible of verifying that the matrix -// is positive definite. -// - -bool SymMatrix4x4::invert() -{ - if (a2 <= 0) return false; - - coord d00 = coord(1.0) / a2; - coord L10 = ab; - coord l10 = ab*d00; - coord L20 = ac; - coord l20 = ac*d00; - coord L30 = ad; - coord l30 = ad*d00; - coord d11 = b2-(L10*l10); - - if (d11 <= 0) return false; else d11 = coord(1.0)/d11; - - coord L21 = (bc-(L10*l20)); - coord l21 = L21*d11; - coord L31 = (bd-(L10*l30)); - coord l31 = L31*d11; - coord d22 = c2-(L20*l20)-(L21*l21); - - if (d22 <= 0) return false; else d22 = coord(1.0) / d22; - - coord L32 = (cd-(L20*l30)-(L21*l31)); - coord l32 = L32*d22; - coord d33 = d2-(L30*l30)-(L31*l31)-(L32*l32); - - if (d33 <= 0) return false; else d33 = coord(1.0) / d33; - - L20 = l10*l21-l20; - L31 = l21*l32-l31; - L30 = l32*l20-L31*l10-l30; - - a2 = d00+(-l10)*((-l10)*d11)+L20*(L20*d22)+L30*(L30*d33); - ab = ((-l10)*d11)+L20*((-l21)*d22)+L30*(L31*d33); - b2 = d11+(-l21)*((-l21)*d22)+L31*(L31*d33); - ac = (L20*d22)+L30*((-l32)*d33); - bc = ((-l21)*d22)+L31*((-l32)*d33); - c2 = d22+(-l32)*((-l32)*d33); - ad = (L30*d33); - bd = (L31*d33); - cd = ((-l32)*d33); - d2 = d33; - - return true; -} - - -////////////////////////////////////////////////////////////////////////// -// -// Generic 4x4 matrix -// -////////////////////////////////////////////////////////////////////////// - -Matrix4x4::Matrix4x4() {} - -Matrix4x4::Matrix4x4(const double& d) -{ - matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = d; - matrix[1][0] = matrix[0][1] = matrix[1][2] = matrix[1][3] = 0; - matrix[2][0] = matrix[2][1] = matrix[0][2] = matrix[2][3] = 0; - matrix[3][0] = matrix[3][1] = matrix[3][2] = matrix[0][3] = 0; -} - -Matrix4x4::Matrix4x4(const double& a11, const double& a12, const double& a13, const double& a14, - const double& a21, const double& a22, const double& a23, const double& a24, - const double& a31, const double& a32, const double& a33, const double& a34, - const double& a41, const double& a42, const double& a43, const double& a44) -{ - matrix[0][0] = a11; matrix[0][1] = a12; matrix[0][2] = a13; matrix[0][3] = a14; - matrix[1][0] = a21; matrix[1][1] = a22; matrix[1][2] = a23; matrix[1][3] = a24; - matrix[2][0] = a31; matrix[2][1] = a32; matrix[2][2] = a33; matrix[2][3] = a34; - matrix[3][0] = a41; matrix[3][1] = a42; matrix[3][2] = a43; matrix[3][3] = a44; -} - -void Matrix4x4::setRotation(const double& rx, const double& ry, const double& rz, const double& rw) -{ + return (w1*(v1*M[0] + v2*M[1] + v3*M[3]) + w2*(v1*M[1] + v2*M[2] + v3*M[4]) + w3*(v1*M[3] + v2*M[4] + v3*M[5])); +} + +// Invert the matrix. If singular return FALSE + +bool SymMatrix3x3::invert() +{ + double det, pos, neg, t, out[6]; + + pos = neg = 0.0; + t = M[0]*M[2]*M[5]; ((t >= 0.0)?(pos):(neg)) += t; + t = M[1]*M[4]*M[3]; ((t >= 0.0)?(pos):(neg)) += t; + t = M[3]*M[1]*M[4]; ((t >= 0.0)?(pos):(neg)) += t; + t = -M[3]*M[2]*M[3]; ((t >= 0.0)?(pos):(neg)) += t; + t = -M[1]*M[1]*M[5]; ((t >= 0.0)?(pos):(neg)) += t; + t = -M[0]*M[4]*M[4]; ((t >= 0.0)?(pos):(neg)) += t; + det = pos+neg; + + t = det/(pos-neg); + if (FABS(t) >= 1.0e-15) + { + out[0] = (M[2] * M[5] - M[4] * M[4]) /det; + out[1] = -(M[1] * M[5] - M[4] * M[3]) /det; + out[2] = (M[0] * M[5] - M[3] * M[3]) /det; + out[3] = (M[1] * M[4] - M[2] * M[3]) /det; + out[4] = -(M[0] * M[4] - M[1] * M[3]) /det; + out[5] = (M[0] * M[2] - M[1] * M[1]) /det; + M[0] = out[0]; M[1] = out[1]; M[2] = out[2]; + M[3] = out[3]; M[4] = out[4]; M[5] = out[5]; + return 1; + } + + return 0; +} + + +// Compute eigenvalues and eigenvectors of the matrix (JACOBI method). +// The calling function is responsible of verifying that the matrix +// is diagonalizable. +// +// This routine was inspired from a software to estimate curvature +// tensors developed at INRIA. Visit the following link for details: +// http://www-sop.inria.fr/geometrica/team/Pierre.Alliez/demos/curvature/ +// +// This version has been slightly optimized. +// + +void SymMatrix3x3::diagonalize(double *eigen_val, double *eigen_vec) const +{ + static const double EPS = 0.00001; + static const double cos_pi_4 = 0.70710678; + static const int MAX_ITER = 100; + double a_P[6], v_P[9]; + double *a = a_P, *v = v_P; + double a_norm,a_normEPS,thr,thr_nn; + int nb_iter = 0; + int i,j,k,ij,jj,ik,l,m,lm,mq,lq,ll,mm,imv,im,iq,ilv,il; + int index_P[3]; + int *index = index_P; + double a_ij,a_lm,a_ll,a_mm,a_im,a_il,a_lm_2,v_ilv,v_imv,x; + double sinx,sinx_2,cosx,cosx_2,sincos,delta; + + a[0] = M[0]; a[1] = M[1]; a[2] = M[2]; + a[3] = M[3]; a[4] = M[4]; a[5] = M[5]; + a--; + + // Step 2 : Init diagonalization matrix as the unit matrix + + for (ij=0, i=0; i<3; i++) for (j=0; j<3; j++) v[ij++] = (i==j)?(1.0):(0.0); + v--; + + // Step 3 : compute the weight of the non diagonal terms + + a_norm = 0.0; + for (i=1, ij=1; i<=3; i++) for (j=1; j<=i; j++, ij++) if( i!=j ) {a_ij = a[ij]; a_norm += a_ij*a_ij;} + + if( a_norm != 0.0 ) + { + a_normEPS = a_norm*EPS; + thr = a_norm ; + + // Step 4 : rotations + while (thr > a_normEPS && nb_iter < MAX_ITER) + { + nb_iter++; + thr_nn = thr / 6; + + for (l=1; l<3; l++) + for (m=l+1; m<=3; m++) + { + // compute sinx and cosx + + lq = (l*l-l)/2; mq = (m*m-m)/2; + lm = l+mq; a_lm = a[lm]; + a_lm_2 = a_lm*a_lm; + + if( a_lm_2 < thr_nn ) continue; + + ll = l+lq; mm = m+mq; + a_ll = a[ll]; a_mm = a[mm]; + delta = a_ll - a_mm; + + if (delta==0.0) {sinx = -cos_pi_4; cosx = cos_pi_4;} + else {x = -atan( (a_lm+a_lm) / delta )/2.0; sinx=sin(x); cosx=cos(x);} + + sinx_2 = sinx*sinx; + cosx_2 = cosx*cosx; + sincos = sinx*cosx; + + // rotate L and M columns + + ilv = 3*(l-1); imv = 3*(m-1); + + for( i=1; i<=3;i++ ) + { + if( (i!=l) && (i!=m) ) + { + iq = (i*i-i)/2; + im = (i1.0e-12) {*L1 = *L2 = *L3 = a11; return;} // Evecs = (1,0,0), (0,1,0), (0,0,1) + + double l1, l2, l3; // Eigenvalues to be computed + + if (Q>=0) {double p=(b>0)?(pow(b/2, 1.0/3.0)):(0); l1=l2=((c2/3.0)+p); l3=((c2/3.0)-2.0*p);} + else + { + double t = atan2(sqrt(-Q), -b/2.0)/3.0, r = pow(((b*b)/4.0)-Q, 1.0/6.0); + double cos_t = cos(t), sin_t = sin(t); + const double sq3 = sqrt(3.0); + l1 = l2 = l3 = (c2/3.0); + l1 += (2*r*cos_t); + l2 -= r*(cos_t+sq3*sin_t); + l3 -= r*(cos_t-sq3*sin_t); + } + + if (l1<=l2 && l1<=l3) {*L1=l1; *L2=(l2=l2 && l1>=l3) {c0=u11; c1=u12; c2=u13; l=l1;} + else if (l2>=l1 && l2>=l3) {c0=u12; c1=u22; c2=u23; l=l2;} + else {c0=u13; c1=u23; c2=u33; l=l3;} + + l1 = sqrt(l); *x = c0/l1; *y = c1/l1; *z = c2/l1; + + return l; +} + + +// Computes the eigenvector corresp. to the maximum eigenvalue + +void SymMatrix3x3::getMaxEigenvector(double *x, double *y, double *z) const +{ + SymMatrix3x3(-M[0], -M[1], -M[2], -M[3], -M[4], -M[5]).getMinEigenvector(x, y, z); +} + +// Prints the matrix values + +void SymMatrix3x3::print(FILE *fp) const +{ + fprintf(fp,"%e %e %e\n",M[0],M[1],M[3]); + fprintf(fp,"%e %e %e\n",M[1],M[2],M[4]); + fprintf(fp,"%e %e %e\n",M[3],M[4],M[5]); +} + + +////////////////////////////////////////////////////////////////////////// +// +// Symmetric 4x4 matrix +// +////////////////////////////////////////////////////////////////////////// + +// Extend a 3x3 matrix + +SymMatrix4x4::SymMatrix4x4(const SymMatrix3x3& q) +{ + a2 = q.M[0]; ab = q.M[1]; ac = q.M[3]; ad = 0; + b2 = q.M[2]; bc = q.M[4]; bd = 0; + c2 = q.M[5]; cd = 0; d2 = 1; +} + + +// Build a quadric + +SymMatrix4x4::SymMatrix4x4(const coord& a, const coord& b, const coord& c, const coord& d) +{ + a2 = a*a; ab = a*b; ac = a*c; ad = a*d; + b2 = b*b; bc = b*c; bd = b*d; + c2 = c*c; cd = c*d; d2 = d*d; +} + +// True iff equal + +bool SymMatrix4x4::operator==(const SymMatrix4x4& q) +{ + return ( + a2 == q.a2 && ab == q.ab && ac == q.ac && ad == q.ad &&\ + b2 == q.b2 && bc == q.bc && bd == q.bd &&\ + c2 == q.c2 && cd == q.cd && d2 == q.d2); +} + +// True iff different + +bool SymMatrix4x4::operator!=(const SymMatrix4x4& q) +{ + return ( + a2 != q.a2 || ab != q.ab || ac != q.ac || ad != q.ad ||\ + b2 != q.b2 || bc != q.bc || bd != q.bd ||\ + c2 != q.c2 || cd != q.cd || d2 != q.d2); +} + +// Sum the matrix 'q' to the current matrix + +void SymMatrix4x4::operator+=(const SymMatrix4x4& q) +{ + a2 += q.a2; ab += q.ab; ac += q.ac; ad += q.ad; + b2 += q.b2; bc += q.bc; bd += q.bd; + c2 += q.c2; cd += q.cd; d2 += q.d2; +} + +// Returns the sum of the matrix with another matrix 'q' + +SymMatrix4x4 SymMatrix4x4::operator+(const SymMatrix4x4& q) const +{ + SymMatrix4x4 n; + + n.a2=a2+q.a2; n.ab=ab+q.ab; n.ac=ac+q.ac; n.ad=ad+q.ad; + n.b2=b2+q.b2; n.bc=bc+q.bc; n.bd=bd+q.bd; + n.c2=c2+q.c2; n.cd=cd+q.cd; n.d2=d2+q.d2; + + return n; +} + +// Returns the product of the matrix with a scalar + +SymMatrix4x4 SymMatrix4x4::operator*(const coord& d) const +{ + SymMatrix4x4 n; + + n.a2=a2*d; n.ab=ab*d; n.ac=ac*d; n.ad=ad*d; + n.b2=b2*d; n.bc=bc*d; n.bd=bd*d; + n.c2=c2*d; n.cd=cd*d; n.d2=d2*d; + + return n; +} + +void SymMatrix4x4::add(const coord& a, const coord& b, const coord& c, const coord& d) +{ + a2 += a*a; ab += a*b; ac += a*c; ad += a*d; + b2 += b*b; bc += b*c; bd += b*d; + c2 += c*c; cd += c*d; d2 += d*d; +} + + +// Computes (a,b,c,w)*M*(a,b,c,w) + +coord SymMatrix4x4::lrMultiply(const coord& x, const coord& y, const coord& z, const coord& w) const +{ + coord a,b,c,d; + a = x*a2 + y*ab + z*ac + w*ad; + b = x*ab + y*b2 + z*bc + w*bd; + c = x*ac + y*bc + z*c2 + w*cd; + d = x*ad + y*bd + z*cd + w*d2; + return (x*a + y*b + z*c + w*d); +} + +// Computes (a,b,c) s.t. (a,b,c,1)*M*(a,b,c,1) is minimized +// Returns FALSE if the minimizer is not unique + +bool SymMatrix4x4::getMinimizer(coord *a, coord *b, coord *c) const +{ + coord det, pos, neg, t; + + pos = neg = 0.0; + t = a2*b2*c2; ((t >= 0.0)?(pos):(neg)) += t; + t = ab*bc*ac; ((t >= 0.0)?(pos):(neg)) += t; + t = ac*ab*bc; ((t >= 0.0)?(pos):(neg)) += t; + t = -ac*b2*ac; ((t >= 0.0)?(pos):(neg)) += t; + t = -ab*ab*c2; ((t >= 0.0)?(pos):(neg)) += t; + t = -a2*bc*bc; ((t >= 0.0)?(pos):(neg)) += t; + det = pos+neg; + + if (pos == neg) return 0; + + t = det/(pos-neg); + if ( +#ifdef USE_HYBRID_KERNEL + (coord::isUsingRationals() && t!=0) || +#endif + (FABS(t) >= 1.0e-15)) + { + *a = -(ad*( (b2*c2 - bc*bc)) + bd*(-(ab*c2 - bc*ac)) + cd*( (ab*bc - b2*ac)))/det; + *b = -(ad*(-(ab*c2 - ac*bc)) + bd*( (a2*c2 - ac*ac)) + cd*(-(a2*bc - ab*ac)))/det; + *c = -(ad*( (ab*bc - ac*b2)) + bd*(-(a2*bc - ac*ab)) + cd*( (a2*b2 - ab*ab)))/det; + return 1; + } + + return 0; +} + + +// Invert a symmetric 4x4 matrix using L*D*L^T decomposition. +// The calling function is responsible of verifying that the matrix +// is positive definite. +// + +bool SymMatrix4x4::invert() +{ + if (a2 <= 0) return false; + + coord d00 = coord(1.0) / a2; + coord L10 = ab; + coord l10 = ab*d00; + coord L20 = ac; + coord l20 = ac*d00; + coord L30 = ad; + coord l30 = ad*d00; + coord d11 = b2-(L10*l10); + + if (d11 <= 0) return false; else d11 = coord(1.0)/d11; + + coord L21 = (bc-(L10*l20)); + coord l21 = L21*d11; + coord L31 = (bd-(L10*l30)); + coord l31 = L31*d11; + coord d22 = c2-(L20*l20)-(L21*l21); + + if (d22 <= 0) return false; else d22 = coord(1.0) / d22; + + coord L32 = (cd-(L20*l30)-(L21*l31)); + coord l32 = L32*d22; + coord d33 = d2-(L30*l30)-(L31*l31)-(L32*l32); + + if (d33 <= 0) return false; else d33 = coord(1.0) / d33; + + L20 = l10*l21-l20; + L31 = l21*l32-l31; + L30 = l32*l20-L31*l10-l30; + + a2 = d00+(-l10)*((-l10)*d11)+L20*(L20*d22)+L30*(L30*d33); + ab = ((-l10)*d11)+L20*((-l21)*d22)+L30*(L31*d33); + b2 = d11+(-l21)*((-l21)*d22)+L31*(L31*d33); + ac = (L20*d22)+L30*((-l32)*d33); + bc = ((-l21)*d22)+L31*((-l32)*d33); + c2 = d22+(-l32)*((-l32)*d33); + ad = (L30*d33); + bd = (L31*d33); + cd = ((-l32)*d33); + d2 = d33; + + return true; +} + + +////////////////////////////////////////////////////////////////////////// +// +// Generic 4x4 matrix +// +////////////////////////////////////////////////////////////////////////// + +Matrix4x4::Matrix4x4() {} + +Matrix4x4::Matrix4x4(const double& d) +{ + matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = d; + matrix[1][0] = matrix[0][1] = matrix[1][2] = matrix[1][3] = 0; + matrix[2][0] = matrix[2][1] = matrix[0][2] = matrix[2][3] = 0; + matrix[3][0] = matrix[3][1] = matrix[3][2] = matrix[0][3] = 0; +} + +Matrix4x4::Matrix4x4(const double& a11, const double& a12, const double& a13, const double& a14, + const double& a21, const double& a22, const double& a23, const double& a24, + const double& a31, const double& a32, const double& a33, const double& a34, + const double& a41, const double& a42, const double& a43, const double& a44) +{ + matrix[0][0] = a11; matrix[0][1] = a12; matrix[0][2] = a13; matrix[0][3] = a14; + matrix[1][0] = a21; matrix[1][1] = a22; matrix[1][2] = a23; matrix[1][3] = a24; + matrix[2][0] = a31; matrix[2][1] = a32; matrix[2][2] = a33; matrix[2][3] = a34; + matrix[3][0] = a41; matrix[3][1] = a42; matrix[3][2] = a43; matrix[3][3] = a44; +} + +void Matrix4x4::setRotation(const double& rx, const double& ry, const double& rz, const double& rw) +{ matrix[0][0] = rw*rw + rx*rx - ry*ry - rz*rz; matrix[0][1] = 2*rx*ry + 2*rw*rz; matrix[0][2] = 2*rx*rz - 2*rw*ry; @@ -757,38 +756,38 @@ void Matrix4x4::setRotation(const double& rx, const double& ry, const double& rz matrix[3][3] = rw*rw + rx*rx + ry*ry + rz*rz; } -void Matrix4x4::setTranslation(const double& x, const double& y, const double& z) -{ - matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = 1; - matrix[1][0] = matrix[0][1] = matrix[1][2] = 0; - matrix[2][0] = matrix[2][1] = matrix[0][2] = 0; - matrix[3][0] = matrix[3][1] = matrix[3][2] = 0; - matrix[0][3] = x; - matrix[1][3] = y; - matrix[2][3] = z; -} - -Matrix4x4 Matrix4x4::operator*(const Matrix4x4& q) const -{ - int i, j; - Matrix4x4 m; - - for (i=0; i<4; i++) for (j=0; j<4; j++) - m.matrix[i][j] = matrix[i][0]*q.matrix[0][j] + matrix[i][1]*q.matrix[1][j] + matrix[i][2]*q.matrix[2][j] + matrix[i][3]*q.matrix[3][j]; - - return m; -} - -void Matrix4x4::transform(double *x, double *y, double *z) -{ - double w, a = *x, b = *y, c = *z; - - *x = matrix[0][0]*a + matrix[0][1]*b + matrix[0][2]*c + matrix[0][3]; - *y = matrix[1][0]*a + matrix[1][1]*b + matrix[1][2]*c + matrix[1][3]; - *z = matrix[2][0]*a + matrix[2][1]*b + matrix[2][2]*c + matrix[2][3]; - w = matrix[3][0]*a + matrix[3][1]*b + matrix[3][2]*c + matrix[3][3]; - - (*x) /= w; (*y) /= w; (*z) /= w; -} - +void Matrix4x4::setTranslation(const double& x, const double& y, const double& z) +{ + matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = 1; + matrix[1][0] = matrix[0][1] = matrix[1][2] = 0; + matrix[2][0] = matrix[2][1] = matrix[0][2] = 0; + matrix[3][0] = matrix[3][1] = matrix[3][2] = 0; + matrix[0][3] = x; + matrix[1][3] = y; + matrix[2][3] = z; +} + +Matrix4x4 Matrix4x4::operator*(const Matrix4x4& q) const +{ + int i, j; + Matrix4x4 m; + + for (i=0; i<4; i++) for (j=0; j<4; j++) + m.matrix[i][j] = matrix[i][0]*q.matrix[0][j] + matrix[i][1]*q.matrix[1][j] + matrix[i][2]*q.matrix[2][j] + matrix[i][3]*q.matrix[3][j]; + + return m; +} + +void Matrix4x4::transform(double *x, double *y, double *z) +{ + double w, a = *x, b = *y, c = *z; + + *x = matrix[0][0]*a + matrix[0][1]*b + matrix[0][2]*c + matrix[0][3]; + *y = matrix[1][0]*a + matrix[1][1]*b + matrix[1][2]*c + matrix[1][3]; + *z = matrix[2][0]*a + matrix[2][1]*b + matrix[2][2]*c + matrix[2][3]; + w = matrix[3][0]*a + matrix[3][1]*b + matrix[3][2]*c + matrix[3][3]; + + (*x) /= w; (*y) /= w; (*z) /= w; +} + } //namespace T_MESH diff --git a/src/mesh_fix/src/Kernel/orientation.c b/src/mesh_fix/src/Kernel/orientation.c index 97a0591d2d..9d72504d00 100644 --- a/src/mesh_fix/src/Kernel/orientation.c +++ b/src/mesh_fix/src/Kernel/orientation.c @@ -171,8 +171,8 @@ double _estm(int elen, double *e) double _adaptive2dorientation(double *pa, double *pb, double *pc, double detsum) { double acx, acy, bcx, bcy,acxtail, acytail, bcxtail, bcytail, detleft, detright; - double detlefttail, detrighttail, det, errbound, B[5], C1[8], C2[12], D[16]; - double B3, u[5], u3, s1, t1, s0, t0, _bvr, _avr, _brn, _arn, c; + double detlefttail, detrighttail, det, errbound, B[4], C1[8], C2[12], D[16]; + double B3, u[4], u3, s1, t1, s0, t0, _bvr, _avr, _brn, _arn, c; double abig, ahi, alo, bhi, blo, err1, err2, err3, _i, _j, _0; int C1length, C2length, Dlength; diff --git a/src/mesh_fix/src/Kernel/point.cpp b/src/mesh_fix/src/Kernel/point.cpp index 7d82b7f858..b16d5d1e85 100644 --- a/src/mesh_fix/src/Kernel/point.cpp +++ b/src/mesh_fix/src/Kernel/point.cpp @@ -28,18 +28,18 @@ * * ****************************************************************************/ -#include "point.h" -#include -#include -#include - -namespace T_MESH -{ - -const Point INFINITE_POINT(DBL_MAX, DBL_MAX, DBL_MAX); - +#include "point.h" +#include +#include +#include + +namespace T_MESH +{ + +const Point INFINITE_POINT(DBL_MAX, DBL_MAX, DBL_MAX); + #ifdef USE_HYBRID_KERNEL - + PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) { if (!PM_Rational::isUsingFiltering() && !PM_Rational::isUsingRationals()) @@ -66,9 +66,9 @@ PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rati return O; } } - -PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c) -{ + +PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c) +{ if (!PM_Rational::isUsingFiltering() && !PM_Rational::isUsingRationals()) { return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); @@ -77,12 +77,12 @@ PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point b->x.isOfDoubleType() && b->y.isOfDoubleType() && b->z.isOfDoubleType() && c->x.isOfDoubleType() && c->y.isOfDoubleType() && c->z.isOfDoubleType()) { - double p1[3], p2[3], p3[3], p4[3]; - p1[0] = (t->x).getDVal(); p1[1] = (t->y).getDVal(); p1[2] = (t->z).getDVal(); - p2[0] = (a->x).getDVal(); p2[1] = (a->y).getDVal(); p2[2] = (a->z).getDVal(); - p3[0] = (b->x).getDVal(); p3[1] = (b->y).getDVal(); p3[2] = (b->z).getDVal(); - p4[0] = (c->x).getDVal(); p4[1] = (c->y).getDVal(); p4[2] = (c->z).getDVal(); - return orient3d(p1, p2, p3, p4); + double p1[3], p2[3], p3[3], p4[3]; + p1[0] = (t->x).getDVal(); p1[1] = (t->y).getDVal(); p1[2] = (t->z).getDVal(); + p2[0] = (a->x).getDVal(); p2[1] = (a->y).getDVal(); p2[2] = (a->z).getDVal(); + p3[0] = (b->x).getDVal(); p3[1] = (b->y).getDVal(); p3[2] = (b->z).getDVal(); + p4[0] = (c->x).getDVal(); p4[1] = (c->y).getDVal(); p4[2] = (c->z).getDVal(); + return orient3d(p1, p2, p3, p4); } else if (PM_Rational::isUsingRationals()) { return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); @@ -92,11 +92,11 @@ PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point PM_Rational O = TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); PM_Rational::use_rationals = false; return O; - } -} - -#else - + } +} + +#else + PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) { // return ((px - rx)*(qy - ry) - (py - ry)*(qx - rx)); @@ -106,395 +106,395 @@ PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rati pqr[2] = TMESH_TO_DOUBLE(qx); pqr[3] = TMESH_TO_DOUBLE(qy); pqr[4] = TMESH_TO_DOUBLE(rx); pqr[5] = TMESH_TO_DOUBLE(ry); return orient2d(pqr, pqr + 2, pqr + 4); -} - -PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c) -{ -// return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); - - double p1[3], p2[3], p3[3], p4[3]; - p1[0] = TMESH_TO_DOUBLE(t->x); p1[1] = TMESH_TO_DOUBLE(t->y); p1[2] = TMESH_TO_DOUBLE(t->z); - p2[0] = TMESH_TO_DOUBLE(a->x); p2[1] = TMESH_TO_DOUBLE(a->y); p2[2] = TMESH_TO_DOUBLE(a->z); - p3[0] = TMESH_TO_DOUBLE(b->x); p3[1] = TMESH_TO_DOUBLE(b->y); p3[2] = TMESH_TO_DOUBLE(b->z); - p4[0] = TMESH_TO_DOUBLE(c->x); p4[1] = TMESH_TO_DOUBLE(c->y); p4[2] = TMESH_TO_DOUBLE(c->z); - return orient3d(p1, p2, p3, p4); -} - -#endif - -coord Point::exactOrientation(const Point *a, const Point *b, const Point *c) const -{ +} + +PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c) +{ +// return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); + + double p1[3], p2[3], p3[3], p4[3]; + p1[0] = TMESH_TO_DOUBLE(t->x); p1[1] = TMESH_TO_DOUBLE(t->y); p1[2] = TMESH_TO_DOUBLE(t->z); + p2[0] = TMESH_TO_DOUBLE(a->x); p2[1] = TMESH_TO_DOUBLE(a->y); p2[2] = TMESH_TO_DOUBLE(a->z); + p3[0] = TMESH_TO_DOUBLE(b->x); p3[1] = TMESH_TO_DOUBLE(b->y); p3[2] = TMESH_TO_DOUBLE(b->z); + p4[0] = TMESH_TO_DOUBLE(c->x); p4[1] = TMESH_TO_DOUBLE(c->y); p4[2] = TMESH_TO_DOUBLE(c->z); + return orient3d(p1, p2, p3, p4); +} + +#endif + +coord Point::exactOrientation(const Point *a, const Point *b, const Point *c) const +{ return orient3D(this, a, b, c); -} - - -////////////// Alignment check ///////////// - -bool Point::exactMisalignment(const Point *A, const Point *B) const +} + + +////////////// Alignment check ///////////// + +bool Point::exactMisalignment(const Point *A, const Point *B) const { if (orient2D(x, y, A->x, A->y, B->x, B->y) != 0) return true; if (orient2D(y, z, A->y, A->z, B->y, B->z) != 0) return true; if (orient2D(z, x, A->z, A->x, B->z, B->x) != 0) return true; - - return false; -} - -bool Point::exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const -{ - coord o1, o2; - int s1, s2; - - o1 = orient2D(x, y, A->x, A->y, B->x, B->y); - o2 = orient2D(Q->x, Q->y, A->x, A->y, B->x, B->y); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); - if (s1 != s2) return false; - - o1 = orient2D(y, z, A->y, A->z, B->y, B->z); - o2 = orient2D(Q->y, Q->z, A->y, A->z, B->y, B->z); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); - if (s1 != s2) return false; - - o1 = orient2D(z, x, A->z, A->x, B->z, B->x); - o2 = orient2D(Q->z, Q->x, A->z, A->x, B->z, B->x); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + return false; +} + +bool Point::exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const +{ + coord o1, o2; + int s1, s2; + + o1 = orient2D(x, y, A->x, A->y, B->x, B->y); + o2 = orient2D(Q->x, Q->y, A->x, A->y, B->x, B->y); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - return true; -} - -// Returns true if the coplanar point 'p' is in the inner area of 't'. -// Undetermined if p and t are not coplanar. -bool Point::pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3) -{ - //if (!p->exactSameSideOnPlane(v1, v2, v3)) return false; - //if (!p->exactSameSideOnPlane(v2, v3, v1)) return false; - //if (!p->exactSameSideOnPlane(v3, v1, v2)) return false; - //return true; - - // Less readable, but slightly more efficient (12 predicates instead of 18) - - coord o1, o2, oo2, oo4, oo6; - int s1, s2; - - o1 = orient2D(p->x, p->y, v2->x, v2->y, v3->x, v3->y); - o2 = oo2 = orient2D(v1->x, v1->y, v2->x, v2->y, v3->x, v3->y); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + o1 = orient2D(y, z, A->y, A->z, B->y, B->z); + o2 = orient2D(Q->y, Q->z, A->y, A->z, B->y, B->z); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->y, p->z, v2->y, v2->z, v3->y, v3->z); - o2 = oo4 = orient2D(v1->y, v1->z, v2->y, v2->z, v3->y, v3->z); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(z, x, A->z, A->x, B->z, B->x); + o2 = orient2D(Q->z, Q->x, A->z, A->x, B->z, B->x); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->z, p->x, v2->z, v2->x, v3->z, v3->x); - o2 = oo6 = orient2D(v1->z, v1->x, v2->z, v2->x, v3->z, v3->x); - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + return true; +} + +// Returns true if the coplanar point 'p' is in the inner area of 't'. +// Undetermined if p and t are not coplanar. +bool Point::pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3) +{ + //if (!p->exactSameSideOnPlane(v1, v2, v3)) return false; + //if (!p->exactSameSideOnPlane(v2, v3, v1)) return false; + //if (!p->exactSameSideOnPlane(v3, v1, v2)) return false; + //return true; + + // Less readable, but slightly more efficient (12 predicates instead of 18) + + coord o1, o2, oo2, oo4, oo6; + int s1, s2; + + o1 = orient2D(p->x, p->y, v2->x, v2->y, v3->x, v3->y); + o2 = oo2 = orient2D(v1->x, v1->y, v2->x, v2->y, v3->x, v3->y); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->x, p->y, v3->x, v3->y, v1->x, v1->y); - o2 = oo2, - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(p->y, p->z, v2->y, v2->z, v3->y, v3->z); + o2 = oo4 = orient2D(v1->y, v1->z, v2->y, v2->z, v3->y, v3->z); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->y, p->z, v3->y, v3->z, v1->y, v1->z); - o2 = oo4; - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(p->z, p->x, v2->z, v2->x, v3->z, v3->x); + o2 = oo6 = orient2D(v1->z, v1->x, v2->z, v2->x, v3->z, v3->x); + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->z, p->x, v3->z, v3->x, v1->z, v1->x); - o2 = oo6; - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(p->x, p->y, v3->x, v3->y, v1->x, v1->y); + o2 = oo2, + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->x, p->y, v1->x, v1->y, v2->x, v2->y); - o2 = oo2; - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(p->y, p->z, v3->y, v3->z, v1->y, v1->z); + o2 = oo4; + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->y, p->z, v1->y, v1->z, v2->y, v2->z); - o2 = oo4; - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + + o1 = orient2D(p->z, p->x, v3->z, v3->x, v1->z, v1->x); + o2 = oo6; + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); if (s1 != s2) return false; - - o1 = orient2D(p->z, p->x, v1->z, v1->x, v2->z, v2->x); - o2 = oo6; - s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); - if (s1 != s2) return false; - - return true; -} - -//////// Lexicographic Point comparison ////////// - -// This can be used with std::sort() -bool Point::operator<(const Point& s) const -{ - if (xs.x) return false; - if (ys.y) return false; - if (zx - ((Point *)b)->x)) < 0) return -1; - if (c > 0) return 1; - if ((c=(((Point *)a)->y - ((Point *)b)->y)) < 0) return -1; - if (c > 0) return 1; - if ((c=(((Point *)a)->z - ((Point *)b)->z)) < 0) return -1; - if (c > 0) return 1; - - return 0; -} - -//////////////// Normalization ///////////////////////// - -void Point::normalize() -{ - coord l = length(); - - if (l == 0) TMesh::error("normalize : Trying to normalize a null vector !\n"); - - x/=l; - y/=l; - z/=l; -} - - -//////////////////// Point rotation //////////////////// -/////////// 'ang' radians CCW around 'axis' //////////// - -void Point::rotate(const Point& a, const double& ang) -{ - double l, q[4], m[3][3]; - if ((l = a.length())==0.0) return; - l = sin(ang/2.0)/l; - - q[0] = TMESH_TO_DOUBLE(a.x)*l; - q[1] = TMESH_TO_DOUBLE(a.y)*l; - q[2] = TMESH_TO_DOUBLE(a.z)*l; - q[3] = cos(ang/2.0); - - m[0][0] = 1.0 - (q[1]*q[1] + q[2]*q[2])*2.0; - m[0][1] = (q[0] * q[1] + q[2] * q[3])*2.0; - m[0][2] = (q[2] * q[0] - q[1] * q[3])*2.0; - - m[1][0] = (q[0] * q[1] - q[2] * q[3])*2.0; - m[1][1] = 1.0 - (q[2] * q[2] + q[0] * q[0])*2.0; - m[1][2] = (q[1] * q[2] + q[0] * q[3])*2.0; - - m[2][0] = (q[2] * q[0] + q[1] * q[3])*2.0; - m[2][1] = (q[1] * q[2] - q[0] * q[3])*2.0; - m[2][2] = 1.0 - (q[1] * q[1] + q[0] * q[0])*2.0; - - q[0] = TMESH_TO_DOUBLE(x); q[1] = TMESH_TO_DOUBLE(y); q[2] = TMESH_TO_DOUBLE(z); - x = m[0][0]*q[0] + m[1][0]*q[1] + m[2][0]*q[2]; - y = m[0][1]*q[0] + m[1][1]*q[1] + m[2][1]*q[2]; - z = m[0][2]*q[0] + m[1][2]*q[1] + m[2][2]*q[2]; -} - - -///// Project the point on the plane whose normal is 'nor' ///// - -void Point::project(const Point *nor) -{ - Point pr = (*this)-((*nor)*((*this)*(*nor))); - x = pr.x; y = pr.y; z = pr.z; -} - - -/////////// Distance from the line passing through A and B //////// - -double Point::distanceFromLine(const Point *A, const Point *B) const -{ - Point BA = (*B)-(*A); - double lba = BA.length(); - - if (lba == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n"); - - return ((((*this)-(*A))&BA).length())/(lba); -} - - -/////////////////// Distance from a line /////////////////////// -//// 'cc' is initialized as the point of the line whose //// -//// distance from 'this' is minimum. //// - -double Point::distanceFromLine(const Point *A, const Point *B, Point *cc) const -{ - Point AB = (*A)-(*B); - Point AP = (*A)-(*this); - Point BP = (*B)-(*this); - - if (AP.isNull()) - { - cc->x = A->x; cc->y = A->y; cc->z = A->z; - return 0.0; - } - else if (BP.isNull()) - { - cc->x = B->x; cc->y = B->y; cc->z = B->z; - return 0.0; - } - - coord t = (AB*AB); - if (t == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n"); - else t = (AP*AB)/(-t); - cc->x = t*AB.x + A->x; - cc->y = t*AB.y + A->y; - cc->z = t*AB.z + A->z; - return distanceFromLine(A,B); -} - - -////////////// Projection on the line passing through A and B /////////// - -Point Point::projection(const Point *A, const Point *B) const -{ - Point BA = (*B)-(*A); - coord l = BA*BA; - if (l == 0.0) TMesh::error("projection : Degenerate line passed !\n"); - - return ((*A)+(BA*((BA*((*this)-(*A)))/(l)))); -} - - -////////////// Distance from a segment ///////////////// - -double Point::distanceFromEdge(const Point *A, const Point *B) const -{ - Point AP = (*A)-(*this); double apl = AP.length(); - Point BP = (*B) - (*this); double bpl = BP.length(); - - if (apl == 0 || bpl == 0.0) return 0.0; - - Point AB = (*A) - (*B); double abl = AP.length(); - Point BA = (*B)-(*A); - - if (abl*apl == 0.0 || abl*bpl == 0.0) return apl; - - if (AB.getAngle(AP) > PI2) return apl; - else if (BA.getAngle(BP) > PI2) return bpl; - - return distanceFromLine(A,B); -} - -/////////////////// Distance from a segment /////////////////////// -//// 'cc' is initialized as the point of the segment whose //// -//// distance from 'this' is minimum. //// - -double Point::distanceFromEdge(const Point *A, const Point *B, Point *cc) const -{ - Point AP = (*A)-(*this); double apl = AP.length(); - Point BP = (*B) - (*this); double bpl = BP.length(); - - if (apl == 0) {cc->setValue(A); return 0.0;} - if (bpl == 0) {cc->setValue(B); return 0.0;} - - Point AB = (*A)-(*B); coord abl = AP.length(); - Point BA = (*B)-(*A); - - if (abl*apl == 0.0 || abl*bpl == 0.0) {cc->setValue(A); return apl;} - - if (AB.getAngle(AP) > PI2) {cc->setValue(A); return apl;} - else if (BA.getAngle(BP) > PI2) {cc->setValue(B); return bpl;} - - coord t = (AB*AB); - if (t == 0.0) {cc->setValue(A); return apl;} - else t = (AP*AB)/(-t); - cc->x = t*AB.x + A->x; - cc->y = t*AB.y + A->y; - cc->z = t*AB.z + A->z; - return distanceFromLine(A,B); -} - -///////////////// Angle between two vectors /////////////// - -double Point::getAngle(const Point& p) const -{ - return atan2(((*this)&p).length(), TMESH_TO_DOUBLE(((*this)*p))); -} - - -/////////// Distance of two straight lines /////////////// - -double Point::distanceLineLine(const Point *A, const Point *A1, const Point *B1) const -{ - Point uu1 = ((*this)-(*A))&((*A1)-(*B1)); - coord nom = ((*A)-(*A1))*(uu1); - return FABS(TMESH_TO_DOUBLE(nom)) / (uu1.length()); -} - - -/////////// Solution of a linear system 3 x 3 ////////// -///// System Ax = d, where A = (a,b,c) rows, d = this ///// - -Point Point::linearSystem(const Point& a, const Point& b, const Point& c) -{ - Point ret; - coord det_A = TMESH_DETERMINANT3X3(a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z); - if (det_A == 0.0) return INFINITE_POINT; - ret.x = TMESH_DETERMINANT3X3(x, a.y, a.z, y, b.y, b.z, z, c.y, c.z); - ret.y = TMESH_DETERMINANT3X3(a.x, x, a.z, b.x, y, b.z, c.x, z, c.z); - ret.z = TMESH_DETERMINANT3X3(a.x, a.y, x, b.x, b.y, y, c.x, c.y, z); - - return (ret/det_A); -} - - - -//// Computes the closest points of the two lines 'this'-v1 and p1-p2 //// -//// Returns FALSE if the lines are parallel. //// - -int Point::closestPoints(const Point *v1, const Point *p1, const Point *p2, Point *ptOnThis, Point *ptOnLine2) const -{ - Point pos1 = *this; Point dir1 = (*v1)-pos1; - Point pos2 = *p1; Point dir2 = (*p2)-pos2; - coord d1l = dir1.length(), d2l = dir2.length(); - - if (d1l == 0.0 && d2l == 0.0) - {ptOnThis->setValue(this); ptOnLine2->setValue(p1); return 1;} - if (d1l*d2l == 0.0) - { - if (d1l <= d2l) - {ptOnThis->setValue(this); distanceFromLine(p1, p2, ptOnLine2); return 1;} - if (d2l <= d1l) - {ptOnLine2->setValue(p1); p1->distanceFromLine(this, v1, ptOnThis); return 1;} - } - - coord ang = dir1.getAngle(dir2); - if (ang == 0.0 || ang == M_PI) return 0; - - coord s, t, A, B, C, D, E, F, denom; - - denom = ((dir1*dir2)/(d1l*d2l)); - denom = denom*denom - 1; - - dir1.normalize(); - dir2.normalize(); - - A = E = dir1*dir2; - B = dir1*dir1; - C = (dir1*pos1) - (dir1*pos2); - D = dir2*dir2; - F = (dir2*pos1) - (dir2*pos2); - - s = ( C * D - A * F ) / denom; - t = ( C * E - B * F ) / denom; - *ptOnThis = pos1 + (dir1*s); - *ptOnLine2 = pos2 + (dir2*t); - -// Uncomment the following to compute the distance between segments -// if (s < 0 || s > ((*v1)-(*this)).length() || t < 0 || t > ((*p2)-(*p1)).length()) -// return 0; // The points does not belong to the edges - - return 1; -} - - - + + o1 = orient2D(p->x, p->y, v1->x, v1->y, v2->x, v2->y); + o2 = oo2; + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + if (s1 != s2) return false; + + o1 = orient2D(p->y, p->z, v1->y, v1->z, v2->y, v2->z); + o2 = oo4; + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + if (s1 != s2) return false; + + o1 = orient2D(p->z, p->x, v1->z, v1->x, v2->z, v2->x); + o2 = oo6; + s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0)); + if (s1 != s2) return false; + + return true; +} + +//////// Lexicographic Point comparison ////////// + +// This can be used with std::sort() +bool Point::operator<(const Point& s) const +{ + if (xs.x) return false; + if (ys.y) return false; + if (zx - ((Point *)b)->x)) < 0) return -1; + if (c > 0) return 1; + if ((c=(((Point *)a)->y - ((Point *)b)->y)) < 0) return -1; + if (c > 0) return 1; + if ((c=(((Point *)a)->z - ((Point *)b)->z)) < 0) return -1; + if (c > 0) return 1; + + return 0; +} + +//////////////// Normalization ///////////////////////// + +void Point::normalize() +{ + coord l = length(); + + if (l == 0) TMesh::error("normalize : Trying to normalize a null vector !\n"); + + x/=l; + y/=l; + z/=l; +} + + +//////////////////// Point rotation //////////////////// +/////////// 'ang' radians CCW around 'axis' //////////// + +void Point::rotate(const Point& a, const double& ang) +{ + double l, q[4], m[3][3]; + if ((l = a.length())==0.0) return; + l = sin(ang/2.0)/l; + + q[0] = TMESH_TO_DOUBLE(a.x)*l; + q[1] = TMESH_TO_DOUBLE(a.y)*l; + q[2] = TMESH_TO_DOUBLE(a.z)*l; + q[3] = cos(ang/2.0); + + m[0][0] = 1.0 - (q[1]*q[1] + q[2]*q[2])*2.0; + m[0][1] = (q[0] * q[1] + q[2] * q[3])*2.0; + m[0][2] = (q[2] * q[0] - q[1] * q[3])*2.0; + + m[1][0] = (q[0] * q[1] - q[2] * q[3])*2.0; + m[1][1] = 1.0 - (q[2] * q[2] + q[0] * q[0])*2.0; + m[1][2] = (q[1] * q[2] + q[0] * q[3])*2.0; + + m[2][0] = (q[2] * q[0] + q[1] * q[3])*2.0; + m[2][1] = (q[1] * q[2] - q[0] * q[3])*2.0; + m[2][2] = 1.0 - (q[1] * q[1] + q[0] * q[0])*2.0; + + q[0] = TMESH_TO_DOUBLE(x); q[1] = TMESH_TO_DOUBLE(y); q[2] = TMESH_TO_DOUBLE(z); + x = m[0][0]*q[0] + m[1][0]*q[1] + m[2][0]*q[2]; + y = m[0][1]*q[0] + m[1][1]*q[1] + m[2][1]*q[2]; + z = m[0][2]*q[0] + m[1][2]*q[1] + m[2][2]*q[2]; +} + + +///// Project the point on the plane whose normal is 'nor' ///// + +void Point::project(const Point *nor) +{ + Point pr = (*this)-((*nor)*((*this)*(*nor))); + x = pr.x; y = pr.y; z = pr.z; +} + + +/////////// Distance from the line passing through A and B //////// + +double Point::distanceFromLine(const Point *A, const Point *B) const +{ + Point BA = (*B)-(*A); + double lba = BA.length(); + + if (lba == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n"); + + return ((((*this)-(*A))&BA).length())/(lba); +} + + +/////////////////// Distance from a line /////////////////////// +//// 'cc' is initialized as the point of the line whose //// +//// distance from 'this' is minimum. //// + +double Point::distanceFromLine(const Point *A, const Point *B, Point *cc) const +{ + Point AB = (*A)-(*B); + Point AP = (*A)-(*this); + Point BP = (*B)-(*this); + + if (AP.isNull()) + { + cc->x = A->x; cc->y = A->y; cc->z = A->z; + return 0.0; + } + else if (BP.isNull()) + { + cc->x = B->x; cc->y = B->y; cc->z = B->z; + return 0.0; + } + + coord t = (AB*AB); + if (t == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n"); + else t = (AP*AB)/(-t); + cc->x = t*AB.x + A->x; + cc->y = t*AB.y + A->y; + cc->z = t*AB.z + A->z; + return distanceFromLine(A,B); +} + + +////////////// Projection on the line passing through A and B /////////// + +Point Point::projection(const Point *A, const Point *B) const +{ + Point BA = (*B)-(*A); + coord l = BA*BA; + if (l == 0.0) TMesh::error("projection : Degenerate line passed !\n"); + + return ((*A)+(BA*((BA*((*this)-(*A)))/(l)))); +} + + +////////////// Distance from a segment ///////////////// + +double Point::distanceFromEdge(const Point *A, const Point *B) const +{ + Point AP = (*A)-(*this); double apl = AP.length(); + Point BP = (*B) - (*this); double bpl = BP.length(); + + if (apl == 0 || bpl == 0.0) return 0.0; + + Point AB = (*A) - (*B); double abl = AP.length(); + Point BA = (*B)-(*A); + + if (abl*apl == 0.0 || abl*bpl == 0.0) return apl; + + if (AB.getAngle(AP) > PI2) return apl; + else if (BA.getAngle(BP) > PI2) return bpl; + + return distanceFromLine(A,B); +} + +/////////////////// Distance from a segment /////////////////////// +//// 'cc' is initialized as the point of the segment whose //// +//// distance from 'this' is minimum. //// + +double Point::distanceFromEdge(const Point *A, const Point *B, Point *cc) const +{ + Point AP = (*A)-(*this); double apl = AP.length(); + Point BP = (*B) - (*this); double bpl = BP.length(); + + if (apl == 0) {cc->setValue(A); return 0.0;} + if (bpl == 0) {cc->setValue(B); return 0.0;} + + Point AB = (*A)-(*B); coord abl = AP.length(); + Point BA = (*B)-(*A); + + if (abl*apl == 0.0 || abl*bpl == 0.0) {cc->setValue(A); return apl;} + + if (AB.getAngle(AP) > PI2) {cc->setValue(A); return apl;} + else if (BA.getAngle(BP) > PI2) {cc->setValue(B); return bpl;} + + coord t = (AB*AB); + if (t == 0.0) {cc->setValue(A); return apl;} + else t = (AP*AB)/(-t); + cc->x = t*AB.x + A->x; + cc->y = t*AB.y + A->y; + cc->z = t*AB.z + A->z; + return distanceFromLine(A,B); +} + +///////////////// Angle between two vectors /////////////// + +double Point::getAngle(const Point& p) const +{ + return atan2(((*this)&p).length(), TMESH_TO_DOUBLE(((*this)*p))); +} + + +/////////// Distance of two straight lines /////////////// + +double Point::distanceLineLine(const Point *A, const Point *A1, const Point *B1) const +{ + Point uu1 = ((*this)-(*A))&((*A1)-(*B1)); + coord nom = ((*A)-(*A1))*(uu1); + return FABS(TMESH_TO_DOUBLE(nom)) / (uu1.length()); +} + + +/////////// Solution of a linear system 3 x 3 ////////// +///// System Ax = d, where A = (a,b,c) rows, d = this ///// + +Point Point::linearSystem(const Point& a, const Point& b, const Point& c) +{ + Point ret; + coord det_A = TMESH_DETERMINANT3X3(a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z); + if (det_A == 0.0) return INFINITE_POINT; + ret.x = TMESH_DETERMINANT3X3(x, a.y, a.z, y, b.y, b.z, z, c.y, c.z); + ret.y = TMESH_DETERMINANT3X3(a.x, x, a.z, b.x, y, b.z, c.x, z, c.z); + ret.z = TMESH_DETERMINANT3X3(a.x, a.y, x, b.x, b.y, y, c.x, c.y, z); + + return (ret/det_A); +} + + + +//// Computes the closest points of the two lines 'this'-v1 and p1-p2 //// +//// Returns FALSE if the lines are parallel. //// + +int Point::closestPoints(const Point *v1, const Point *p1, const Point *p2, Point *ptOnThis, Point *ptOnLine2) const +{ + Point pos1 = *this; Point dir1 = (*v1)-pos1; + Point pos2 = *p1; Point dir2 = (*p2)-pos2; + coord d1l = dir1.length(), d2l = dir2.length(); + + if (d1l == 0.0 && d2l == 0.0) + {ptOnThis->setValue(this); ptOnLine2->setValue(p1); return 1;} + if (d1l*d2l == 0.0) + { + if (d1l <= d2l) + {ptOnThis->setValue(this); distanceFromLine(p1, p2, ptOnLine2); return 1;} + if (d2l <= d1l) + {ptOnLine2->setValue(p1); p1->distanceFromLine(this, v1, ptOnThis); return 1;} + } + + coord ang = dir1.getAngle(dir2); + if (ang == 0.0 || ang == M_PI) return 0; + + coord s, t, A, B, C, D, E, F, denom; + + denom = ((dir1*dir2)/(d1l*d2l)); + denom = denom*denom - 1; + + dir1.normalize(); + dir2.normalize(); + + A = E = dir1*dir2; + B = dir1*dir1; + C = (dir1*pos1) - (dir1*pos2); + D = dir2*dir2; + F = (dir2*pos1) - (dir2*pos2); + + s = ( C * D - A * F ) / denom; + t = ( C * E - B * F ) / denom; + *ptOnThis = pos1 + (dir1*s); + *ptOnLine2 = pos2 + (dir2*t); + +// Uncomment the following to compute the distance between segments +// if (s < 0 || s > ((*v1)-(*this)).length() || t < 0 || t > ((*p2)-(*p1)).length()) +// return 0; // The points does not belong to the edges + + return 1; +} + + + // Returns the point of intersection between the two lines defined by (p,q) and (r,s) respectively // Return INFINITE_POINT is lines are parallel or if p==q or r==s Point Point::lineLineIntersection(const Point& p, const Point& q, const Point& r, const Point& s) @@ -509,7 +509,7 @@ Point Point::lineLineIntersection(const Point& p, const Point& q, const Point& r coord k = (((dc&db)*dab) / (dab*dab)); return p + (da*k); } - + // Returns the point of intersection between the line for (p,q) and the plane for (r,s,t) // Returns INFINITE_POINT in case of parallelism Point Point::linePlaneIntersection(const Point& p, const Point& q, const Point& r, const Point& s, const Point& t) @@ -520,134 +520,134 @@ Point Point::linePlaneIntersection(const Point& p, const Point& q, const Point& coord gamma = num / den; return p + ((q - p)*gamma); } - + coord Point::squaredTriangleArea3D(const Point& p, const Point& q, const Point& r) { Point pr = (p - r), qr = (q - r); Point n = pr&qr; return (n*n) / 4; } - - -////////////////////////////////////////////////////////////////// -// -// Basic predicates of type 'pointIn' -// -////////////////////////////////////////////////////////////////// - -// Returns true if 'p' is a point of the segment v1-v2 (endpoints excluded) -bool Point::pointInInnerSegment(const Point *p, const Point *v1, const Point *v2) -{ - if (!p->exactMisalignment(v1, v2)) // Segment and point aligned - { - if (v1->x < v2->x && v1->x < p->x && p->x < v2->x) return true; - if (v1->y < v2->y && v1->y < p->y && p->y < v2->y) return true; - if (v1->z < v2->z && v1->z < p->z && p->z < v2->z) return true; - if (v1->x > v2->x && v1->x > p->x && p->x > v2->x) return true; - if (v1->y > v2->y && v1->y > p->y && p->y > v2->y) return true; - if (v1->z > v2->z && v1->z > p->z && p->z > v2->z) return true; - } - return false; -} - -// Returns true if 'p' is a point of the segment v1-v2 (endpoints included) -bool Point::pointInSegment(const Point *p, const Point *v1, const Point *v2) -{ - return ((*p) == (*(v1)) || (*p) == (*(v2)) || Point::pointInInnerSegment(p, v1, v2)); -} - - -// Returns true if the coplanar point 'p' is either in the inner area of -// 't' or on its border. Undetermined if p and t are not coplanar. -bool Point::pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3) -{ - if (Point::pointInSegment(p, v1, v2)) return true; - else if (Point::pointInSegment(p, v2, v3)) return true; - else if (Point::pointInSegment(p, v3, v1)) return true; - else return Point::pointInInnerTriangle(p, v1, v2, v3); -} - - -////////////////////////////////////////////////////////////////// -// -// Basic predicates of type 'segmentIntersects' -// -////////////////////////////////////////////////////////////////// - -// true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). -// Collinear overlapping segments are not considered to be properly intersecting. -bool Point::segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2) -{ - return (p1->exactOrientation(p2, sp1, sp2) == 0 && !p1->exactSameSideOnPlane(p2, sp1, sp2) && !sp1->exactSameSideOnPlane(sp2, p1, p2)); -} - -// Returns true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). -// Collinear overlapping segments are not considered to be properly intersecting. -bool Point::innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2) -{ - if (p1 == sp1 || p1 == sp2 || p2 == sp1 || p2 == sp2) return false; - return (p1.exactOrientation(&p2, &sp1, &sp2) == 0 && !p1.exactSameSideOnPlane(&p2, &sp1, &sp2) && !sp1.exactSameSideOnPlane(&sp2, &p1, &p2)); -} - -bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3) -{ - coord o1, o2, o3; - - coord mx = MIN(s1->x, s2->x); - if (v1->x < mx && v2->x < mx && v3->x < mx) return false; - mx = MAX(s1->x, s2->x); - if (v1->x > mx && v2->x > mx && v3->x > mx) return false; - mx = MIN(s1->y, s2->y); - if (v1->y < mx && v2->y < mx && v3->y < mx) return false; - mx = MAX(s1->y, s2->y); - if (v1->y > mx && v2->y > mx && v3->y > mx) return false; - mx = MIN(s1->z, s2->z); - if (v1->z < mx && v2->z < mx && v3->z < mx) return false; - mx = MAX(s1->z, s2->z); - if (v1->z > mx && v2->z > mx && v3->z > mx) return false; - - o1 = s1->exactOrientation(v1, v2, v3); - o2 = s2->exactOrientation(v1, v2, v3); - if (o1 == 0 && o2 == 0) - { - if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; - if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; - if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; - if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true; - return false; - } - - if ((o1>0 && o2>0) || (o1<0 && o2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 - o1 = s1->exactOrientation(s2, v1, v2); - o2 = s1->exactOrientation(s2, v2, v3); - if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; - o3 = s1->exactOrientation(s2, v3, v1); - if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; - if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; - return true; -} - -bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& oo1, const coord& oo2) -{ - // In this case the fast reject by bounding box appears to be a disadvantage ... - if (oo1 == 0 && oo2 == 0) - { - if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; - if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; - if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; - if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true; - return false; - } - - if ((oo1>0 && oo2>0) || (oo1<0 && oo2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 - coord o1, o2, o3; - o1 = s1->exactOrientation(s2, v1, v2); - o2 = s1->exactOrientation(s2, v2, v3); - if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; - o3 = s1->exactOrientation(s2, v3, v1); - if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; - if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; - return true; -} - + + +////////////////////////////////////////////////////////////////// +// +// Basic predicates of type 'pointIn' +// +////////////////////////////////////////////////////////////////// + +// Returns true if 'p' is a point of the segment v1-v2 (endpoints excluded) +bool Point::pointInInnerSegment(const Point *p, const Point *v1, const Point *v2) +{ + if (!p->exactMisalignment(v1, v2)) // Segment and point aligned + { + if (v1->x < v2->x && v1->x < p->x && p->x < v2->x) return true; + if (v1->y < v2->y && v1->y < p->y && p->y < v2->y) return true; + if (v1->z < v2->z && v1->z < p->z && p->z < v2->z) return true; + if (v1->x > v2->x && v1->x > p->x && p->x > v2->x) return true; + if (v1->y > v2->y && v1->y > p->y && p->y > v2->y) return true; + if (v1->z > v2->z && v1->z > p->z && p->z > v2->z) return true; + } + return false; +} + +// Returns true if 'p' is a point of the segment v1-v2 (endpoints included) +bool Point::pointInSegment(const Point *p, const Point *v1, const Point *v2) +{ + return ((*p) == (*(v1)) || (*p) == (*(v2)) || Point::pointInInnerSegment(p, v1, v2)); +} + + +// Returns true if the coplanar point 'p' is either in the inner area of +// 't' or on its border. Undetermined if p and t are not coplanar. +bool Point::pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3) +{ + if (Point::pointInSegment(p, v1, v2)) return true; + else if (Point::pointInSegment(p, v2, v3)) return true; + else if (Point::pointInSegment(p, v3, v1)) return true; + else return Point::pointInInnerTriangle(p, v1, v2, v3); +} + + +////////////////////////////////////////////////////////////////// +// +// Basic predicates of type 'segmentIntersects' +// +////////////////////////////////////////////////////////////////// + +// true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). +// Collinear overlapping segments are not considered to be properly intersecting. +bool Point::segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2) +{ + return (p1->exactOrientation(p2, sp1, sp2) == 0 && !p1->exactSameSideOnPlane(p2, sp1, sp2) && !sp1->exactSameSideOnPlane(sp2, p1, p2)); +} + +// Returns true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). +// Collinear overlapping segments are not considered to be properly intersecting. +bool Point::innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2) +{ + if (p1 == sp1 || p1 == sp2 || p2 == sp1 || p2 == sp2) return false; + return (p1.exactOrientation(&p2, &sp1, &sp2) == 0 && !p1.exactSameSideOnPlane(&p2, &sp1, &sp2) && !sp1.exactSameSideOnPlane(&sp2, &p1, &p2)); +} + +bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3) +{ + coord o1, o2, o3; + + coord mx = MIN(s1->x, s2->x); + if (v1->x < mx && v2->x < mx && v3->x < mx) return false; + mx = MAX(s1->x, s2->x); + if (v1->x > mx && v2->x > mx && v3->x > mx) return false; + mx = MIN(s1->y, s2->y); + if (v1->y < mx && v2->y < mx && v3->y < mx) return false; + mx = MAX(s1->y, s2->y); + if (v1->y > mx && v2->y > mx && v3->y > mx) return false; + mx = MIN(s1->z, s2->z); + if (v1->z < mx && v2->z < mx && v3->z < mx) return false; + mx = MAX(s1->z, s2->z); + if (v1->z > mx && v2->z > mx && v3->z > mx) return false; + + o1 = s1->exactOrientation(v1, v2, v3); + o2 = s2->exactOrientation(v1, v2, v3); + if (o1 == 0 && o2 == 0) + { + if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; + if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; + if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; + if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true; + return false; + } + + if ((o1>0 && o2>0) || (o1<0 && o2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 + o1 = s1->exactOrientation(s2, v1, v2); + o2 = s1->exactOrientation(s2, v2, v3); + if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; + o3 = s1->exactOrientation(s2, v3, v1); + if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; + if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; + return true; +} + +bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& oo1, const coord& oo2) +{ + // In this case the fast reject by bounding box appears to be a disadvantage ... + if (oo1 == 0 && oo2 == 0) + { + if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; + if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; + if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; + if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true; + return false; + } + + if ((oo1>0 && oo2>0) || (oo1<0 && oo2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 + coord o1, o2, o3; + o1 = s1->exactOrientation(s2, v1, v2); + o2 = s1->exactOrientation(s2, v2, v3); + if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; + o3 = s1->exactOrientation(s2, v3, v1); + if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; + if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; + return true; +} + } //namespace T_MESH diff --git a/src/mesh_fix/src/MeshFix/meshfix.cpp b/src/mesh_fix/src/MeshFix/meshfix.cpp index d864c79646..3f6ea84833 100644 --- a/src/mesh_fix/src/MeshFix/meshfix.cpp +++ b/src/mesh_fix/src/MeshFix/meshfix.cpp @@ -29,30 +29,30 @@ bool joinClosestComponents(Basic_TMesh *tin) Triangle *t, *s; Node *n; List triList, boundary_loops, *one_loop; - List **bloops_array; + Data *bloops_array; int i, j, numloops; // Mark triangles with connected component's unique ID i = 0; - FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL; - FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info == NULL) + FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info.forget(); + FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info.empty()) { i++; triList.appendHead(t); - t->info = new intWrapper(i); + t->info = i; while (triList.numels()) { t = (Triangle *)triList.popHead(); - if ((s = t->t1()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = new intWrapper(i); } - if ((s = t->t2()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = new intWrapper(i); } - if ((s = t->t3()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = new intWrapper(i); } + if ((s = t->t1()) != NULL && s->info.empty()) { triList.appendHead(s); s->info = i; } + if ((s = t->t2()) != NULL && s->info.empty()) { triList.appendHead(s); s->info = i; } + if ((s = t->t3()) != NULL && s->info.empty()) { triList.appendHead(s); s->info = i; } } } if (i<2) { - FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL; + FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info.forget(); // JMesh::info("Mesh is a single component. Nothing done."); return false; } @@ -75,7 +75,7 @@ bool joinClosestComponents(Basic_TMesh *tin) } FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_VISIT2(v); - bloops_array = (List **)boundary_loops.toArray(); + bloops_array = boundary_loops.toArray(); numloops = boundary_loops.numels(); int numtris = tin->T.numels(); @@ -84,7 +84,7 @@ bool joinClosestComponents(Basic_TMesh *tin) gv = NULL; for (i = 0; ihead()->data)->info != ((Vertex *)bloops_array[j]->head()->data)->info) + if (((Vertex *)((List*)(bloops_array[i]))->head()->data)->info != ((Vertex *)((List*)(bloops_array[j]))->head()->data)->info) { adist = closestPair(bloops_array[i], bloops_array[j], &v, &w); if (adistjoinBoundaryLoops(gv, gw, 1, 0); - FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL; - FOREACHVVVERTEX((&(tin->V)), v, n) v->info = NULL; + FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info.forget(); + FOREACHVVVERTEX((&(tin->V)), v, n) v->info.forget(); - free(bloops_array); + delete [] bloops_array; while ((one_loop = (List *)boundary_loops.popHead()) != NULL) delete one_loop; return (gv != NULL); diff --git a/src/mesh_fix/src/TMesh/edge.cpp b/src/mesh_fix/src/TMesh/edge.cpp index cee1ff3eb7..c32be0a71a 100644 --- a/src/mesh_fix/src/TMesh/edge.cpp +++ b/src/mesh_fix/src/TMesh/edge.cpp @@ -28,143 +28,143 @@ * * ****************************************************************************/ -#include "edge.h" -#include "triangle.h" - -namespace T_MESH -{ - -//////// Length-based edge comparison for qsort ////////// - -int edgeCompare(const Data *a, const Data *b) -{ - coord la = ((Edge *)a)->squaredLength(); - coord lb = ((Edge *)b)->squaredLength(); - - if (lalb) return 1; - - return 0; -} - - -//////// Lexycographic edge comparison for qsort ////////// - -int lexEdgeCompare(const Data *a, const Data *b) -{ - Vertex *va1 = ((Edge *)a)->v1; - Vertex *va2 = ((Edge *)a)->v2; - Vertex *vb1 = ((Edge *)b)->v1; - Vertex *vb2 = ((Edge *)b)->v2; - - if (xyzCompare(va1, va2) > 0) p_swap((void **)&va1, (void **)&va2); - if (xyzCompare(vb1, vb2) > 0) p_swap((void **)&vb1, (void **)&vb2); - - int ca = xyzCompare(va1, vb1); - - if (ca == 0) return xyzCompare(va2, vb2); - - return ca; -} - - -//////// Vertex-based edge comparison for qsort ////////// - -int vtxEdgeCompare(const Data *a, const Data *b) -{ - Vertex *va1 = ((Edge *)a)->v1; - Vertex *va2 = ((Edge *)a)->v2; - Vertex *vb1 = ((Edge *)b)->v1; - Vertex *vb2 = ((Edge *)b)->v2; - Vertex *tmp; - - if (va2vb1) return 1; - if (va2vb2) return 1; - return 0; -} - - -//////////////////////// Constructor /////////////////////// -//!< AMF_ADD 1.1-2 > -Edge::Edge(){ - mask = 0; - info = NULL; -} -Edge::Edge(Vertex *va, Vertex *vb) -{ - v1 = va; - v2 = vb; - t1 = t2 = NULL; - info = NULL; - mask = 0; -} - - -////////////////// Destructor ///////////////////////////// - -Edge::~Edge() -{ -} - - -////// Returns the unit vector for the edge direction ////// - -Point Edge::toUnitVector() const -{ - Point v = toVector(); - coord l = v.length(); - - if (l == 0) TMesh::error("Edge::toUnitVector : Degenerate Edge !\n"); - - return v/l; -} - - -/// Returns the edge normal. //// -/// It is the average of the incident triangle normals //// - -Point Edge::getNormal() const -{ - Point nor, n1, n2; - - if (t1 == NULL || t2 == NULL) return Point(0,0,0); - - n1 = t1->getNormal(); - n2 = t2->getNormal(); - nor = n1+n2; - if (nor.length() != 0.0) nor.normalize(); - return nor; -} - -////////////////////////// Edge swap //////////////////////// - -bool Edge::swap(const bool fast) -{ - if (!fast && (t1 == NULL || t2 == NULL || - t2->oppositeVertex(this)->getEdge(t1->oppositeVertex(this)) != NULL)) return 0; - - Edge *e1 = t1->nextEdge(this); - Edge *e3 = t2->nextEdge(this); - v1->e0 = e3; - v2->e0 = e1; - v1 = t2->oppositeVertex(this); - v2 = t1->oppositeVertex(this); - t1->replaceEdge(e1, e3); - t2->replaceEdge(e3, e1); - t1->invert(); - t2->invert(); - e1->replaceTriangle(t1, t2); - e3->replaceTriangle(t2, t1); - - return 1; -} - - -////////////////////////// Edge collapse //////////////////////// +#include "edge.h" +#include "triangle.h" + +namespace T_MESH +{ + +//////// Length-based edge comparison for qsort ////////// + +int edgeCompare(const Data &a, const Data &b) +{ + coord la = ((Edge *)a)->squaredLength(); + coord lb = ((Edge *)b)->squaredLength(); + + if (lalb) return 1; + + return 0; +} + + +//////// Lexycographic edge comparison for qsort ////////// + +int lexEdgeCompare(const Data& a, const Data &b) +{ + Vertex *va1 = ((Edge *)a)->v1; + Vertex *va2 = ((Edge *)a)->v2; + Vertex *vb1 = ((Edge *)b)->v1; + Vertex *vb2 = ((Edge *)b)->v2; + + if (xyzCompare(va1, va2) > 0) p_swap((void **)&va1, (void **)&va2); + if (xyzCompare(vb1, vb2) > 0) p_swap((void **)&vb1, (void **)&vb2); + + int ca = xyzCompare(va1, vb1); + + if (ca == 0) return xyzCompare(va2, vb2); + + return ca; +} + + +//////// Vertex-based edge comparison for qsort ////////// + +int vtxEdgeCompare(const Data &a, const Data &b) +{ + Vertex *va1 = ((Edge *)a)->v1; + Vertex *va2 = ((Edge *)a)->v2; + Vertex *vb1 = ((Edge *)b)->v1; + Vertex *vb2 = ((Edge *)b)->v2; + Vertex *tmp; + + if (va2vb1) return 1; + if (va2vb2) return 1; + return 0; +} + + +//////////////////////// Constructor /////////////////////// +//!< AMF_ADD 1.1-2 > +Edge::Edge(){ + mask = 0; + info.forget(); +} +Edge::Edge(Vertex *va, Vertex *vb) +{ + v1 = va; + v2 = vb; + t1 = t2 = NULL; + info.forget(); + mask = 0; +} + + +////////////////// Destructor ///////////////////////////// + +Edge::~Edge() +{ +} + + +////// Returns the unit vector for the edge direction ////// + +Point Edge::toUnitVector() const +{ + Point v = toVector(); + coord l = v.length(); + + if (l == 0) TMesh::error("Edge::toUnitVector : Degenerate Edge !\n"); + + return v/l; +} + + +/// Returns the edge normal. //// +/// It is the average of the incident triangle normals //// + +Point Edge::getNormal() const +{ + Point nor, n1, n2; + + if (t1 == NULL || t2 == NULL) return Point(0,0,0); + + n1 = t1->getNormal(); + n2 = t2->getNormal(); + nor = n1+n2; + if (nor.length() != 0.0) nor.normalize(); + return nor; +} + +////////////////////////// Edge swap //////////////////////// + +bool Edge::swap(const bool fast) +{ + if (!fast && (t1 == NULL || t2 == NULL || + t2->oppositeVertex(this)->getEdge(t1->oppositeVertex(this)) != NULL)) return 0; + + Edge *e1 = t1->nextEdge(this); + Edge *e3 = t2->nextEdge(this); + v1->e0 = e3; + v2->e0 = e1; + v1 = t2->oppositeVertex(this); + v2 = t1->oppositeVertex(this); + t1->replaceEdge(e1, e3); + t2->replaceEdge(e3, e1); + t1->invert(); + t2->invert(); + e1->replaceTriangle(t1, t2); + e3->replaceTriangle(t2, t1); + + return 1; +} + + +////////////////////////// Edge collapse //////////////////////// Vertex *Edge::collapseOnV1() { @@ -251,177 +251,177 @@ bool Edge::collapse(const Point& p) return true; } - -bool Edge::collapse() -{ - return collapse(((*v1)+(*v2))/2); -} - - -///// Merge with another boundary edge ///// - -bool Edge::merge(Edge *e) -{ - if (t1 && t2) return 0; - if (e->t1 && e->t2) return 0; - Triangle *ot = (e->t1==NULL)?(e->t2):(e->t1); - if (ot == getBoundaryTriangle()) return 0; - if ((t1 && e->t1) || (t2 && e->t2)) e->invert(); - Vertex *ov1 = e->v1, *ov2 = e->v2; - List *ve1=NULL, *ve2=NULL; - Node *n; - Edge *f, *f2; - - if (ov1 != v1) - { - ve1 = ov1->VE(); - FOREACHVEEDGE(ve1, f, n) - { - f2 = f->oppositeVertex(ov1)->getEdge(v1); - if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary())) - {delete(ve1); return 0;} - } - } - if (ov2 != v2) - { - ve2 = ov2->VE(); - FOREACHVEEDGE(ve2, f, n) - { - f2 = f->oppositeVertex(ov2)->getEdge(v2); - if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary())) - {delete(ve1); delete(ve2); return 0;} - } - } - - if (ov1 != v1) - { - FOREACHVEEDGE(ve1, f, n) f->replaceVertex(ov1, v1); - delete(ve1); - ov1->e0 = NULL; - } - if (ov2 != v2) - { - FOREACHVEEDGE(ve2, f, n) f->replaceVertex(ov2, v2); - delete(ve2); - ov2->e0 = NULL; - } - ot->replaceEdge(e, this); - ((t1==NULL)?(t1):(t2)) = ot; - v1->e0 = v2->e0 = this; - e->v1 = e->v2 = NULL; - - return 1; -} - - -///// Angle between the normal of incident triangles ///// - -double Edge::curvature() const -{ - if (!t1 || !t2) return -1.0; - return t1->getDAngle(t2); -} - - -//// Dihedral angle - -double Edge::dihedralAngle() const -{ - if (!t1 || !t2) return -1.0; - Point nor1 = t1->getNormal(); - Point nor2 = t2->getNormal(); - if (nor1.isNull() || nor2.isNull()) return -1.0; - double c = nor1.getAngle(&nor2); - - Vertex *ov = t2->oppositeVertex(this); - if (((*ov)*nor1) - ((*v1)*nor1) < 0) return -(c - M_PI); - - return c+M_PI; -} - -//// Min Angle among those of the two incident triangles //// - -double Edge::delaunayMinAngle() const -{ - if (t1==NULL || t2==NULL) return 2*M_PI; - if (squaredLength()==0) return 0; - if (t1->nextEdge(this)->squaredLength() == 0) return 0; - if (t1->prevEdge(this)->squaredLength() == 0) return 0; - double a1 = t1->getAngle(v1); - double a2 = t1->getAngle(v2); - double a3 = t1->getAngle(t1->oppositeVertex(this)); - if (t2->nextEdge(this)->length()==0) return 0; - if (t2->prevEdge(this)->length()==0) return 0; - double a4 = t2->getAngle(v1); - double a5 = t2->getAngle(v2); - double a6 = t2->getAngle(t2->oppositeVertex(this)); - - if (a1+a4 >= M_PI || a2+a5 >= M_PI) return 3*M_PI; - return MIN(a1,(MIN(a2,(MIN(a3,(MIN(a4,(MIN(a5,a6))))))))); -} - - -// If edge is stitchable, merge it with its copy - -bool Edge::stitch() -{ - // This function seems to be insufficient to stitch in every case ! - if (!isOnBoundary()) return 0; - - Triangle *t, *t0 = (t1 != NULL) ? (t1) : (t2); - Vertex *v0; - Edge *e1; - - for (v0 = v1; v0 != NULL; v0 = ((v0 == v1) ? (v2) : (NULL))) - { - e1 = this; - t = t0; - while (t != NULL) - { - e1 = t->nextEdge(e1); if (!e1->hasVertex(v0)) e1 = t->nextEdge(e1); - t = e1->oppositeTriangle(t); - } - if (e1->oppositeVertex(v0) == oppositeVertex(v0)) - { - t = (e1->t1 != NULL) ? (e1->t1) : (e1->t2); - t->replaceEdge(e1, this); - v1->e0 = v2->e0 = this; - e1->v1 = e1->v2 = NULL; - replaceTriangle(NULL, t); - return 1; - } - } - - return 0; -} - -bool Edge::overlaps() const -{ - if (t1 == NULL || t2 == NULL) return false; - - Vertex *ov = t2->oppositeVertex(this); - if (ov->exactOrientation(t1->v1(), t1->v2(), t1->v3()) == 0 && ov->exactSameSideOnPlane(t1->oppositeVertex(this), v1, v2)) return true; - else return false; -} - -bool Edge::intersects(const Triangle *t) const -{ - if (t->hasEdge(this)) return false; - - Vertex *cv = (t->hasVertex(v1)) ? (v1) : ((t->hasVertex(v2)) ? (v2) : (NULL)); - if (cv) // If they share a vertex, intersection occurs if t's opposite edge intersect this edge - { - Edge *oe = t->oppositeEdge(cv); - if (Point::pointInTriangle(oppositeVertex(cv), cv, oe->v1, oe->v2)) return true; - else return (Point::segmentsIntersect(oe->v1, oe->v2, v1, v2)); - } - else return Point::segmentIntersectsTriangle(v1, v2, t->v1(), t->v2(), t->v3()); -} - -coord Edge::getConvexity() const -{ - if (t1 == NULL || t2 == NULL) return DBL_MAX; - else return (t1->oppositeVertex(this)->exactOrientation(t2->v3(), t2->v2(), t2->v1())); -} - + +bool Edge::collapse() +{ + return collapse(((*v1)+(*v2))/2); +} + + +///// Merge with another boundary edge ///// + +bool Edge::merge(Edge *e) +{ + if (t1 && t2) return 0; + if (e->t1 && e->t2) return 0; + Triangle *ot = (e->t1==NULL)?(e->t2):(e->t1); + if (ot == getBoundaryTriangle()) return 0; + if ((t1 && e->t1) || (t2 && e->t2)) e->invert(); + Vertex *ov1 = e->v1, *ov2 = e->v2; + List *ve1=NULL, *ve2=NULL; + Node *n; + Edge *f, *f2; + + if (ov1 != v1) + { + ve1 = ov1->VE(); + FOREACHVEEDGE(ve1, f, n) + { + f2 = f->oppositeVertex(ov1)->getEdge(v1); + if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary())) + {delete(ve1); return 0;} + } + } + if (ov2 != v2) + { + ve2 = ov2->VE(); + FOREACHVEEDGE(ve2, f, n) + { + f2 = f->oppositeVertex(ov2)->getEdge(v2); + if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary())) + {delete(ve1); delete(ve2); return 0;} + } + } + + if (ov1 != v1) + { + FOREACHVEEDGE(ve1, f, n) f->replaceVertex(ov1, v1); + delete(ve1); + ov1->e0 = NULL; + } + if (ov2 != v2) + { + FOREACHVEEDGE(ve2, f, n) f->replaceVertex(ov2, v2); + delete(ve2); + ov2->e0 = NULL; + } + ot->replaceEdge(e, this); + ((t1==NULL)?(t1):(t2)) = ot; + v1->e0 = v2->e0 = this; + e->v1 = e->v2 = NULL; + + return 1; +} + + +///// Angle between the normal of incident triangles ///// + +double Edge::curvature() const +{ + if (!t1 || !t2) return -1.0; + return t1->getDAngle(t2); +} + + +//// Dihedral angle + +double Edge::dihedralAngle() const +{ + if (!t1 || !t2) return -1.0; + Point nor1 = t1->getNormal(); + Point nor2 = t2->getNormal(); + if (nor1.isNull() || nor2.isNull()) return -1.0; + double c = nor1.getAngle(&nor2); + + Vertex *ov = t2->oppositeVertex(this); + if (((*ov)*nor1) - ((*v1)*nor1) < 0) return -(c - M_PI); + + return c+M_PI; +} + +//// Min Angle among those of the two incident triangles //// + +double Edge::delaunayMinAngle() const +{ + if (t1==NULL || t2==NULL) return 2*M_PI; + if (squaredLength()==0) return 0; + if (t1->nextEdge(this)->squaredLength() == 0) return 0; + if (t1->prevEdge(this)->squaredLength() == 0) return 0; + double a1 = t1->getAngle(v1); + double a2 = t1->getAngle(v2); + double a3 = t1->getAngle(t1->oppositeVertex(this)); + if (t2->nextEdge(this)->length()==0) return 0; + if (t2->prevEdge(this)->length()==0) return 0; + double a4 = t2->getAngle(v1); + double a5 = t2->getAngle(v2); + double a6 = t2->getAngle(t2->oppositeVertex(this)); + + if (a1+a4 >= M_PI || a2+a5 >= M_PI) return 3*M_PI; + return MIN(a1,(MIN(a2,(MIN(a3,(MIN(a4,(MIN(a5,a6))))))))); +} + + +// If edge is stitchable, merge it with its copy + +bool Edge::stitch() +{ + // This function seems to be insufficient to stitch in every case ! + if (!isOnBoundary()) return 0; + + Triangle *t, *t0 = (t1 != NULL) ? (t1) : (t2); + Vertex *v0; + Edge *e1; + + for (v0 = v1; v0 != NULL; v0 = ((v0 == v1) ? (v2) : (NULL))) + { + e1 = this; + t = t0; + while (t != NULL) + { + e1 = t->nextEdge(e1); if (!e1->hasVertex(v0)) e1 = t->nextEdge(e1); + t = e1->oppositeTriangle(t); + } + if (e1->oppositeVertex(v0) == oppositeVertex(v0)) + { + t = (e1->t1 != NULL) ? (e1->t1) : (e1->t2); + t->replaceEdge(e1, this); + v1->e0 = v2->e0 = this; + e1->v1 = e1->v2 = NULL; + replaceTriangle(NULL, t); + return 1; + } + } + + return 0; +} + +bool Edge::overlaps() const +{ + if (t1 == NULL || t2 == NULL) return false; + + Vertex *ov = t2->oppositeVertex(this); + if (ov->exactOrientation(t1->v1(), t1->v2(), t1->v3()) == 0 && ov->exactSameSideOnPlane(t1->oppositeVertex(this), v1, v2)) return true; + else return false; +} + +bool Edge::intersects(const Triangle *t) const +{ + if (t->hasEdge(this)) return false; + + Vertex *cv = (t->hasVertex(v1)) ? (v1) : ((t->hasVertex(v2)) ? (v2) : (NULL)); + if (cv) // If they share a vertex, intersection occurs if t's opposite edge intersect this edge + { + Edge *oe = t->oppositeEdge(cv); + if (Point::pointInTriangle(oppositeVertex(cv), cv, oe->v1, oe->v2)) return true; + else return (Point::segmentsIntersect(oe->v1, oe->v2, v1, v2)); + } + else return Point::segmentIntersectsTriangle(v1, v2, t->v1(), t->v2(), t->v3()); +} + +coord Edge::getConvexity() const +{ + if (t1 == NULL || t2 == NULL) return DBL_MAX; + else return (t1->oppositeVertex(this)->exactOrientation(t2->v3(), t2->v2(), t2->v1())); +} + } //namespace T_MESH diff --git a/src/mesh_fix/src/TMesh/io.cpp b/src/mesh_fix/src/TMesh/io.cpp index 1dda5ff413..25b6842908 100644 --- a/src/mesh_fix/src/TMesh/io.cpp +++ b/src/mesh_fix/src/TMesh/io.cpp @@ -357,14 +357,12 @@ int Basic_TMesh::loadVRML1(const char *fname) int i,i1,i2,i3,i4,nv=0,triangulate=0; Vertex *v; - coord cx; - if ((fp = fopen(fname,"r")) == NULL) return IO_CANTOPEN; if (!seek_keyword(fp, "point")) {closeLoadingSession(fp, 0, NULL, 0); return IO_FORMAT;} if (!seek_keyword(fp, "[")) {closeLoadingSession(fp, 0, NULL, 0); return IO_FORMAT;} - while (fscanf(fp, "%f %f %f,", &x, &y, &z) == 3) { V.appendTail(newVertex(x, y, z)); cx = coord(x); /*printf("%f %f\n", x, cx.toFloat());*/ } + while (fscanf(fp, "%f %f %f,", &x, &y, &z) == 3) { V.appendTail(newVertex(x, y, z));/* cx = coord(x); printf("%f %f\n", x, cx.toFloat());*/ } nv = V.numels(); ExtVertex **var = (ExtVertex **)malloc(sizeof(ExtVertex *)*nv); i = 0; FOREACHVERTEX(v, n) var[i++] = new ExtVertex(v); @@ -473,7 +471,7 @@ int Basic_TMesh::loadEFF(const char *fname) Node *n; char s[256]; coord x, y, z; - int i, i1, i2, i3, nv=-1, nt=-1, triangulate = 0; + int i, i1, i2, i3, nv=-1, nt=-1; Vertex *v; @@ -722,7 +720,7 @@ int Basic_TMesh::saveVRML1(const char *fname, const int mode) fprintf(fp,"Material {\n diffuseColor [\n"); FOREACHTRIANGLE(t, n) { - pkc = ((intWrapper*)(t->info))->operator int(); + pkc = (unsigned int)((j_voidint)t->info); fprintf(fp," %f %f %f,\n",((pkc>>24)&0x000000ff)/255.0,((pkc>>16)&0x000000ff)/255.0,((pkc>>8)&0x000000ff)/255.0); } fprintf(fp," ]\n}\nMaterialBinding {\n value PER_FACE_INDEXED\n}\n"); @@ -731,7 +729,7 @@ int Basic_TMesh::saveVRML1(const char *fname, const int mode) fprintf(fp,"Material {\n diffuseColor [\n"); FOREACHVERTEX(v, n) { - pkc = ((intWrapper*)(v->info))->operator int(); + pkc = (unsigned int)((j_voidint)v->info); fprintf(fp," %f %f %f,\n",((pkc>>24)&0x000000ff)/255.0,((pkc>>16)&0x000000ff)/255.0,((pkc>>8)&0x000000ff)/255.0); } fprintf(fp," ]\n}\nMaterialBinding {\n value PER_VERTEX_INDEXED\n}\n"); @@ -893,7 +891,7 @@ int Basic_TMesh::saveVerTri(const char *fname) ocds = new coord[V.numels()]; i=0; FOREACHVERTEX(v, n) ocds[i++] = v->x; i=0; FOREACHVERTEX(v, n) v->x = ++i; - i=0; FOREACHTRIANGLE(t, n) {i++; t->info = new intWrapper(i);} + i=0; FOREACHTRIANGLE(t, n) {i++; t->info = i;} fprintf(fpt,"%d\n",T.numels()); FOREACHTRIANGLE(t, n) @@ -948,13 +946,13 @@ bool Basic_TMesh::pinch(Edge *e1, bool with_common_vertex) } if (n == NULL) return false; - ee->removeNode(e1); ee->removeNode(e2); e1->info = e2->info = NULL; + ee->removeNode(e1); ee->removeNode(e2); e1->info.forget(); e2->info.forget(); if (ee->numels() == 0) delete ee; Edge *e, *e_1 = NULL, *e_2 = NULL; ve = e1->v1->VE(); - for (n = ve->head(); n != NULL; n = n->next()) if ((e = (Edge *)n->data)->info != NULL) { e_1 = e; break; } - for (n = ve->tail(); n != NULL; n = n->prev()) if ((e = (Edge *)n->data)->info != NULL) + for (n = ve->head(); n != NULL; n = n->next()) if ((e = (Edge *)n->data)->info.notEmpty()) { e_1 = e; break; } + for (n = ve->tail(); n != NULL; n = n->prev()) if ((e = (Edge *)n->data)->info.notEmpty()) { if ((*(e->oppositeVertex(e1->v1))) != (*(e_1->oppositeVertex(e1->v1)))) e_1 = NULL; break; @@ -962,8 +960,8 @@ bool Basic_TMesh::pinch(Edge *e1, bool with_common_vertex) delete ve; ve = e1->v2->VE(); - for (n = ve->head(); n != NULL; n = n->next()) if ((e = (Edge *)n->data)->info != NULL) { e_2 = e; break; } - for (n = ve->tail(); n != NULL; n = n->prev()) if ((e = (Edge *)n->data)->info != NULL) + for (n = ve->head(); n != NULL; n = n->next()) if ((e = (Edge *)n->data)->info.notEmpty()) { e_2 = e; break; } + for (n = ve->tail(); n != NULL; n = n->prev()) if ((e = (Edge *)n->data)->info.notEmpty()) { if ((*(e->oppositeVertex(e1->v2))) != (*(e_2->oppositeVertex(e1->v2)))) e_2 = NULL; break; @@ -1004,7 +1002,7 @@ int Basic_TMesh::cutAndStitch() duplicateNonManifoldVertices(); singular_edges.sort(&lexEdgeCompare); - FOREACHEDGE(e1, n) e1->info = NULL; + FOREACHEDGE(e1, n) e1->info.forget(); e2 = NULL; FOREACHVEEDGE((&singular_edges), e1, n) { @@ -1465,7 +1463,6 @@ int Basic_TMesh::loadSTL(const char *fname) bool binary=0; Vertex *v, *v1=NULL, *v2=NULL, *v3=NULL; Edge *e1, *e2, *e3; - Triangle *t; Point nor; if ((fp = fopen(fname,"r")) == NULL) return IO_CANTOPEN; @@ -1502,8 +1499,8 @@ int Basic_TMesh::loadSTL(const char *fname) v3 = newVertex((*((float *)(facet+36))), (*((float *)(facet+40))), (*((float *)(facet+44)))); V.appendHead(v1); V.appendHead(v2); V.appendHead(v3); e1=CreateEdge(v1, v2); e2=CreateEdge(v2, v3); e3=CreateEdge(v3, v1); - if (Triangle(e1,e2,e3).getNormal()*nor < 0) t=CreateTriangle(e1, e3, e2); - else t=CreateTriangle(e1, e2, e3); + if (Triangle(e1,e2,e3).getNormal()*nor < 0) CreateTriangle(e1, e3, e2); + else CreateTriangle(e1, e2, e3); } } else @@ -1529,8 +1526,8 @@ int Basic_TMesh::loadSTL(const char *fname) e1=CreateEdge(v1, v2); e2=CreateEdge(v2, v3); e3=CreateEdge(v3, v1); - if (Triangle(e1,e2,e3).getNormal()*nor < 0) t=CreateTriangle(e1, e3, e2); - else t=CreateTriangle(e1, e2, e3); + if (Triangle(e1,e2,e3).getNormal()*nor < 0) CreateTriangle(e1, e3, e2); + else CreateTriangle(e1, e2, e3); v1=v2=v3=NULL; } } diff --git a/src/mesh_fix/src/TMesh/tin.cpp b/src/mesh_fix/src/TMesh/tin.cpp index 7cd3d89133..9b618a798b 100644 --- a/src/mesh_fix/src/TMesh/tin.cpp +++ b/src/mesh_fix/src/TMesh/tin.cpp @@ -32,16 +32,16 @@ #include #include -namespace T_MESH -{ +namespace T_MESH +{ Vertex * Basic_TMesh::newVertex(){ return new Vertex(); } //!< AMF_ADD 1.1> - Vertex * Basic_TMesh::newVertex(const coord &x, const coord &y, const coord &z){ return new Vertex(x, y, z); } //!< AMF_ADD 1.1> - Vertex * Basic_TMesh::newVertex(Point *p){ return new Vertex(p); } //!< AMF_ADD 1.1> - Vertex * Basic_TMesh::newVertex(Point &p){ return new Vertex(p); } //!< AMF_ADD 1.1> - Vertex * Basic_TMesh::newVertex(Vertex *v){ return new Vertex(v); } //!< AMF_ADD 1.1-2> - Edge * Basic_TMesh::newEdge(Vertex *s, Vertex *d){ return new Edge(s, d); } //!< AMF_ADD 1.1> - Edge * Basic_TMesh::newEdge(Edge *e){ return new Edge(e->v1,e->v2); } //!< AMF_ADD 1.1-2> + Vertex * Basic_TMesh::newVertex(const coord &x, const coord &y, const coord &z){ return new Vertex(x, y, z); } //!< AMF_ADD 1.1> + Vertex * Basic_TMesh::newVertex(Point *p){ return new Vertex(p); } //!< AMF_ADD 1.1> + Vertex * Basic_TMesh::newVertex(Point &p){ return new Vertex(p); } //!< AMF_ADD 1.1> + Vertex * Basic_TMesh::newVertex(Vertex *v){ return new Vertex(v); } //!< AMF_ADD 1.1-2> + Edge * Basic_TMesh::newEdge(Vertex *s, Vertex *d){ return new Edge(s, d); } //!< AMF_ADD 1.1> + Edge * Basic_TMesh::newEdge(Edge *e){ return new Edge(e->v1,e->v2); } //!< AMF_ADD 1.1-2> Triangle * Basic_TMesh::newTriangle(){ return new Triangle(); } //!< AMF_ADD 1.1> Triangle * Basic_TMesh::newTriangle(Edge *a, Edge *b, Edge *c){ return new Triangle(a, b, c); } //!< AMF_ADD 1.1> @@ -124,8 +124,8 @@ void Basic_TMesh::init(const char *tin_definition) } else if (!strcmp(tin_definition, "cube")) { - const double crds[8][3] = {{0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0},{0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1}}; - const int tris[12][3] = {{3, 2, 1},{3, 1, 0},{4, 5, 6},{4, 6, 7},{7, 6, 2},{7, 2, 3},{0, 1, 5},{0, 5, 4},{1, 2, 6},{1, 6, 5},{3, 0, 4},{3, 4, 7}}; + const double crds[8][3] = {{0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0},{0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1}}; + const int tris[12][3] = {{3, 2, 1},{3, 1, 0},{4, 5, 6},{4, 6, 7},{7, 6, 2},{7, 2, 3},{0, 1, 5},{0, 5, 4},{1, 2, 6},{1, 6, 5},{3, 0, 4},{3, 4, 7}}; ExtVertex *ev[8]; for (int i=0; i<8; i++) { @@ -144,7 +144,7 @@ void Basic_TMesh::init(const char *tin_definition) } else if (!strcmp(tin_definition, "cylinder")) { - const double crds[8][2] = {{1,0},{0.7,0.7},{0,1},{-0.7,0.7},{-1,0},{-0.7,-0.7},{0,-1},{0.7,-0.7}}; + const double crds[8][2] = {{1,0},{0.7,0.7},{0,1},{-0.7,0.7},{-1,0},{-0.7,-0.7},{0,-1},{0.7,-0.7}}; ExtVertex *ev[8]; for (int i=0; i<16; i++) { @@ -187,11 +187,11 @@ void Basic_TMesh::init(const Basic_TMesh *tin, const bool clone_info) Triangle *t, *nt; int i; - Data **t_info = new Data *[tin->T.numels()]; + Data *t_info = new Data [tin->T.numels()]; i=0; FOREACHVTTRIANGLE((&(tin->T)), t, n) t_info[i++]=t->info; - Data **e_info = new Data *[tin->E.numels()]; + Data *e_info = new Data [tin->E.numels()]; i=0; FOREACHVEEDGE((&(tin->E)), e, n) e_info[i++]=e->info; - Data **v_info = new Data *[tin->V.numels()]; + Data *v_info = new Data [tin->V.numels()]; i=0; FOREACHVVVERTEX((&(tin->V)), v, n) v_info[i++]=v->info; FOREACHVVVERTEX((&(tin->V)), v, n) @@ -205,10 +205,10 @@ void Basic_TMesh::init(const Basic_TMesh *tin, const bool clone_info) FOREACHVTTRIANGLE((&(tin->T)), t, n) {nt=newTriangle((Edge *)t->e1->info,(Edge *)t->e2->info,(Edge *)t->e3->info); T.appendTail(nt); t->info = nt;} - FOREACHVVVERTEX((&(tin->V)), v, n) {((Vertex *)v->info)->e0 = (Edge *)v->e0->info; v->info = NULL;} + FOREACHVVVERTEX((&(tin->V)), v, n) {((Vertex *)v->info)->e0 = (Edge *)v->e0->info; v->info.forget();} FOREACHVEEDGE((&(tin->E)), e, n) - {((Edge *)e->info)->t1 = (e->t1)?((Triangle *)e->t1->info):(NULL); ((Edge *)e->info)->t2 = (e->t2)?((Triangle *)e->t2->info):(NULL); e->info = NULL;} + {((Edge *)e->info)->t1 = (e->t1)?((Triangle *)e->t1->info):(NULL); ((Edge *)e->info)->t2 = (e->t2)?((Triangle *)e->t2->info):(NULL); e->info.forget();} i=0; FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info=t_info[i++]; i=0; FOREACHVEEDGE((&(tin->E)), e, n) e->info=e_info[i++]; @@ -280,9 +280,9 @@ void Basic_TMesh::init(const Triangle *t0, const bool keep_reference) if (!keep_reference) { - FOREACHVVVERTEX((&sv), v, n) v->info = NULL; - FOREACHVEEDGE((&se), e, n) e->info = NULL; - FOREACHVTTRIANGLE((&st), t, n) t->info = NULL; + FOREACHVVVERTEX((&sv), v, n) v->info.forget(); + FOREACHVEEDGE((&se), e, n) e->info.forget(); + FOREACHVTTRIANGLE((&st), t, n) t->info.forget(); } eulerUpdate(); @@ -293,11 +293,11 @@ Basic_TMesh *Basic_TMesh::split() { if (T.numels() == 0) return NULL; deselectTriangles(); - Triangle *t = (Triangle *)T.head()->data; - selectConnectedComponent(t); - Basic_TMesh *stin = createSubMeshFromSelection(t); - removeSelectedTriangles(); - return stin; + Triangle *t = (Triangle *)T.head()->data; + selectConnectedComponent(t); + Basic_TMesh *stin = createSubMeshFromSelection(t); + removeSelectedTriangles(); + return stin; } ///////////////////// Destructor /////////////////////////// @@ -424,32 +424,31 @@ Triangle *Basic_TMesh::EulerEdgeTriangle(Edge *e2, Edge *e3) /////////// Creation of two triangles bridging two boundary edges ///////////// -Edge *Basic_TMesh::bridgeBoundaries(Edge *gve, Edge *gwe) -{ - if (gve == gwe || !gve->isOnBoundary() || !gwe->isOnBoundary()) return NULL; - - Triangle *t; - Vertex *v = gve->commonVertex(gwe); - if (v != NULL) - { - t = EulerEdgeTriangle(gve, gwe); - return gve; - } - - Vertex *gv = (gve->t1) ? (gve->v1) : (gve->v2); - Vertex *gw = (gwe->t1) ? (gwe->v2) : (gwe->v1); - Vertex *gvn = gve->oppositeVertex(gv); - Vertex *gwn = gwe->oppositeVertex(gw); - - Edge *je = CreateEdge(gv, gw); - Edge *je2 = CreateEdge(gwn, gvn); - Edge *je1 = CreateEdge(gv, gwn); - - t = CreateTriangle(je, gwe, je1); - t = CreateTriangle(je1, je2, gve); - - return je1; -} +Edge *Basic_TMesh::bridgeBoundaries(Edge *gve, Edge *gwe) +{ + if (gve == gwe || !gve->isOnBoundary() || !gwe->isOnBoundary()) return NULL; + + Vertex *v = gve->commonVertex(gwe); + if (v != NULL) + { + EulerEdgeTriangle(gve, gwe); + return gve; + } + + Vertex *gv = (gve->t1) ? (gve->v1) : (gve->v2); + Vertex *gw = (gwe->t1) ? (gwe->v2) : (gwe->v1); + Vertex *gvn = gve->oppositeVertex(gv); + Vertex *gwn = gwe->oppositeVertex(gw); + + Edge *je = CreateEdge(gv, gw); + Edge *je2 = CreateEdge(gwn, gvn); + Edge *je1 = CreateEdge(gv, gwn); + + CreateTriangle(je, gwe, je1); + CreateTriangle(je1, je2, gve); + + return je1; +} ////////////////////////////////////////////////////////////////// // // @@ -622,16 +621,16 @@ int Basic_TMesh::removeVertices() } -//// Removes all the vertices that can be deleted without changing the geometric realization. O(N). -int Basic_TMesh::removeRedundantVertices() -{ - Node *n; - Vertex *v; - int fv = 0; - FOREACHVERTEX(v, n) if (v->removeIfRedundant()) fv++; - removeUnlinkedElements(); - return fv; -} +//// Removes all the vertices that can be deleted without changing the geometric realization. O(N). +int Basic_TMesh::removeRedundantVertices() +{ + Node *n; + Vertex *v; + int fv = 0; + FOREACHVERTEX(v, n) if (v->removeIfRedundant()) fv++; + removeUnlinkedElements(); + return fv; +} ////////////////////////////////////////////////////////////////// // // @@ -764,15 +763,15 @@ void Basic_TMesh::invertSelection(Triangle *t0) } -void Basic_TMesh::reselectSelection(Triangle *t0) -{ - if (!IS_VISITED(t0)) return; - - Node *n; - Triangle *t, *s; - List triList(t0); - MARK_VISIT2(t0); - +void Basic_TMesh::reselectSelection(Triangle *t0) +{ + if (!IS_VISITED(t0)) return; + + Node *n; + Triangle *t, *s; + List triList(t0); + MARK_VISIT2(t0); + while(triList.numels()) { t = (Triangle *)triList.popHead(); @@ -782,7 +781,7 @@ void Basic_TMesh::reselectSelection(Triangle *t0) } FOREACHTRIANGLE(t, n) if (!IS_VISITED2(t)) UNMARK_VISIT(t); else UNMARK_VISIT2(t); -} +} // Creates a new mesh out of a selection. @@ -838,14 +837,14 @@ Basic_TMesh *Basic_TMesh::createSubMeshFromSelection(Triangle *t0, bool keep_ref FOREACHVEEDGE((&sE), e, n) e->v1->e0 = e->v2->e0 = e; int i; - Data **v_info = NULL, **e_info = NULL, **t_info = NULL; + Data *v_info = NULL, *e_info = NULL, *t_info = NULL; if (!keep_ref) { - v_info = new Data *[sV.numels()]; + v_info = new Data [sV.numels()]; i=0; FOREACHVVVERTEX((&sV), v, n) v_info[i++] = v->info; - e_info = new Data *[sE.numels()]; + e_info = new Data [sE.numels()]; i=0; FOREACHVEEDGE((&sE), e, n) e_info[i++] = e->info; - t_info = new Data *[sT.numels()]; + t_info = new Data [sT.numels()]; i=0; FOREACHVTTRIANGLE((&sT), t, n) t_info[i++] = t->info; } @@ -884,17 +883,17 @@ Basic_TMesh *Basic_TMesh::createSubMeshFromSelection(Triangle *t0, bool keep_ref Basic_TMesh *Basic_TMesh::createSubMeshFromTriangle(Triangle *t0) { - Basic_TMesh *ntin = newObject("triangle"); - - Vertex *v1 = (Vertex *)ntin->V.head()->data; - Vertex *v2 = (Vertex *)ntin->V.head()->next()->data; - Vertex *v3 = (Vertex *)ntin->V.head()->next()->next()->data; - v1->setValue(t0->v1()); - v2->setValue(t0->v3()); - v3->setValue(t0->v2()); - ((Triangle *)ntin->T.head()->data)->info = t0->info; - - return ntin; + Basic_TMesh *ntin = newObject("triangle"); + + Vertex *v1 = (Vertex *)ntin->V.head()->data; + Vertex *v2 = (Vertex *)ntin->V.head()->next()->data; + Vertex *v3 = (Vertex *)ntin->V.head()->next()->next()->data; + v1->setValue(t0->v1()); + v2->setValue(t0->v3()); + v3->setValue(t0->v2()); + ((Triangle *)ntin->T.head()->data)->info = t0->info; + + return ntin; } ///// Marks all the triangles within distance L as selected ////// @@ -1130,15 +1129,15 @@ void Basic_TMesh::append(Basic_TMesh *src) } -// Move all the elements of 't' to this mesh and delete 't' itself. -void Basic_TMesh::moveMeshElements(Basic_TMesh *t, bool delInput) -{ +// Move all the elements of 't' to this mesh and delete 't' itself. +void Basic_TMesh::moveMeshElements(Basic_TMesh *t, bool delInput) +{ V.joinTailList(&(t->V)); E.joinTailList(&(t->E)); T.joinTailList(&(t->T)); d_boundaries = d_handles = d_shells = 1; if(delInput) delete t; -} +} ////////////////////////////////////////////////////////////////// @@ -1850,7 +1849,7 @@ void Basic_TMesh::openToDisk() FOREACHEDGE(e, n) UNMARK_BIT(e, 3); - FOREACHVERTEX(v, n) if (v->info) {delete(((List *)v->info)); v->info = NULL;} + FOREACHVERTEX(v, n) v->info.clear(); duplicateNonManifoldVertices(); d_boundaries = d_handles = d_shells = 1; } diff --git a/src/mesh_fix/src/TMesh/triangle.cpp b/src/mesh_fix/src/TMesh/triangle.cpp index 15fed33b72..f90f53c776 100644 --- a/src/mesh_fix/src/TMesh/triangle.cpp +++ b/src/mesh_fix/src/TMesh/triangle.cpp @@ -28,233 +28,233 @@ * * ****************************************************************************/ -#include "triangle.h" -#include - -namespace T_MESH -{ - -extern "C" double orient2d(double *, double *, double *); - -//////////////////// Constructor ////////////////////// - -//!< AMF_ADD 1.1> -Triangle::Triangle(){ - mask = 0; - info = NULL; -} - -Triangle::Triangle(Edge *a, Edge *b, Edge *c) -{ - e1 = a; - e2 = b; - e3 = c; - mask = 0; - info = NULL; -} - - -//////////////////// Normal vector ////////////////////// - -Point Triangle::getNormal() const -{ - Vertex *va = v1(), *vb = v2(), *vc = v3(); - Point vd = (((*va)-(*vb))&((*vb)-(*vc))); - coord l = vd.length(); - - if (l == 0) return Point(0,0,0); - - return vd/l; -} - - -////// Directional vector //////// - -Point Triangle::getVector() const -{ - Vertex *va = v1(), *vb = v2(), *vc = v3(); - return (((*va) - (*vb))&((*vb) - (*vc))); -} - - -/////////////////// Normal consistence check //////////////////// - -bool Triangle::checkAdjNor(const Triangle *t) const -{ - Edge *e = commonEdge(t); - if (e == NULL) return 1; - - Edge *ea = nextEdge(e); - Edge *eb = t->nextEdge(e); - if (ea->commonVertex(eb) == ea->commonVertex(e)) return 0; - - return 1; -} - - -//////////////////////// Triangle area ///////////////////////// - -double Triangle::area() const -{ - double a = e1->length(), b = e2->length(), c = e3->length(); - if (a==0.0 || b==0.0 || c==0.0) return 0.0; - double p = (a+b+c)/2.0; - p = p*(p-a)*(p-b)*(p-c); if (p<0) return 0.0; - return sqrt(p); -} - - -/////////////////////// Triangle perimeter ///////////////////// - -double Triangle::perimeter() const -{ - return e1->length()+e2->length()+e3->length(); -} - - -///////////// Barycenter /////////////////////// - -Point Triangle::getCenter() const -{ - Point va = *v1(), vb = *v2(), vc = *v3(); - return (va+vb+vc)/3.0; -} - - -///////////////////////// Circlecenter ///////////////////////// - -Point Triangle::getCircleCenter() const -{ - Point va = *v1(), vb = *v2(), vc = *v3(); - Point q1 = vb-va; - Point q2 = vc-va; - Point n = q2&q1; - Point m1 = e2->getMidPoint(); - Point m2 = e1->getMidPoint(); - - return Point(n*va,q1*m1,q2*m2).linearSystem(n,q1,q2); -} - - -/////// Check wether the point is inside the triangle's bounding ball ///// - -bool Triangle::inSphere(const Point *p) const -{ - Point c = getCircleCenter(); - coord rad = c.squaredDistance(e1->v1); - - return (p->squaredDistance(&c) < rad); -} - - -//////////////////// Angle at a vertex ///////////////////// - -double Triangle::getAngle(const Vertex *v) const -{ - Vertex *va = v1(), *vb = v2(), *vc = v3(); - if (v == va) return v->getAngle(vb, vc); - if (v == vb) return v->getAngle(va, vc); - if (v == vc) return v->getAngle(vb, va); - - return -1.0; -} - - -/////////// Angle between the two directional vectors ///////// - -double Triangle::getDAngle(const Triangle *t) const -{ - Point thisNormal = getVector(); - Point otherNormal = t->getVector(); - - if (thisNormal.isNull() || otherNormal.isNull()) return -1.0; - - return thisNormal.getAngle(otherNormal); -} - - -///////////// Distance from the plane of the triangle ////////////// - -double Triangle::distanceFromPoint(const Point *p) const -{ - return sqrt(TMESH_TO_DOUBLE(squaredDistanceFromPoint(p))); -} - -///////////// Squared distance from the plane of the triangle ////////////// - -coord Triangle::squaredDistanceFromPoint(const Point *p) const -{ - Point CA = e1->toVector()&e2->toVector(); - coord CA2 = CA*CA; - - if (CA2 == 0) return -1.0; - coord d = ((CA*(*p))-(CA*(*(e1->v1)))); - - return (d*d)/CA2; -} - - -///////////// Distance of point from the triangle ////////////// - -double Triangle::pointTriangleDistance(const Point *p, Point *cp) const -{ - return sqrt(TMESH_TO_DOUBLE(pointTriangleSquaredDistance(p))); -} - - -///////////// Distance of point from the triangle ////////////// - -coord Triangle::pointTriangleSquaredDistance(const Point *p, Edge **closest_edge, Vertex **closest_vertex) const -{ - Vertex *va = v1(), *vb = v2(), *vc = v3(); - Point n(((*va)-(*vb))&((*vb)-(*vc))); - if (n.x == 0 && n.y == 0 && n.z == 0) return -1.0; - - coord d1 = ((((*va)-(*vb))&((*vb)-(*p)))*n); - coord d2 = ((((*vb)-(*vc))&((*vc)-(*p)))*n); - coord d3 = ((((*vc)-(*va))&((*va)-(*p)))*n); - - if (d1 > 0 && d2 > 0 && d3 > 0) // Closest point in inner triangle - { - if (closest_edge != NULL) *closest_edge = NULL; - if (closest_vertex != NULL) *closest_vertex = NULL; - return squaredDistanceFromPoint(p); - } - - if (d2 < 0) { va = vb; vb = vc; if (closest_edge != NULL) *closest_edge = e3; } - else if (d3 < 0) { vb = va; va = vc; if (closest_edge != NULL) *closest_edge = e1; } - else if (closest_edge != NULL) *closest_edge = e2; - - Point i(p->projection(va,vb)); - Point p1(i-(*va)); Point p2(i-(*vb)); - - if (p1*p2 < 0) // Closest point on interior of one edge - { - return i.squaredDistance(p); - } - - d1=p1.squaredLength(); d2=p2.squaredLength(); - if (d1 < d2) { if (closest_vertex != NULL) *closest_vertex = va; return p->squaredDistance(va); } - else { if (closest_vertex != NULL) *closest_vertex = vb; return p->squaredDistance(vb); } -} - - -/////////// Projection of point 'p' on the plane of the triangle ///// - -Point Triangle::project(const Point *p) const -{ - Point n = getVector(); - if (n.isNull()) return INFINITE_POINT; - return Point::linePlaneIntersection(*p, (*p) + n, *(v1()), *(v2()), *(v3())); -} - -bool Triangle::isExactlyDegenerate() const -{ +#include "triangle.h" +#include + +namespace T_MESH +{ + +extern "C" double orient2d(double *, double *, double *); + +//////////////////// Constructor ////////////////////// + +//!< AMF_ADD 1.1> +Triangle::Triangle(){ + mask = 0; + info.forget(); +} + +Triangle::Triangle(Edge *a, Edge *b, Edge *c) +{ + e1 = a; + e2 = b; + e3 = c; + mask = 0; + info.forget(); +} + + +//////////////////// Normal vector ////////////////////// + +Point Triangle::getNormal() const +{ + Vertex *va = v1(), *vb = v2(), *vc = v3(); + Point vd = (((*va)-(*vb))&((*vb)-(*vc))); + coord l = vd.length(); + + if (l == 0) return Point(0,0,0); + + return vd/l; +} + + +////// Directional vector //////// + +Point Triangle::getVector() const +{ + Vertex *va = v1(), *vb = v2(), *vc = v3(); + return (((*va) - (*vb))&((*vb) - (*vc))); +} + + +/////////////////// Normal consistence check //////////////////// + +bool Triangle::checkAdjNor(const Triangle *t) const +{ + Edge *e = commonEdge(t); + if (e == NULL) return 1; + + Edge *ea = nextEdge(e); + Edge *eb = t->nextEdge(e); + if (ea->commonVertex(eb) == ea->commonVertex(e)) return 0; + + return 1; +} + + +//////////////////////// Triangle area ///////////////////////// + +double Triangle::area() const +{ + double a = e1->length(), b = e2->length(), c = e3->length(); + if (a==0.0 || b==0.0 || c==0.0) return 0.0; + double p = (a+b+c)/2.0; + p = p*(p-a)*(p-b)*(p-c); if (p<0) return 0.0; + return sqrt(p); +} + + +/////////////////////// Triangle perimeter ///////////////////// + +double Triangle::perimeter() const +{ + return e1->length()+e2->length()+e3->length(); +} + + +///////////// Barycenter /////////////////////// + +Point Triangle::getCenter() const +{ + Point va = *v1(), vb = *v2(), vc = *v3(); + return (va+vb+vc)/3.0; +} + + +///////////////////////// Circlecenter ///////////////////////// + +Point Triangle::getCircleCenter() const +{ + Point va = *v1(), vb = *v2(), vc = *v3(); + Point q1 = vb-va; + Point q2 = vc-va; + Point n = q2&q1; + Point m1 = e2->getMidPoint(); + Point m2 = e1->getMidPoint(); + + return Point(n*va,q1*m1,q2*m2).linearSystem(n,q1,q2); +} + + +/////// Check wether the point is inside the triangle's bounding ball ///// + +bool Triangle::inSphere(const Point *p) const +{ + Point c = getCircleCenter(); + coord rad = c.squaredDistance(e1->v1); + + return (p->squaredDistance(&c) < rad); +} + + +//////////////////// Angle at a vertex ///////////////////// + +double Triangle::getAngle(const Vertex *v) const +{ + Vertex *va = v1(), *vb = v2(), *vc = v3(); + if (v == va) return v->getAngle(vb, vc); + if (v == vb) return v->getAngle(va, vc); + if (v == vc) return v->getAngle(vb, va); + + return -1.0; +} + + +/////////// Angle between the two directional vectors ///////// + +double Triangle::getDAngle(const Triangle *t) const +{ + Point thisNormal = getVector(); + Point otherNormal = t->getVector(); + + if (thisNormal.isNull() || otherNormal.isNull()) return -1.0; + + return thisNormal.getAngle(otherNormal); +} + + +///////////// Distance from the plane of the triangle ////////////// + +double Triangle::distanceFromPoint(const Point *p) const +{ + return sqrt(TMESH_TO_DOUBLE(squaredDistanceFromPoint(p))); +} + +///////////// Squared distance from the plane of the triangle ////////////// + +coord Triangle::squaredDistanceFromPoint(const Point *p) const +{ + Point CA = e1->toVector()&e2->toVector(); + coord CA2 = CA*CA; + + if (CA2 == 0) return -1.0; + coord d = ((CA*(*p))-(CA*(*(e1->v1)))); + + return (d*d)/CA2; +} + + +///////////// Distance of point from the triangle ////////////// + +double Triangle::pointTriangleDistance(const Point *p, Point *cp) const +{ + return sqrt(TMESH_TO_DOUBLE(pointTriangleSquaredDistance(p))); +} + + +///////////// Distance of point from the triangle ////////////// + +coord Triangle::pointTriangleSquaredDistance(const Point *p, Edge **closest_edge, Vertex **closest_vertex) const +{ + Vertex *va = v1(), *vb = v2(), *vc = v3(); + Point n(((*va)-(*vb))&((*vb)-(*vc))); + if (n.x == 0 && n.y == 0 && n.z == 0) return -1.0; + + coord d1 = ((((*va)-(*vb))&((*vb)-(*p)))*n); + coord d2 = ((((*vb)-(*vc))&((*vc)-(*p)))*n); + coord d3 = ((((*vc)-(*va))&((*va)-(*p)))*n); + + if (d1 > 0 && d2 > 0 && d3 > 0) // Closest point in inner triangle + { + if (closest_edge != NULL) *closest_edge = NULL; + if (closest_vertex != NULL) *closest_vertex = NULL; + return squaredDistanceFromPoint(p); + } + + if (d2 < 0) { va = vb; vb = vc; if (closest_edge != NULL) *closest_edge = e3; } + else if (d3 < 0) { vb = va; va = vc; if (closest_edge != NULL) *closest_edge = e1; } + else if (closest_edge != NULL) *closest_edge = e2; + + Point i(p->projection(va,vb)); + Point p1(i-(*va)); Point p2(i-(*vb)); + + if (p1*p2 < 0) // Closest point on interior of one edge + { + return i.squaredDistance(p); + } + + d1=p1.squaredLength(); d2=p2.squaredLength(); + if (d1 < d2) { if (closest_vertex != NULL) *closest_vertex = va; return p->squaredDistance(va); } + else { if (closest_vertex != NULL) *closest_vertex = vb; return p->squaredDistance(vb); } +} + + +/////////// Projection of point 'p' on the plane of the triangle ///// + +Point Triangle::project(const Point *p) const +{ + Point n = getVector(); + if (n.isNull()) return INFINITE_POINT; + return Point::linePlaneIntersection(*p, (*p) + n, *(v1()), *(v2()), *(v3())); +} + +bool Triangle::isExactlyDegenerate() const +{ return (!v1()->exactMisalignment((v2()), (v3()))); -} - -//// get longest edge ///// - +} + +//// get longest edge ///// + Edge *Triangle::getLongestEdge() const { coord l1 = e1->squaredLength(); @@ -264,8 +264,8 @@ Edge *Triangle::getLongestEdge() const if (l2>=l1 && l2>=l3) return e2; return e3; } - -Edge *Triangle::getCapEdge() const + +Edge *Triangle::getCapEdge() const { Edge *e; e = e1; if (Point::pointInInnerSegment(oppositeVertex(e), e->v1, e->v2)) return e; @@ -273,138 +273,138 @@ Edge *Triangle::getCapEdge() const e = e3; if (Point::pointInInnerSegment(oppositeVertex(e), e->v1, e->v2)) return e; return NULL; } - -///////////// Overlap check //////////////////// - -bool Triangle::overlaps() const -{ - return (e1->overlaps() || e2->overlaps() || e3->overlaps()); -} - -Vertex *Triangle::commonVertex(const Triangle *t2) const -{ - if (hasVertex(t2->v1())) return t2->v1(); - if (hasVertex(t2->v2())) return t2->v2(); - if (hasVertex(t2->v3())) return t2->v3(); - return NULL; -} - - -/// Debug - -void Triangle::printTriangle(FILE *fp) const -{ - v1()->printPoint(fp); - v2()->printPoint(fp); - v3()->printPoint(fp); -} - - -// This can be made more efficient, I guess... - -bool Triangle::intersects(const Triangle *t2, bool justproper) const -{ - Vertex *v11, *v12, *v13, *v21, *v22, *v23; - - if (justproper) - { - // This works for non-degenerate triangles. Not sure it will work for degeneracies too. - v11 = v1(); v12 = v2(); v13 = v3(); - v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3(); - Vertex *eq1 = ((*v11) == (*v21)) ? (v21) : (((*v11) == (*v22)) ? (v22) : (((*v11) == (*v23)) ? (v23) : (NULL))); - Vertex *eq2 = ((*v12) == (*v21)) ? (v21) : (((*v12) == (*v22)) ? (v22) : (((*v12) == (*v23)) ? (v23) : (NULL))); - Vertex *eq3 = ((*v13) == (*v21)) ? (v21) : (((*v13) == (*v22)) ? (v22) : (((*v13) == (*v23)) ? (v23) : (NULL))); - if (eq1 && eq2 && eq3) return false; // Triangles coincide - Edge *ce1 = NULL, *ce2 = NULL; - if (eq1 && eq2) { ce1 = e2; ce2 = (t2->e1->hasVertices(eq1, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq1, eq2)) ? (t2->e2) : (t2->e3)); } - if (eq2 && eq3) { ce1 = e3; ce2 = (t2->e1->hasVertices(eq3, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq2)) ? (t2->e2) : (t2->e3)); } - if (eq3 && eq1) { ce1 = e1; ce2 = (t2->e1->hasVertices(eq3, eq1)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq1)) ? (t2->e2) : (t2->e3)); } - if (ce1) - { - Vertex *ov = t2->oppositeVertex(ce2); - return (ov->exactOrientation(v11, v12, v13) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce1), ce1->v1, ce1->v2)); - } - Vertex *cv1 = NULL, *cv2 = NULL; - if (eq1) { cv1 = v11; cv2 = eq1; } - if (eq2) { cv1 = v12; cv2 = eq2; } - if (eq3) { cv1 = v13; cv2 = eq3; } - if (cv1) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle - { - Edge *ee1 = oppositeEdge(cv1), *ee2 = t2->oppositeEdge(cv2); - return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) || - Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13)); - } - } - else - { - Edge *ce = commonEdge(t2); - if (ce) // If they share an edge, intersection occurs only if t1 and t2 overlap - { - Vertex *ov = t2->oppositeVertex(ce); - return (ov->exactOrientation(v1(), v2(), v3()) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce), ce->v1, ce->v2)); - } - - Vertex *cv = commonVertex(t2); - v11 = v1(); v12 = v2(); v13 = v3(); - v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3(); - if (cv) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle - { - Edge *ee1 = oppositeEdge(cv), *ee2 = t2->oppositeEdge(cv); - return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) || - Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13)); - } - } - - // Fast reject by bounding box - coord mx = MIN(v11->x, MIN(v13->x, v12->x)); - if (v21->x < mx && v22->x < mx && v23->x < mx) return false; - mx = MAX(v11->x, MAX(v13->x, v12->x)); - if (v21->x > mx && v22->x > mx && v23->x > mx) return false; - mx = MIN(v11->y, MIN(v13->y, v12->y)); - if (v21->y < mx && v22->y < mx && v23->y < mx) return false; - mx = MAX(v11->y, MAX(v13->y, v12->y)); - if (v21->y > mx && v22->y > mx && v23->y > mx) return false; - mx = MIN(v11->z, MIN(v13->z, v12->z)); - if (v21->z < mx && v22->z < mx && v23->z < mx) return false; - mx = MAX(v11->z, MAX(v13->z, v12->z)); - if (v21->z > mx && v22->z > mx && v23->z > mx) return false; - - // Calculate relative orientations - coord o11 = v11->exactOrientation(v21, v22, v23); - coord o12 = v12->exactOrientation(v21, v22, v23); - coord o13 = v13->exactOrientation(v21, v22, v23); - if ((o11>0 && o12>0 && o13>0) || (o11<0 && o12<0 && o13<0)) return false; // t1 above/below t2 - coord o21 = v21->exactOrientation(v11, v12, v13); - coord o22 = v22->exactOrientation(v11, v12, v13); - coord o23 = v23->exactOrientation(v11, v12, v13); - if ((o21>0 && o22>0 && o23>0) || (o21<0 && o22<0 && o23<0)) return false; // t2 above/below t1 - - if (o11 == 0 && o12 == 0 && o13 == 0) // t1 and t2 are coplanar - { - if (Point::innerSegmentsCross(v11, v12, v21, v22)) return true; - if (Point::innerSegmentsCross(v11, v12, v22, v23)) return true; - if (Point::innerSegmentsCross(v11, v12, v23, v21)) return true; - if (Point::innerSegmentsCross(v12, v13, v21, v22)) return true; - if (Point::innerSegmentsCross(v12, v13, v22, v23)) return true; - if (Point::innerSegmentsCross(v12, v13, v23, v21)) return true; - if (Point::innerSegmentsCross(v13, v11, v21, v22)) return true; - if (Point::innerSegmentsCross(v13, v11, v22, v23)) return true; - if (Point::innerSegmentsCross(v13, v11, v23, v21)) return true; - return ( - Point::pointInTriangle(v11, v21, v22, v23) || - Point::pointInTriangle(v12, v21, v22, v23) || - Point::pointInTriangle(v13, v21, v22, v23) || - Point::pointInTriangle(v21, v11, v12, v13) || - Point::pointInTriangle(v22, v11, v12, v13) || - Point::pointInTriangle(v23, v11, v12, v13)); - } - else return ( - Point::segmentIntersectsTriangle(v11, v12, v21, v22, v23, o11, o12) || - Point::segmentIntersectsTriangle(v12, v13, v21, v22, v23, o12, o13) || - Point::segmentIntersectsTriangle(v13, v11, v21, v22, v23, o13, o11) || - Point::segmentIntersectsTriangle(v21, v22, v11, v12, v13, o21, o22) || - Point::segmentIntersectsTriangle(v22, v23, v11, v12, v13, o22, o23) || - Point::segmentIntersectsTriangle(v23, v21, v11, v12, v13, o23, o21)); -} - + +///////////// Overlap check //////////////////// + +bool Triangle::overlaps() const +{ + return (e1->overlaps() || e2->overlaps() || e3->overlaps()); +} + +Vertex *Triangle::commonVertex(const Triangle *t2) const +{ + if (hasVertex(t2->v1())) return t2->v1(); + if (hasVertex(t2->v2())) return t2->v2(); + if (hasVertex(t2->v3())) return t2->v3(); + return NULL; +} + + +/// Debug + +void Triangle::printTriangle(FILE *fp) const +{ + v1()->printPoint(fp); + v2()->printPoint(fp); + v3()->printPoint(fp); +} + + +// This can be made more efficient, I guess... + +bool Triangle::intersects(const Triangle *t2, bool justproper) const +{ + Vertex *v11, *v12, *v13, *v21, *v22, *v23; + + if (justproper) + { + // This works for non-degenerate triangles. Not sure it will work for degeneracies too. + v11 = v1(); v12 = v2(); v13 = v3(); + v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3(); + Vertex *eq1 = ((*v11) == (*v21)) ? (v21) : (((*v11) == (*v22)) ? (v22) : (((*v11) == (*v23)) ? (v23) : (NULL))); + Vertex *eq2 = ((*v12) == (*v21)) ? (v21) : (((*v12) == (*v22)) ? (v22) : (((*v12) == (*v23)) ? (v23) : (NULL))); + Vertex *eq3 = ((*v13) == (*v21)) ? (v21) : (((*v13) == (*v22)) ? (v22) : (((*v13) == (*v23)) ? (v23) : (NULL))); + if (eq1 && eq2 && eq3) return false; // Triangles coincide + Edge *ce1 = NULL, *ce2 = NULL; + if (eq1 && eq2) { ce1 = e2; ce2 = (t2->e1->hasVertices(eq1, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq1, eq2)) ? (t2->e2) : (t2->e3)); } + if (eq2 && eq3) { ce1 = e3; ce2 = (t2->e1->hasVertices(eq3, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq2)) ? (t2->e2) : (t2->e3)); } + if (eq3 && eq1) { ce1 = e1; ce2 = (t2->e1->hasVertices(eq3, eq1)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq1)) ? (t2->e2) : (t2->e3)); } + if (ce1) + { + Vertex *ov = t2->oppositeVertex(ce2); + return (ov->exactOrientation(v11, v12, v13) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce1), ce1->v1, ce1->v2)); + } + Vertex *cv1 = NULL, *cv2 = NULL; + if (eq1) { cv1 = v11; cv2 = eq1; } + if (eq2) { cv1 = v12; cv2 = eq2; } + if (eq3) { cv1 = v13; cv2 = eq3; } + if (cv1) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle + { + Edge *ee1 = oppositeEdge(cv1), *ee2 = t2->oppositeEdge(cv2); + return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) || + Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13)); + } + } + else + { + Edge *ce = commonEdge(t2); + if (ce) // If they share an edge, intersection occurs only if t1 and t2 overlap + { + Vertex *ov = t2->oppositeVertex(ce); + return (ov->exactOrientation(v1(), v2(), v3()) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce), ce->v1, ce->v2)); + } + + Vertex *cv = commonVertex(t2); + v11 = v1(); v12 = v2(); v13 = v3(); + v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3(); + if (cv) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle + { + Edge *ee1 = oppositeEdge(cv), *ee2 = t2->oppositeEdge(cv); + return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) || + Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13)); + } + } + + // Fast reject by bounding box + coord mx = MIN(v11->x, MIN(v13->x, v12->x)); + if (v21->x < mx && v22->x < mx && v23->x < mx) return false; + mx = MAX(v11->x, MAX(v13->x, v12->x)); + if (v21->x > mx && v22->x > mx && v23->x > mx) return false; + mx = MIN(v11->y, MIN(v13->y, v12->y)); + if (v21->y < mx && v22->y < mx && v23->y < mx) return false; + mx = MAX(v11->y, MAX(v13->y, v12->y)); + if (v21->y > mx && v22->y > mx && v23->y > mx) return false; + mx = MIN(v11->z, MIN(v13->z, v12->z)); + if (v21->z < mx && v22->z < mx && v23->z < mx) return false; + mx = MAX(v11->z, MAX(v13->z, v12->z)); + if (v21->z > mx && v22->z > mx && v23->z > mx) return false; + + // Calculate relative orientations + coord o11 = v11->exactOrientation(v21, v22, v23); + coord o12 = v12->exactOrientation(v21, v22, v23); + coord o13 = v13->exactOrientation(v21, v22, v23); + if ((o11>0 && o12>0 && o13>0) || (o11<0 && o12<0 && o13<0)) return false; // t1 above/below t2 + coord o21 = v21->exactOrientation(v11, v12, v13); + coord o22 = v22->exactOrientation(v11, v12, v13); + coord o23 = v23->exactOrientation(v11, v12, v13); + if ((o21>0 && o22>0 && o23>0) || (o21<0 && o22<0 && o23<0)) return false; // t2 above/below t1 + + if (o11 == 0 && o12 == 0 && o13 == 0) // t1 and t2 are coplanar + { + if (Point::innerSegmentsCross(v11, v12, v21, v22)) return true; + if (Point::innerSegmentsCross(v11, v12, v22, v23)) return true; + if (Point::innerSegmentsCross(v11, v12, v23, v21)) return true; + if (Point::innerSegmentsCross(v12, v13, v21, v22)) return true; + if (Point::innerSegmentsCross(v12, v13, v22, v23)) return true; + if (Point::innerSegmentsCross(v12, v13, v23, v21)) return true; + if (Point::innerSegmentsCross(v13, v11, v21, v22)) return true; + if (Point::innerSegmentsCross(v13, v11, v22, v23)) return true; + if (Point::innerSegmentsCross(v13, v11, v23, v21)) return true; + return ( + Point::pointInTriangle(v11, v21, v22, v23) || + Point::pointInTriangle(v12, v21, v22, v23) || + Point::pointInTriangle(v13, v21, v22, v23) || + Point::pointInTriangle(v21, v11, v12, v13) || + Point::pointInTriangle(v22, v11, v12, v13) || + Point::pointInTriangle(v23, v11, v12, v13)); + } + else return ( + Point::segmentIntersectsTriangle(v11, v12, v21, v22, v23, o11, o12) || + Point::segmentIntersectsTriangle(v12, v13, v21, v22, v23, o12, o13) || + Point::segmentIntersectsTriangle(v13, v11, v21, v22, v23, o13, o11) || + Point::segmentIntersectsTriangle(v21, v22, v11, v12, v13, o21, o22) || + Point::segmentIntersectsTriangle(v22, v23, v11, v12, v13, o22, o23) || + Point::segmentIntersectsTriangle(v23, v21, v11, v12, v13, o23, o21)); +} + } //namespace T_MESH diff --git a/src/slic3r/Utils/FixModelByMeshFix.cpp b/src/slic3r/Utils/FixModelByMeshFix.cpp index 150b7c1031..3758f2ce72 100644 --- a/src/slic3r/Utils/FixModelByMeshFix.cpp +++ b/src/slic3r/Utils/FixModelByMeshFix.cpp @@ -50,8 +50,6 @@ namespace detail { using namespace T_MESH; -static int ensure_tmesh_initialization = (TMesh::init(), 0); - double closestPair(List *bl1, List *bl2, Vertex **closest_on_bl1, Vertex **closest_on_bl2) { Node *n, *m; @@ -76,30 +74,29 @@ bool joinClosestComponents(Basic_TMesh *tin) Triangle *t, *s; Node *n; List triList, boundary_loops, *one_loop; - List **bloops_array; + Data *bloops_array; int i, j, numloops; // Mark triangles with connected component's unique ID i = 0; - FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL; - FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info == NULL) + FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = Data(); + FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info == Data()) { i++; triList.appendHead(t); - t->info = new intWrapper(i); while (triList.numels()) { t = (Triangle *)triList.popHead(); - if ((s = t->t1()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = new intWrapper(i);} - if ((s = t->t2()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = new intWrapper(i);} - if ((s = t->t3()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = new intWrapper(i);} + if ((s = t->t1()) != NULL && s->info.empty()) {triList.appendHead(s); s->info = i;} + if ((s = t->t2()) != NULL && s->info.empty()) {triList.appendHead(s); s->info = i;} + if ((s = t->t3()) != NULL && s->info.empty()) {triList.appendHead(s); s->info = i;} } } if (i<2) { - FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL; + FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = Data(); // JMesh::info("Mesh is a single component. Nothing done."); return false; } @@ -122,7 +119,7 @@ bool joinClosestComponents(Basic_TMesh *tin) } FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_VISIT2(v); - bloops_array = (List **)boundary_loops.toArray(); + bloops_array = boundary_loops.toArray(); numloops = boundary_loops.numels(); double adist, @@ -131,7 +128,7 @@ bool joinClosestComponents(Basic_TMesh *tin) gv = NULL; for (i = 0; i < numloops; i++) for (j = 0; j < numloops; j++) - if (((Vertex*) bloops_array[i]->head()->data)->info != ((Vertex*) bloops_array[j]->head()->data)->info) + if (((Vertex*)((List*)(bloops_array[i]))->head()->data)->info != ((Vertex*) ((List*)(bloops_array[j]))->head()->data)->info) { adist = closestPair(bloops_array[i], bloops_array[j], &v, &w); if (adist < mindist) { @@ -145,12 +142,12 @@ bool joinClosestComponents(Basic_TMesh *tin) tin->joinBoundaryLoops(gv, gw, 1, 0); FOREACHVTTRIANGLE((&(tin->T)), t, n) - t->info = NULL; + t->info.clear(); FOREACHVVVERTEX((&(tin->V)), v, n) - v->info = NULL; + v->info.clear(); - free(bloops_array); - while ((one_loop = (List*) boundary_loops.popHead()) != NULL) + delete [] bloops_array; + while ((one_loop = (List*) boundary_loops.popHead()) != Data()) delete one_loop; return (gv != NULL); @@ -159,7 +156,6 @@ bool joinClosestComponents(Basic_TMesh *tin) class Basic_TMesh_Adapter: public Basic_TMesh { public: void load_indexed_triangle_set(const indexed_triangle_set &its) { - for (const auto &vertex : its.vertices) { this->V.appendTail(this->newVertex(vertex.x(), vertex.y(), vertex.z())); } @@ -241,6 +237,7 @@ private: free(tmp); } fixConnectivity(); +// rebuildConnectivity(true); this->d_boundaries = this->d_handles = this->d_shells = 1; } }; @@ -279,6 +276,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD auto worker_thread = boost::thread( [&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() { try { + T_MESH::TMesh::init(); // TODO call only once (but it seems that multiple calls do not break it) std::vector meshes_repaired; meshes_repaired.reserve(volumes.size()); for (ModelVolume *mv : volumes) { @@ -296,7 +294,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD on_progress(L("Join closest components"), unsigned(progress_part_base + 0.1 * percent_per_part)); if (canceled) throw RepairCanceledException(); - joinClosestComponents(&tin); + while (joinClosestComponents(&tin)) (tin.shells()); tin.deselectTriangles(); tin.boundaries(); // Keep only the largest component (i.e. with most triangles)