mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 01:25:59 +08:00
refactoring of void*, crash fix
This commit is contained in:
parent
9fccbd00d0
commit
1455d0e1b3
@ -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
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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((®), t, n) MARK_VISIT(t);
|
||||
}
|
||||
else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t);
|
||||
|
||||
printf("%d\n",reg.numels());
|
||||
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
e = t->e1; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e2; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e3; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
}
|
||||
|
||||
while (all_edges.numels())
|
||||
{
|
||||
e = (Edge *)all_edges.popHead();
|
||||
if (IS_BIT(e, 5)) { boundary_edges.appendHead(e); UNMARK_BIT(e, 5); }
|
||||
else { interior_edges.appendHead(e); MARK_BIT(e, 5); }
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&boundary_edges), e, n)
|
||||
{
|
||||
v = e->v1; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
v = e->v2; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
}
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) UNMARK_BIT(v, 5);
|
||||
|
||||
// Due to the above definitions, interior edges are BIT
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n)
|
||||
{
|
||||
ve = v->VE();
|
||||
sigma=0; nee=0; FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e, 5)) {nee++; sigma += e->length();}
|
||||
sigma /= double(nee); v->info = new doubleWrapper(sigma);
|
||||
delete(ve);
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) UNMARK_BIT(e, 5);
|
||||
FOREACHVEEDGE((&boundary_edges), e, n) MARK_BIT(e, 6);
|
||||
|
||||
do
|
||||
{
|
||||
pnnt=nnt;
|
||||
nnt=0;
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
vc = t->getCenter();
|
||||
sv1 = (*(doubleWrapper *)t->v1()->info);
|
||||
sv2 = (*(doubleWrapper *)t->v2()->info);
|
||||
sv3 = (*(doubleWrapper *)t->v3()->info);
|
||||
sigma = (sv1+sv2+sv3)/3.0;
|
||||
dv1 = alpha*(t->v1()->distance(&vc));
|
||||
dv2 = alpha*(t->v2()->distance(&vc));
|
||||
dv3 = alpha*(t->v3()->distance(&vc));
|
||||
if (dv1>sigma && dv1>sv1 && dv2>sigma && dv2>sv2 && dv3>sigma && dv3>sv3)
|
||||
{
|
||||
ntb = T.numels();
|
||||
v = splitTriangle(t,&vc,1);
|
||||
nnt += (T.numels()-ntb);
|
||||
if (T.numels() == ntb+2)
|
||||
{
|
||||
v->info = new doubleWrapper(sigma);
|
||||
interior_vertices.appendHead(v);
|
||||
interior_edges.appendHead(v->e0);
|
||||
interior_edges.appendHead(v->e0->leftTriangle(v)->prevEdge(v->e0));
|
||||
interior_edges.appendHead(v->e0->rightTriangle(v)->nextEdge(v->e0));
|
||||
t1 = ((Triangle *)T.head()->data);
|
||||
t2 = ((Triangle *)T.head()->next()->data);
|
||||
t1->mask = t2->mask = t->mask;
|
||||
reg.appendHead(t1); reg.appendHead(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) {MARK_BIT(e, 5); toswap.appendHead(e);}
|
||||
totits=0; swaps=1;
|
||||
while (swaps && totits++ < 10)
|
||||
{
|
||||
swaps = 0;
|
||||
while ((e=(Edge *)toswap.popHead())!=NULL)
|
||||
{
|
||||
UNMARK_BIT(e, 5);
|
||||
l = e->squaredLength();
|
||||
if (e->swap())
|
||||
{
|
||||
if (e->squaredLength() >= l*0.999999) e->swap(1);
|
||||
else
|
||||
{
|
||||
swaps++;
|
||||
toswap.appendTail(e);
|
||||
f = e->t1->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t1->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pnnt==nnt) gits++;
|
||||
} while (nnt && gits<10);
|
||||
|
||||
//FOREACHVEEDGE((&boundary_edges), e, n) UNMARK_BIT(e, 6);
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) { delete((Data *)v->info); v->info = NULL; MARK_BIT(v, 5);}
|
||||
FOREACHVVVERTEX((&interior_vertices), v, n) { delete((Data *)v->info); v->info = NULL; MARK_BIT(v, 6);}
|
||||
|
||||
if (gits>=10) {TMesh::warning("Fill holes: Refinement stage failed to converge. Breaking.\n"); return 1;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Joins the two boundary vertices gv and gw through an edge. A pair of triangles is
|
||||
// added to properly change the topology of the mesh.
|
||||
// On success, the return value is the new edge connecting the two vertices.
|
||||
// NULL is returned on failure.
|
||||
// Failure occurs if gv and gw are not both on boundary.
|
||||
// If 'justconnect' is false, the remaining hole is filled with new triangles, unless
|
||||
// gv and gw are contiguous on the boundary loop (failure).
|
||||
// If 'justconnect' is true, gv and gw must not belong to the same boundary loop (failure).
|
||||
// If 'refine', the patching triangles are refined to reproduce neighboring density.
|
||||
|
||||
Edge *Basic_TMesh::joinBoundaryLoops(Vertex *gv, Vertex *gw, bool justconnect, bool refine)
|
||||
{
|
||||
Vertex *v, *gvn, *gwn;
|
||||
Edge *e, *gve, *gwe;
|
||||
Triangle *t;
|
||||
Node *n;
|
||||
double tl1 = 0.0, tl2 = 0.0, pl1, pl2;
|
||||
|
||||
if (gv == NULL || gw == NULL || !gv->isOnBoundary() || !gw->isOnBoundary()) return NULL;
|
||||
|
||||
FOREACHVERTEX(v, n) UNMARK_VISIT(v);
|
||||
deselectTriangles();
|
||||
|
||||
v = gv;
|
||||
if (!justconnect)
|
||||
{
|
||||
do { v = v->nextOnBoundary(); if (v == gw) return NULL; } while (v != gv);
|
||||
} else
|
||||
{
|
||||
gvn = gv->nextOnBoundary(); gwn = gv->prevOnBoundary();
|
||||
if (gw == gvn || gw == gwn) return NULL;
|
||||
if (gw == gvn->nextOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gvn->prevBoundaryEdge(), gvn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gvn);
|
||||
}
|
||||
if (gw == gwn->prevOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gwn->prevBoundaryEdge(), gwn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gwn);
|
||||
}
|
||||
}
|
||||
|
||||
gve = gv->prevBoundaryEdge();
|
||||
gvn = gve->oppositeVertex(gv);
|
||||
gwe = gw->nextBoundaryEdge();
|
||||
gwn = gwe->oppositeVertex(gw);
|
||||
|
||||
Edge *je = CreateEdge(gv, gw);
|
||||
Edge *je1 = CreateEdge(gv, gwn);
|
||||
Edge *je2 = CreateEdge(gwn, gvn);
|
||||
|
||||
t = CreateTriangle(je, gwe, je1); MARK_VISIT(t);
|
||||
t = CreateTriangle(je1, je2, gve); MARK_VISIT(t);
|
||||
|
||||
if (justconnect) return je;
|
||||
|
||||
v = gv; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl1 += e->length(); } while (v != gv);
|
||||
v = gw; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl2 += e->length(); } while (v != gw);
|
||||
pl1 = tl1; pl2 = tl2;
|
||||
|
||||
double c1, c2;
|
||||
|
||||
e = je;
|
||||
while (e->isOnBoundary())
|
||||
{
|
||||
gv = (e->t2 != NULL) ? (e->v2) : (e->v1); gve = gv->nextBoundaryEdge();
|
||||
gw = (e->t1 != NULL) ? (e->v2) : (e->v1); gwe = gw->prevBoundaryEdge();
|
||||
c1 = fabs((pl1 - gve->length())*tl2 - pl2*tl1);
|
||||
c2 = fabs((pl2 - gwe->length())*tl1 - pl1*tl2);
|
||||
if (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((®), t, n) MARK_VISIT(t);
|
||||
}
|
||||
else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t);
|
||||
|
||||
printf("%d\n",reg.numels());
|
||||
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
e = t->e1; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e2; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e3; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
}
|
||||
|
||||
while (all_edges.numels())
|
||||
{
|
||||
e = (Edge *)all_edges.popHead();
|
||||
if (IS_BIT(e, 5)) { boundary_edges.appendHead(e); UNMARK_BIT(e, 5); }
|
||||
else { interior_edges.appendHead(e); MARK_BIT(e, 5); }
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&boundary_edges), e, n)
|
||||
{
|
||||
v = e->v1; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
v = e->v2; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
}
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) UNMARK_BIT(v, 5);
|
||||
|
||||
// Due to the above definitions, interior edges are BIT
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n)
|
||||
{
|
||||
ve = v->VE();
|
||||
sigma=0; nee=0; FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e, 5)) {nee++; sigma += e->length();}
|
||||
sigma /= nee; v->info = new coord(sigma);
|
||||
delete(ve);
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) UNMARK_BIT(e, 5);
|
||||
FOREACHVEEDGE((&boundary_edges), e, n) MARK_BIT(e, 6);
|
||||
|
||||
do
|
||||
{
|
||||
pnnt=nnt;
|
||||
nnt=0;
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
vc = t->getCenter();
|
||||
sv1 = (*(coord *)t->v1()->info);
|
||||
sv2 = (*(coord *)t->v2()->info);
|
||||
sv3 = (*(coord *)t->v3()->info);
|
||||
sigma = (sv1+sv2+sv3)/3.0;
|
||||
dv1 = alpha*(t->v1()->distance(&vc));
|
||||
dv2 = alpha*(t->v2()->distance(&vc));
|
||||
dv3 = alpha*(t->v3()->distance(&vc));
|
||||
if (dv1>sigma && dv1>sv1 && dv2>sigma && dv2>sv2 && dv3>sigma && dv3>sv3)
|
||||
{
|
||||
ntb = T.numels();
|
||||
v = splitTriangle(t,&vc,1);
|
||||
nnt += (T.numels()-ntb);
|
||||
if (T.numels() == ntb+2)
|
||||
{
|
||||
v->info = new coord(sigma);
|
||||
interior_vertices.appendHead(v);
|
||||
interior_edges.appendHead(v->e0);
|
||||
interior_edges.appendHead(v->e0->leftTriangle(v)->prevEdge(v->e0));
|
||||
interior_edges.appendHead(v->e0->rightTriangle(v)->nextEdge(v->e0));
|
||||
t1 = ((Triangle *)T.head()->data);
|
||||
t2 = ((Triangle *)T.head()->next()->data);
|
||||
t1->mask = t2->mask = t->mask;
|
||||
reg.appendHead(t1); reg.appendHead(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) {MARK_BIT(e, 5); toswap.appendHead(e);}
|
||||
totits=0; swaps=1;
|
||||
while (swaps && totits++ < 10)
|
||||
{
|
||||
swaps = 0;
|
||||
while ((e=(Edge *)toswap.popHead())!=NULL)
|
||||
{
|
||||
UNMARK_BIT(e, 5);
|
||||
l = e->squaredLength();
|
||||
if (e->swap())
|
||||
{
|
||||
if (e->squaredLength() >= l*0.999999) e->swap(1);
|
||||
else
|
||||
{
|
||||
swaps++;
|
||||
toswap.appendTail(e);
|
||||
f = e->t1->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t1->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pnnt==nnt) gits++;
|
||||
} while (nnt && gits<10);
|
||||
|
||||
//FOREACHVEEDGE((&boundary_edges), e, n) UNMARK_BIT(e, 6);
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) { v->info.clear(); MARK_BIT(v, 5);}
|
||||
FOREACHVVVERTEX((&interior_vertices), v, n) { v->info.clear(); MARK_BIT(v, 6);}
|
||||
|
||||
if (gits>=10) {TMesh::warning("Fill holes: Refinement stage failed to converge. Breaking.\n"); return 1;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Joins the two boundary vertices gv and gw through an edge. A pair of triangles is
|
||||
// added to properly change the topology of the mesh.
|
||||
// On success, the return value is the new edge connecting the two vertices.
|
||||
// NULL is returned on failure.
|
||||
// Failure occurs if gv and gw are not both on boundary.
|
||||
// If 'justconnect' is false, the remaining hole is filled with new triangles, unless
|
||||
// gv and gw are contiguous on the boundary loop (failure).
|
||||
// If 'justconnect' is true, gv and gw must not belong to the same boundary loop (failure).
|
||||
// If 'refine', the patching triangles are refined to reproduce neighboring density.
|
||||
|
||||
Edge *Basic_TMesh::joinBoundaryLoops(Vertex *gv, Vertex *gw, bool justconnect, bool refine)
|
||||
{
|
||||
Vertex *v, *gvn, *gwn;
|
||||
Edge *e, *gve, *gwe;
|
||||
Triangle *t;
|
||||
Node *n;
|
||||
double tl1 = 0.0, tl2 = 0.0, pl1, pl2;
|
||||
|
||||
if (gv == NULL || gw == NULL || !gv->isOnBoundary() || !gw->isOnBoundary()) return NULL;
|
||||
|
||||
FOREACHVERTEX(v, n) UNMARK_VISIT(v);
|
||||
deselectTriangles();
|
||||
|
||||
v = gv;
|
||||
if (!justconnect)
|
||||
{
|
||||
do { v = v->nextOnBoundary(); if (v == gw) return NULL; } while (v != gv);
|
||||
} else
|
||||
{
|
||||
gvn = gv->nextOnBoundary(); gwn = gv->prevOnBoundary();
|
||||
if (gw == gvn || gw == gwn) return NULL;
|
||||
if (gw == gvn->nextOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gvn->prevBoundaryEdge(), gvn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gvn);
|
||||
}
|
||||
if (gw == gwn->prevOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gwn->prevBoundaryEdge(), gwn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gwn);
|
||||
}
|
||||
}
|
||||
|
||||
gve = gv->prevBoundaryEdge();
|
||||
gvn = gve->oppositeVertex(gv);
|
||||
gwe = gw->nextBoundaryEdge();
|
||||
gwn = gwe->oppositeVertex(gw);
|
||||
|
||||
Edge *je = CreateEdge(gv, gw);
|
||||
Edge *je1 = CreateEdge(gv, gwn);
|
||||
Edge *je2 = CreateEdge(gwn, gvn);
|
||||
|
||||
t = CreateTriangle(je, gwe, je1); MARK_VISIT(t);
|
||||
t = CreateTriangle(je1, je2, gve); MARK_VISIT(t);
|
||||
|
||||
if (justconnect) return je;
|
||||
|
||||
v = gv; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl1 += e->length(); } while (v != gv);
|
||||
v = gw; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl2 += e->length(); } while (v != gw);
|
||||
pl1 = tl1; pl2 = tl2;
|
||||
|
||||
double c1, c2;
|
||||
|
||||
e = je;
|
||||
while (e->isOnBoundary())
|
||||
{
|
||||
gv = (e->t2 != NULL) ? (e->v2) : (e->v1); gve = gv->nextBoundaryEdge();
|
||||
gw = (e->t1 != NULL) ? (e->v2) : (e->v1); gwe = gw->prevBoundaryEdge();
|
||||
c1 = fabs((pl1 - gve->length())*tl2 - pl2*tl1);
|
||||
c2 = fabs((pl2 - gwe->length())*tl1 - pl1*tl2);
|
||||
if (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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user