refactoring of void*, crash fix

This commit is contained in:
PavelMikus 2022-06-14 11:41:17 +02:00
parent 9fccbd00d0
commit 1455d0e1b3
29 changed files with 3519 additions and 3629 deletions

View File

@ -31,7 +31,9 @@
#ifndef _BASICS_H
#define _BASICS_H
#include <functional>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <limits.h>
@ -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<typename T, typename Child>
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<void(int64_t)> 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<double, doubleWrapper> {
public:
doubleWrapper(double val = 0) {
this->value = val;
Data() {
delete_object_func = [](int64_t){};
}
operator double &() {
Data(void* ptr) = delete;
template<typename S>
Data(S* ptr) {
delete_object_func = [](int64_t p){
delete reinterpret_cast<S*>(p);
};
value = reinterpret_cast<int64_t>(ptr);
}
operator void*() = delete;
template<typename S>
operator S*() const {
return reinterpret_cast<S*>(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<typename S>
bool operator!=(const S* ptr) const {
return value != reinterpret_cast<int64_t>(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<intWrapper*>(d)->operator int();
}
} //namespace T_MESH

View File

@ -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())

View File

@ -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:

View File

@ -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 a<b, >0 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
};

View File

@ -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

View File

@ -28,156 +28,155 @@
* *
****************************************************************************/
#ifndef _JLIST_H
#define _JLIST_H
#include <stdio.h>
#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 <stdio.h>
#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

View File

@ -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 <a, *this, b> 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 <a, *this, b> 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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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();

View File

@ -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);

View File

@ -33,60 +33,60 @@
#include <stdlib.h>
#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 (!(Mx<mp.x || mx>Mp.x || My<mp.y || my>Mp.y || Mz<mp.z || mz>Mp.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 (!(Mx<mp.x || mx>Mp.x || My<mp.y || my>Mp.y || Mz<mp.z || mz>Mp.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

View File

@ -28,12 +28,12 @@
* *
****************************************************************************/
#include "tin.h"
#include <stdlib.h>
namespace T_MESH
{
#include "tin.h"
#include <stdlib.h>
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((&reg), t, n) MARK_VISIT(t);
}
else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t);
printf("%d\n",reg.numels());
FOREACHVTTRIANGLE((&reg), 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((&reg), 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 (c1<c2)
{
t = EulerEdgeTriangle(e, gve); MARK_VISIT(t);
pl1 -= gve->length();
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((&reg), t, n) MARK_VISIT(t);
}
else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t);
printf("%d\n",reg.numels());
FOREACHVTTRIANGLE((&reg), 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((&reg), 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 (c1<c2)
{
t = EulerEdgeTriangle(e, gve); MARK_VISIT(t);
pl1 -= gve->length();
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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -34,8 +34,7 @@
#include <vector>
#include <algorithm>
#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);

View File

@ -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; i<n; i++) appendTail(d[i]);
@ -73,21 +73,21 @@ List::~List()
////////////////// Append an element //////////////////
void List::appendHead(const Data *d)
void List::appendHead(const Data& d)
{
l_head = new Node(NULL, d, l_head);
if (l_tail == NULL) l_tail = l_head;
l_numels++;
}
void List::appendTail(const Data *d)
void List::appendTail(const Data& d)
{
l_tail = new Node(l_tail, d, NULL);
if (l_head == NULL) l_head = l_tail;
l_numels++;
}
void List::insertAfter(Node *b, const Data *d)
void List::insertAfter(Node *b, const Data& d)
{
Node *nn = new Node(b, d, b->next());
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; i<l_numels; i++, n=n->n_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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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; 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) { mindist = adist; gv = v; gw = w; }
@ -92,10 +92,10 @@ bool joinClosestComponents(Basic_TMesh *tin)
if (gv != NULL) tin->joinBoundaryLoops(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);

View File

@ -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 (la<lb) return -1;
if (la>lb) 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 (va2<va1) { tmp = va1; va1 = va2; va2 = tmp; }
if (vb2<vb1) { tmp = vb1; vb1 = vb2; vb2 = tmp; }
if (va1<vb1) return -1;
if (va1>vb1) return 1;
if (va2<vb2) return -1;
if (va2>vb2) 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 (la<lb) return -1;
if (la>lb) 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 (va2<va1) { tmp = va1; va1 = va2; va2 = tmp; }
if (vb2<vb1) { tmp = vb1; vb1 = vb2; vb2 = tmp; }
if (va1<vb1) return -1;
if (va1>vb1) return 1;
if (va2<vb2) return -1;
if (va2>vb2) 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

View File

@ -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;
}
}

View File

@ -32,16 +32,16 @@
#include <stdlib.h>
#include <string.h>
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;
}

View File

@ -28,233 +28,233 @@
* *
****************************************************************************/
#include "triangle.h"
#include <stdlib.h>
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 <stdlib.h>
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

View File

@ -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<TriangleMesh> 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)