Skip to content
Snippets Groups Projects
Commit 1c58a7ff authored by Francois Henrotte's avatar Francois Henrotte
Browse files

smoother for cross fields

parent 9c34cdcb
No related branches found
No related tags found
No related merge requests found
......@@ -14,9 +14,6 @@ using std::ostream;
#include "Matrix.h"
//double max(const double a, const double b) { return (b>a)?b:a;}
double min(const double a, const double b) { return (b<a)?b:a; }
double squ(const double a) { return a*a; }
/* Defined in SVector3.h */
/* double angle(const SVector3 v, const SVector3 w) { */
......@@ -63,14 +60,17 @@ void Qtn::storeProduct(const Qtn &x, const Qtn &y) {
v[2] = a0*b1 - a1*b0 + a2*b3 + a3*b2;
v[3] =-a0*b0 - a1*b1 - a2*b2 + a3*b3;
}
Qtn Qtn::operator *(const Qtn &x) const {
Qtn y;
y.storeProduct(*this, x);
return y;
Qtn Qtn::operator *(const Qtn &y) const {
Qtn x;
x.storeProduct(*this, y);
return x;
}
SVector3 eulerAxisFromQtn(const Qtn &x){
double temp = sqrt(1. - x[3]*x[3]);
if(temp< 1e-10)
return SVector3(1,0,0);
else
return SVector3(x[0]/temp, x[1]/temp, x[2]/temp);
}
......@@ -97,11 +97,23 @@ class cross3D{
private:
SVector3 frst, scnd;
public:
cross3D() {
frst = SVector3(1,0,0);
scnd = SVector3(0,1,0);
}
cross3D(const SVector3 &a, const SVector3 &b){
frst = a.unit();
scnd = crossprod(crossprod(frst, b), frst).unit();
}
cross3D(Matrix &m){
cross3D(const SVector3 &a) {
//if only a is given, b is an arbitrary vector not parallel to a
SVector3 b, Ex(1,0,0), Ey(0,1,0);
frst = a.unit();
b = (crossprod(a,Ex).norm() < 1e-2) ? Ey : Ex;
scnd = crossprod(crossprod(frst, b), frst).unit();
}
cross3D(const Matrix &x){
Matrix m = x;
SVector3 a(m.get_m11(), m.get_m21(), m.get_m31());
SVector3 b(m.get_m12(), m.get_m22(), m.get_m32());
frst = a.unit();
......@@ -127,7 +139,8 @@ public:
scnd = im(R*scnd*conj(R));
return *this;
}
Qtn rotationTo(const cross3D &x) const;
Qtn rotationTo(const cross3D &y) const;
Qtn rotationToOnSurf(const cross3D &y) const;
};
ostream& operator<< (ostream &os, const cross3D &x) {
......@@ -135,7 +148,7 @@ ostream& operator<< (ostream &os, const cross3D &x) {
return os;
}
cross3D cross3D::get(const int k) const{
cross3D cross3D::get(int k) const{
SVector3 a, b;
switch(k){
case 0: a = getFrst() ; b = getScnd() ; break;
......@@ -175,81 +188,136 @@ Qtn cross3D::rotationTo(const cross3D &y) const{
/* x.rotationTo(y) returns a quaternion R representing the rotation
such that y = R x, x = conj(R) y
eulerAngleFromQtn(R) = distance(x, y)
if onFace is true, only the rotation around y.frst (which is the normal) is returned
*/
int ind1, ind2;
double d, dmin, th1, th2;
SVector3 n, w, axis;
double d, dmin, jmin, kmin, th1, th2;
SVector3 axis;
Qtn Rxy1, Rxy2;
cross3D xx = get(0);
dmin = angle(xx.frst, y.get(0).frst); ind1 = 0;
for(unsigned int k=4 ; k<24; k=k+4){
if((d = angle(xx.frst, y.get(k).frst)) < dmin) {
ind1 = k;
cross3D xx = *this;
cross3D yy = y;
//ind1 = 0; jmin=0; dmin = angle(xx.get(kmin).frst, vect[jmin]);
dmin = M_PI; jmin = kmin = 0;
for(int j=0 ; j<24; j=j+4){
for(int k=0 ; k<12; k=k+4){
if((d = angle(xx.get(j).frst, yy.get(k).frst)) < dmin) {
kmin = k;
jmin = j;
dmin = d;
}
}
// y.get(ind1) is the attitude of y whose y.first minimizes the angle with x.first
axis = crossprod(xx.frst, y.get(ind1).frst);
if(axis.norm() > 1e-8)
axis.normalize();
else {
axis = SVector3(1,0,0);
dmin = 0.;
}
xx = xx.get(jmin);
yy = yy.get(kmin);
// xx.frst and yy.frst now form the smallest angle among the 6^2 possible.
th1 = dmin;
if(th1 > 1.00001*acos(1./sqrt(3.))){
std::cout << "This should not happen: th1 = " << th1 << std::endl;
exit(1);
}
if(th1 > 1e-8)
axis = crossprod(xx.frst, yy.frst).unit();
else {
axis = SVector3(1,0,0);
th1 = 0.;
}
Rxy1 = Qtn(axis, dmin);
Rxy1 = Qtn(axis, th1);
xx.rotate(Rxy1);
dmin = angle(xx.scnd, y.get(ind1).scnd); ind2 = ind1;
for(unsigned int k=1 ; k<4; k++){
if((d = angle(xx.scnd, y.get(ind1 + k).scnd)) < dmin) {
ind2 = ind1 + k;
dmin = M_PI;
for(int j=0 ; j<4; j++){
if((d = angle(xx.get(j).scnd, yy.scnd)) < dmin) {
jmin = j;
dmin = d;
}
}
// y.get(ind2) is the attitude of y whose y.second minimizes the angle with xx.second
axis = crossprod(xx.scnd, y.get(ind2).scnd);
//axis = xx.first;
if(axis.norm() > 1e-8)
axis.normalize();
else {
axis = SVector3(1,0,0);
dmin = 0.;
}
xx = xx.get(jmin);
// xx.scnd and yy.scnd now form the smallest angle among the 4^2 possible.
th2 = dmin;
if(th2 > M_PI/2.){
if(th2 > M_PI/4.){
std::cout << "This should not happen: th2 = " << th2 << std::endl;
exit(1);
}
Rxy2 = Qtn(axis, dmin);
if(th2 > 1e-8)
axis = crossprod(xx.scnd, yy.scnd).unit();
else {
axis = SVector3(1,0,0);
th2 = 0.;
}
xx.rotate(Rxy2);
Rxy2 = Qtn(axis, th2);
Qtn R = Rxy2*Rxy1;
// test
double theta = eulerAngleFromQtn(R);
if(theta > 1.11){
if(theta > 1.07 /*0.988*/){ //
std::cout << "Ouch! th1 = " << th1 << " th2 = " << th2 << std::endl;
std::cout << "x = " << *this << std::endl;
std::cout << "y = " << y << std::endl;
/* std::cout << "R = " << R << std::endl; */
std::cout << "R = " << R << std::endl;
std::cout << "u = " << eulerAngleFromQtn(R) << std::endl;
std::cout << "axis = " << eulerAxisFromQtn(R) << std::endl;
}
return R;
}
Qtn cross3D::rotationToOnSurf(const cross3D &y) const{
/* this->frst and y.frst are assumed to be the normal to the face
R1 is the rotation such that R1(this->frst) = y.frst.
R2 is then the rotation such that R2 o R1(this->scnd) = y.scnd
*/
double d, dmin, jmin, th1, th2;
SVector3 axis;
cross3D xx = *this;
cross3D yy = y;
th1 = angle(xx.frst, yy.frst);
if(th1 > 1e-8)
axis = crossprod(xx.frst, yy.frst).unit();
else {
axis = SVector3(1,0,0);
th1 = 0.;
}
Qtn R1 = Qtn(axis, th1);
xx.rotate(R1);
if(fabs(angle(xx.getFrst(), yy.getFrst())) > 1e-8){
std::cout << "This should not happen: not aligned "<< std::endl;
exit(1);
}
dmin = M_PI; jmin = 0;
for(int j=0 ; j<4; j++){
if((d = angle(xx.get(j).scnd, yy.scnd)) < dmin) {
jmin = j;
dmin = d;
}
}
xx = xx.get(jmin);
// xx.scnd and yy.scnd now form the smallest angle among the 4^2 possible.
th2 = dmin;
if(th2 > M_PI/4.){
std::cout << "This should not happen: th2 = " << th2 << std::endl;
exit(1);
}
if(th2 > 1e-8)
axis = crossprod(xx.scnd, yy.scnd).unit();
else {
axis = SVector3(1,0,0);
th2 = 0.;
}
Qtn R2 = Qtn(axis, th2);
return R2;
}
Matrix convert(const cross3D x){
Matrix m;
SVector3 v;
......
......@@ -25,7 +25,7 @@
Frame_field::Frame_field(){}
void Frame_field::init_region(GRegion* gr){
// Fill in the ANN tree with the bondary cross field of region gr
// Fill in a ANN tree with the bondary cross field of region gr
#if defined(HAVE_ANN)
int index;
MVertex* vertex;
......@@ -63,6 +63,8 @@ void Frame_field::init_region(GRegion* gr){
}
void Frame_field::init_face(GFace* gf){
// Fills the auxiliary std::map "temp" with a pair <vertex, Matrix>
// for each vertex of the face gf.
unsigned int i;
int j;
bool ok;
......@@ -431,40 +433,278 @@ void Frame_field::clear(){
delete kd_tree;
annClose();
#endif
#if defined(HAVE_ANN)
if(annTreeData) delete annTreeData;
if(annTree) delete annTree;
#endif
}
// BARYCENTRIC
#include "cross3D.h"
// CWTSSpaceVector<> convert(const SVector3 v){
// return CWTSSpaceVector<> (v.x(), v.y(), v.z());
// }
//double max(const double a, const double b) { return (b>a)?b:a;}
double min(const double a, const double b) { return (b<a)?b:a; }
double squ(const double a) { return a*a; }
// SVector3 convert(const CWTSSpaceVector<> x){
// return SVector3 (x[0], x[1], x[2]);
// }
int Frame_field::build_vertex_to_vertices(GEntity* gr, int onWhat, bool initialize){
// build vertex to vertices data
std::set<MVertex*> vertices;
if(initialize) vertex_to_vertices.clear();
for(unsigned int i=0; i<gr->getNumMeshElements(); i++){
MElement* pElem = gr->getMeshElement(i);
unsigned int n = pElem->getNumVertices();
for(unsigned int j=0; j<n; j++){
MVertex* pVertex = pElem->getVertex(j);
if(pVertex->onWhat()->dim() != onWhat) continue;
// ostream& operator<< (ostream &os, SVector3 &v) {
// os << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")";
// return os;
// }
std::map<MVertex*,std::set<MVertex*> >::iterator it = vertex_to_vertices.find(pVertex);
if(it != vertex_to_vertices.end()){
for(unsigned int k=1; k<n; k++)
it->second.insert(pElem->getVertex((j+k) % n));
}
else{
vertices.clear();
for(unsigned int k=1; k<n; k++)
vertices.insert(pElem->getVertex((j+k) % n));
vertex_to_vertices.insert(std::pair<MVertex*,std::set<MVertex*> >(pVertex,vertices));
}
void Frame_field::init(GRegion* gr){
// SVector3 Ex(1,0,0), Ey(0,1,0), Ez(0,0,1);
// SVector3 v(1,2,0), w(0,1,1.3);
// cross3D x(Ez, Ex);
// cross3D y = cross3D(v, w);
}
}
return vertex_to_vertices.size();
}
//Recombinator crossData;
crossData.build_vertex_to_vertices(gr);
std::cout << "Vertices in crossData = " << crossData.vertex_to_vertices.size() << std::endl;
for(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter
= crossData.vertex_to_vertices.begin();
iter != crossData.vertex_to_vertices.end(); ++iter){
MVertex* pVertex = iter->first;
Matrix m = search(pVertex->x(), pVertex->y(), pVertex->z());
// if(pVertex->onWhat()->dim() <= 2)
crossField[pVertex->getNum()] = m;
int Frame_field::build_vertex_to_elements(GEntity* gr, bool initialize){
std::set<MElement*> elements;
if(initialize) vertex_to_elements.clear();
for(unsigned int i=0; i<gr->getNumMeshElements(); i++){
MElement* pElem = gr->getMeshElement(i);
unsigned int n = pElem->getNumVertices();
for(unsigned int j=0; j<n; j++){
MVertex* pVertex = pElem->getVertex(j);
std::map<MVertex*,std::set<MElement*> >::iterator it = vertex_to_elements.find(pVertex);
if(it != vertex_to_elements.end())
it->second.insert(pElem);
else{
elements.clear();
elements.insert(pElem);
vertex_to_elements.insert(std::pair<MVertex*,std::set<MElement*> >(pVertex,elements));
}
}
}
return vertex_to_elements.size();
}
void Frame_field::build_listVertices(GEntity* gr, int dim, bool initialize){
std::set<MVertex*> list;
for(unsigned int i=0; i<gr->getNumMeshElements(); i++){
MElement* pElem = gr->getMeshElement(i);
for(int j=0; j<pElem->getNumVertices(); j++){
MVertex * pVertex = pElem->getVertex(j);
if(pVertex->onWhat()->dim() == dim)
list.insert(pVertex);
}
}
if(initialize) listVertices.clear();
for(std::set<MVertex*>::const_iterator it=list.begin(); it!=list.end(); it++)
listVertices.push_back(*it);
}
int Frame_field::buildAnnData(GEntity* ge, int dim){
build_listVertices(ge,dim);
int n = listVertices.size();
#if defined(HAVE_ANN)
annTreeData = annAllocPts(n,3);
for(int i=0; i<n; i++){
MVertex* pVertex = listVertices[i];
annTreeData[i][0] = pVertex->x();
annTreeData[i][1] = pVertex->y();
annTreeData[i][2] = pVertex->z();
}
annTree = new ANNkd_tree(annTreeData,n,3);
#endif
std::cout << "ANN data for " << ge->tag() << "(" << dim << ") contains " << n << " vertices" << std::endl;
return n;
}
void Frame_field::deleteAnnData(){
#if defined(HAVE_ANN)
if(annTreeData) delete annTreeData;
if(annTree) delete annTree;
annTreeData = NULL;
annTree = NULL;
#endif
}
int Frame_field::findAnnIndex(SPoint3 p){
int index = 0;
#if defined(HAVE_ANN)
ANNpoint query = annAllocPt(3);
ANNidxArray indices = new ANNidx[1];
ANNdistArray distances = new ANNdist[1];
query[0] = p.x();
query[1] = p.y();
query[2] = p.z();
double e = 0.;
annTree->annkSearch(query,1,indices,distances,e);
annDeallocPt(query);
index = indices[0];
delete[] indices;
delete[] distances;
#endif
return index;
}
void Frame_field::initFace(GFace* gf){
// align crosses of gf with the normal (average on neighbour elements)
// at all vertices of the GFace gf
build_vertex_to_elements(gf);
for(std::map<MVertex*, std::set<MElement*> >::const_iterator it
= vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){
std::set<MElement*> elements = it->second;
SVector3 Area = SVector3(0,0,0);
for(std::set<MElement*>::const_iterator iter=elements.begin();
iter != elements.end(); iter++){
MElement *pElem = *iter;
int n = pElem->getNumVertices();
int i;
for(i=0; i<n; i++){
if(pElem->getVertex(i) == it->first) break;
if(i == n-1) {
std::cout << "This should not happen" << std:: endl; exit(1);
}
}
SVector3 V0 = pElem->getVertex(i)->point();
SVector3 V1 = pElem->getVertex((i+n-1)%n)->point(); // previous vertex
SVector3 V2 = pElem->getVertex((i+1)%n)->point(); // next vertex
Area += crossprod(V2-V0,V1-V0);
}
Area.normalize(); // average normal over neighbour face elements
Matrix m = convert(cross3D(Area));
std::map<MVertex*, Matrix>::iterator iter = crossField.find(it->first);
if(iter == crossField.end())
crossField.insert(std::pair<MVertex*, Matrix>(it->first,m));
else
crossField[it->first] = m;
}
std::cout << "Nodes in face = " << vertex_to_elements.size() << std::endl;
// compute cumulative cross-data vertices x elements for the whole contour of gf
std::list<GEdge*> edges = gf->edges();
vertex_to_elements.clear();
for( std::list<GEdge*>::const_iterator it=edges.begin(); it!=edges.end(); it++)
build_vertex_to_elements(*it,false);
// align crosses of the contour of "gf" with the tangent to the contour
for(std::map<MVertex*, std::set<MElement*> >::const_iterator it
= vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){
MVertex* pVertex = it->first;
std::set<MElement*> elements = it->second;
if(elements.size() != 2){
std::cout << "The face has an open boundary" << std::endl;
exit(1);
}
MEdge edg1 = (*elements.begin())->getEdge(0);
MEdge edg2 = (*elements.rbegin())->getEdge(0);
SVector3 tangent = edg1.scaledTangent() + edg2.scaledTangent();
tangent.normalize();
std::map<MVertex*, Matrix>::iterator iter = crossField.find(pVertex);
if(iter == crossField.end()) {
std::cout << "This should not happen: cross not found 1" << std::endl;
exit(1);
}
cross3D x(cross3D((*iter).second));
Matrix m = convert(cross3D(x.getFrst(), tangent));
crossField[pVertex] = m;
}
// fills ANN data with the vertices of the contour (dim=1) of "gf"
buildAnnData(gf,1);
std::cout << "Nodes on contour = " << vertex_to_elements.size() << std::endl;
std::cout << "crossField = " << crossField.size() << std::endl;
std::cout << "region = " << gf->getNumMeshVertices() << std::endl;
// align crosses.scnd with the nearest cross of the contour
// fixme: we have to rebuild the vertex_to_elements list
// to have a working iterator oin the verticies of gf
// The natural iterator gf->getMeshVertex(i) seems not to work
// when the option PackingOfParallelogram is on.
build_vertex_to_elements(gf);
for(std::map<MVertex*, std::set<MElement*> >::const_iterator it
= vertex_to_elements.begin(); it != vertex_to_elements.end(); it++){
//for(unsigned int i=0; i<gf->getNumMeshVertices(); i++){
//MVertex* pVertex0 = gf->getMeshVertex(i);
MVertex* pVertex0 = it->first;
if(pVertex0->onWhat()->dim() != 2) continue;
std::map<MVertex*, Matrix>::iterator iter = crossField.find(pVertex0);
cross3D y;
if(iter == crossField.end()){
std::cout << "This should not happen: cross not found 2" << std::endl;
std::cout << pVertex0->x() << "," << pVertex0->y() << "," << pVertex0->z() << std::endl;
//exit(1);
y = cross3D();
}
else
y = cross3D((*iter).second); //local cross y.getFirst() is the normal
// Find the index of the nearest cross on the contour, using annTree
int index = findAnnIndex(pVertex0->point());
MVertex* pVertex = listVertices[index]; //nearest vertex on contour
iter = crossField.find(pVertex);
if(iter == crossField.end()){
std::cout << "This should not happen: cross not found 3" << std::endl;
exit(1);
}
cross3D x = cross3D((*iter).second); //nearest cross on contour, x.getFrst() is the normal
//Matrix m = convert(cross3D(x.getFrst(),y.getScnd()));
SVector3 v1 = y.getFrst();
Matrix m = convert( y.rotate(conj(x.rotationToOnSurf(y)))); //rotation around the normal
SVector3 v2 = y.getFrst();
if(fabs(angle(v1,v2)) > 1e-8){
std::cout << "This should not happen: rotation affected the normal" << std::endl;
exit(1);
}
crossField[pVertex0] = m;
}
checkAnnData(gf, "zzz.pos");
deleteAnnData();
}
void Frame_field::initRegion(GRegion* gr, int n){
std::list<GFace*> faces = gr->faces();
for(std::list<GFace*>::const_iterator iter=faces.begin(); iter!=faces.end(); iter++){
initFace(*iter);
// smoothing must be done immediately because crosses on the contour vertices
// are now initialized with the normal to THIS face.
smoothFace(*iter, n);
}
// Fills ANN data with the vertices of the surface (dim=2) of "gr"
buildAnnData(gr,2);
for(unsigned int i=0; i<gr->getNumMeshVertices(); i++){
MVertex* pVertex0 = gr->getMeshVertex(i);
if(pVertex0->onWhat()->dim() != 3) continue;
// Find the index of the nearest cross on the contour, using annTree
int index = findAnnIndex(pVertex0->point());
MVertex* pVertex = listVertices[index];
Matrix m = crossField[pVertex];
crossField.insert(std::pair<MVertex*, Matrix>(pVertex0,m));
}
deleteAnnData();
buildAnnData(gr,3);
}
Matrix Frame_field::findCross(double x, double y, double z){
int index = Frame_field::findAnnIndex(SPoint3(x,y,z));
MVertex* pVertex = Frame_field::listVertices[index];
return crossField[pVertex];
}
double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, Matrix &m0){
......@@ -486,9 +726,10 @@ double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::cons
MVertex *pVertex = *it;
if(pVertex->getNum() == pVertex0->getNum())
std::cout << "This should not happen!" << std::endl;
std::map<int, Matrix>::const_iterator itB = crossField.find(pVertex->getNum());
if(itB == crossField.end()) // not found
m = search(pVertex->x(), pVertex->y(), pVertex->z());
std::map<MVertex*, Matrix>::const_iterator itB = crossField.find(pVertex);
if(itB == crossField.end()){ // not found
std::cout << "This should not happen: cross not found 4" << std::endl; exit(1);
}
else
m = itB->second;
cross3D y(m);
......@@ -501,22 +742,15 @@ double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::cons
crossDist[edge] = theta;
if (fabs(theta) > 1e-10) {
axis = eulerAxisFromQtn(Rxy); // undefined if theta==0
// dT = convert(axis) * (theta / edge.length() / edge.length()) ;
dT = axis * (theta / edge.length() / edge.length()) ;
T += dT;
}
temp += 1. / edge.length() / edge.length();
//std::cout << " " << pVertex->getNum() << " : " << theta << dT << std::endl;
}
if(list.size()) T *= 1.0/temp; // average rotation vector
double a = T.norm();
SVector3 b = T; b.normalize();
if(debug) std::cout << "energy= " << energy << " T= " << a << b << std::endl;
if(temp) T *= 1.0/temp; // average rotation vector
//std::cout << "xold=> " << x << std::endl;
theta = T.norm();
if(fabs(theta) > 1e-10){
//axis = convert(T);
axis = T;
if(debug) std::cout << "-> " << pVertex0->getNum() << " : " << T << std::endl;
Qtn R(axis.unit(),theta);
......@@ -526,27 +760,44 @@ double Frame_field::findBarycenter(std::map<MVertex*, std::set<MVertex*> >::cons
return energy;
}
double Frame_field::smooth(GRegion* gr){
// loops on crossData.vertex_to_vertices
//
double Frame_field::smoothFace(GFace *gf, int n){
double energy=0;
build_vertex_to_vertices(gf, 2);
build_vertex_to_vertices(gf, 0, false);
for(int i=0; i<n; i++){
energy = smooth();
std::cout << "energy = " << energy << std::endl;
}
return energy;
}
double Frame_field::smoothRegion(GRegion *gr, int n){
double energy=0;
build_vertex_to_vertices(gr, 3);
//build_vertex_to_vertices(gr, 1, false);
//build_vertex_to_vertices(gr, 0, false);
for(int i=0; i<n; i++){
energy = smooth();
std::cout << "energy = " << energy << std::endl;
}
return energy;
}
double Frame_field::smooth(){
Matrix m, m0;
double enew, eold;
// Recombinator crossData;
// crossData.build_vertex_to_vertices(gr);
//std::cout << "NbVert= " << crossData.vertex_to_vertices.size() << std::endl ;
double energy = 0;
for(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter
= crossData.vertex_to_vertices.begin();
iter != crossData.vertex_to_vertices.end(); ++iter){
= vertex_to_vertices.begin(); iter != vertex_to_vertices.end(); ++iter){
MVertex* pVertex0 = iter->first;
if(pVertex0->onWhat()->dim()>2){
//MVertex* pVertex0 = iter->first;
SVector3 T(0, 0, 0);
std::map<int, Matrix>::iterator itA = crossField.find(iter->first->getNum());
if(itA == crossField.end())
m0 = search(pVertex0->x(), pVertex0->y(), pVertex0->z());
std::map<MVertex*, Matrix>::iterator itA = crossField.find(iter->first);
if(itA == crossField.end()){
std::cout << "This should not happen" << std::endl; exit(1);
}
else
m0 = itA->second;
......@@ -560,101 +811,87 @@ double Frame_field::smooth(GRegion* gr){
} while ((enew < eold) && (++NbIter < 10));
energy += eold;
}
}
return energy;
}
void Frame_field::save(GRegion* gr, const std::string& filename){
SPoint3 p, p1;
MVertex* pVertex;
std::map<MVertex*,Matrix>::iterator it;
Matrix m;
// Recombinator crossData;
// crossData.build_vertex_to_vertices(gr);
double k = 0.04;
void Frame_field::save(const std::vector<std::pair<SPoint3, Matrix> > data,
const std::string& filename){
const cross3D origin(SVector3(1,0,0), SVector3(0,1,0));
SPoint3 p1;
double k = 0.1;
std::ofstream file(filename.c_str());
file << "View \"cross field\" {\n";
for(std::map<MVertex*, std::set<MVertex*> >::iterator iter = crossData.vertex_to_vertices.begin();
iter != crossData.vertex_to_vertices.end(); ++iter){
pVertex = iter->first;
std::map<int, Matrix>::iterator itA = crossField.find(pVertex->getNum());
if(itA == crossField.end())
m = search(pVertex->x(), pVertex->y(), pVertex->z());
else
m = itA->second;
p = SPoint3(pVertex->x(),pVertex->y(),pVertex->z());
double val1=0, val2=0;
p1 = SPoint3(pVertex->x() + k*m.get_m11(),
pVertex->y() + k*m.get_m21(),
pVertex->z() + k*m.get_m31());
for(unsigned int i=0; i<data.size(); i++){
SPoint3 p = data[i].first;
Matrix m = data[i].second;
double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin)), val2=val1;
p1 = SPoint3(p.x() + k*m.get_m11(),
p.y() + k*m.get_m21(),
p.z() + k*m.get_m31());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(pVertex->x() - k*m.get_m11(),
pVertex->y() - k*m.get_m21(),
pVertex->z() - k*m.get_m31());
p1 = SPoint3(p.x() - k*m.get_m11(),
p.y() - k*m.get_m21(),
p.z() - k*m.get_m31());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(pVertex->x() + k*m.get_m12(),
pVertex->y() + k*m.get_m22(),
pVertex->z() + k*m.get_m32());
p1 = SPoint3(p.x() + k*m.get_m12(),
p.y() + k*m.get_m22(),
p.z() + k*m.get_m32());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(pVertex->x() - k*m.get_m12(),
pVertex->y() - k*m.get_m22(),
pVertex->z() - k*m.get_m32());
p1 = SPoint3(p.x() - k*m.get_m12(),
p.y() - k*m.get_m22(),
p.z() - k*m.get_m32());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(pVertex->x() + k*m.get_m13(),
pVertex->y() + k*m.get_m23(),
pVertex->z() + k*m.get_m33());
p1 = SPoint3(p.x() + k*m.get_m13(),
p.y() + k*m.get_m23(),
p.z() + k*m.get_m33());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(pVertex->x() - k*m.get_m13(),
pVertex->y() - k*m.get_m23(),
pVertex->z() - k*m.get_m33());
p1 = SPoint3(p.x() - k*m.get_m13(),
p.y() - k*m.get_m23(),
p.z() - k*m.get_m33());
print_segment(p,p1,val1,val2,file);
}
file << "};\n";
file.close();
}
void Frame_field::fillTreeVolume(GRegion* gr){
#if defined(HAVE_ANN)
int n = crossData.vertex_to_vertices.size();
std::cout << "Filling ANN tree with " << n << " vertices" << std::endl;
annTreeData = annAllocPts(n,3);
int index=0;
vertIndices.clear();
for(std::map<MVertex*, std::set<MVertex*> >::iterator iter = crossData.vertex_to_vertices.begin();
iter != crossData.vertex_to_vertices.end(); ++iter){
MVertex* pVertex = iter->first;
annTreeData[index][0] = pVertex->x();
annTreeData[index][1] = pVertex->y();
annTreeData[index][2] = pVertex->z();
vertIndices.push_back(pVertex->getNum());
index++;
}
annTree = new ANNkd_tree(annTreeData,n,3);
#endif
void Frame_field::saveCrossField(const std::string& filename, double scale, bool full){
const cross3D origin(SVector3(1,0,0), SVector3(0,1,0));
SPoint3 p1;
double k = scale;
std::ofstream file(filename.c_str());
file << "View \"cross field\" {\n";
for(std::map<MVertex*, Matrix>::const_iterator it = crossField.begin();
it != crossField.end(); it++){
SPoint3 p = it->first->point();
Matrix m = it->second;
double val1 = eulerAngleFromQtn(cross3D(m).rotationTo(origin))*180./M_PI, val2=val1;
p1 = SPoint3(p.x() + k*m.get_m11(),
p.y() + k*m.get_m21(),
p.z() + k*m.get_m31());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(p.x() - k*m.get_m11(),
p.y() - k*m.get_m21(),
p.z() - k*m.get_m31());
if(full) print_segment(p,p1,val1,val2,file);
p1 = SPoint3(p.x() + k*m.get_m12(),
p.y() + k*m.get_m22(),
p.z() + k*m.get_m32());
print_segment(p,p1,val1,val2,file);
p1 = SPoint3(p.x() - k*m.get_m12(),
p.y() - k*m.get_m22(),
p.z() - k*m.get_m32());
if(full) print_segment(p,p1,val1,val2,file);
p1 = SPoint3(p.x() + k*m.get_m13(),
p.y() + k*m.get_m23(),
p.z() + k*m.get_m33());
if(full) print_segment(p,p1,val1,val2,file);
p1 = SPoint3(p.x() - k*m.get_m13(),
p.y() - k*m.get_m23(),
p.z() - k*m.get_m33());
if(full) print_segment(p,p1,val1,val2,file);
}
Matrix Frame_field::findNearestCross(double x,double y,double z){
#if defined(HAVE_ANN)
ANNpoint query = annAllocPt(3);
ANNidxArray indices = new ANNidx[1];
ANNdistArray distances = new ANNdist[1];
query[0] = x;
query[1] = y;
query[2] = z;
double e = 0.0;
annTree->annkSearch(query,1,indices,distances,e);
annDeallocPt(query);
std::map<int, Matrix>::const_iterator it = crossField.find(vertIndices[indices[0]]);
//annTreeData[indices[0]] gives the coordinates
delete[] indices;
delete[] distances;
return it->second;
#else
return Matrix();
#endif
file << "};\n";
file.close();
}
void Frame_field::save_dist(const std::string& filename){
......@@ -665,7 +902,7 @@ void Frame_field::save_dist(const std::string& filename){
it != crossDist.end(); it++){
MVertex* pVerta = it->first.getVertex(0);
MVertex* pVertb = it->first.getVertex(1);
double value = it->second;
double value = it->second*180./M_PI;
if(it->first.length())
value /= it->first.length();
file << "SL ("
......@@ -677,6 +914,24 @@ void Frame_field::save_dist(const std::string& filename){
file.close();
}
void Frame_field::checkAnnData(GEntity* ge, const std::string& filename){
#if defined(HAVE_ANN)
std::ofstream file(filename.c_str());
file << "View \"ANN pairing\" {\n";
for(unsigned int i=0; i<ge->getNumMeshVertices(); i++){
MVertex* pVerta = ge->getMeshVertex(i);
MVertex* pVertb = listVertices[findAnnIndex(pVerta->point())];
double value = pVerta->distance(pVertb);
file << "SL ("
<< pVerta->x() << ", " << pVerta->y() << ", " << pVerta->z() << ", "
<< pVertb->x() << ", " << pVertb->y() << ", " << pVertb->z() << ")"
<< "{" << value << "," << value << "};\n";
}
file << "};\n";
file.close();
#endif
}
#include "PView.h"
#include "PViewDataList.h"
void Frame_field::save_energy(GRegion* gr, const std::string& filename){
......@@ -1310,16 +1565,16 @@ void Nearest_point::clear(){
std::map<MVertex*,Matrix> Frame_field::temp;
std::vector<std::pair<MVertex*,Matrix> > Frame_field::field;
std::map<int, Matrix> Frame_field::crossField;
std::map<MVertex*, Matrix> Frame_field::crossField;
std::map<MEdge, double, Less_Edge> Frame_field::crossDist;
Recombinator Frame_field::crossData;
std::map<MVertex*,std::set<MVertex*> > Frame_field::vertex_to_vertices;
std::map<MVertex*,std::set<MElement*> > Frame_field::vertex_to_elements;
std::vector<MVertex*> Frame_field::listVertices;
#if defined(HAVE_ANN)
ANNpointArray Frame_field::duplicate;
ANNkd_tree* Frame_field::kd_tree;
ANNpointArray Frame_field::annTreeData;
ANNkd_tree* Frame_field::annTree;
std::vector<int> Frame_field::vertIndices;
#endif
std::map<MVertex*,double> Size_field::boundary;
......
......@@ -27,15 +27,14 @@ class Frame_field{
private:
static std::map<MVertex*, Matrix> temp;
static std::vector<std::pair<MVertex*, Matrix> > field;
static std::map<int, Matrix> crossField;
//static std::map<MVertex*, Matrix, MVertexLessThanNum> crossField;
static std::map<MVertex*, Matrix> crossField;
static std::map<MEdge, double, Less_Edge> crossDist;
static std::vector<MVertex*> listVertices;
#if defined(HAVE_ANN)
static ANNpointArray duplicate;
static ANNkd_tree* kd_tree;
static ANNpointArray annTreeData;
static ANNkd_tree* annTree;
static std::vector<int> vertIndices;
#endif
Frame_field();
public:
......@@ -50,15 +49,27 @@ class Frame_field{
static void print_field1();
static void print_field2(GRegion*);
static void print_segment(SPoint3,SPoint3,double,double,std::ofstream&);
static Recombinator crossData;
static void init(GRegion* gr);
static double smooth(GRegion* gr);
static std::map<MVertex*,std::set<MVertex*> > vertex_to_vertices;
static std::map<MVertex*,std::set<MElement*> > vertex_to_elements;
static int build_vertex_to_vertices(GEntity* gr, int onWhat, bool initialize=true);
static int build_vertex_to_elements(GEntity* gr, bool initialize=true);
static void build_listVertices(GEntity* gr, int dim, bool initialize=true);
static int buildAnnData(GEntity* ge, int dim);
static void deleteAnnData();
static int findAnnIndex(SPoint3 p);
static Matrix findCross(double x, double y, double z);
static void initFace(GFace* gf);
static void initRegion(GRegion* gr, int n);
static double smoothFace(GFace *gf, int n);
static double smoothRegion(GRegion *gr, int n);
static double smooth();
static double findBarycenter(std::map<MVertex*, std::set<MVertex*> >::const_iterator iter, Matrix &m0);
static void fillTreeVolume(GRegion* gr);
static Matrix findNearestCross(double x,double y,double z);
static void save(GRegion* gr, const std::string &filename);
static void save(const std::vector<std::pair<SPoint3, Matrix> > data,
const std::string& filename);
static void saveCrossField(const std::string& filename, double scale, bool full=true);
static void save_energy(GRegion* gr, const std::string& filename);
static void save_dist(const std::string& filename);
static void checkAnnData(GEntity* ge, const std::string& filename);
static GRegion* test();
static void clear();
};
......
......@@ -325,6 +325,18 @@ void Filler::treat_model(){
}
void Filler::treat_region(GRegion* gr){
int NumSmooth = CTX::instance()->mesh.smoothCrossField;
std::cout << "NumSmooth = " << NumSmooth << std::endl ;
if(NumSmooth && (gr->dim() == 3)){
double scale = gr->bounds().diag()*1e-2;
Frame_field::initRegion(gr,NumSmooth);
Frame_field::saveCrossField("cross0.pos",scale);
Frame_field::smoothRegion(gr,NumSmooth);
Frame_field::saveCrossField("cross1.pos",scale);
}
#if defined(HAVE_RTREE)
unsigned int i;
int j;
......@@ -347,23 +359,6 @@ void Filler::treat_region(GRegion* gr){
RTree<Node*,double,3,double> rtree;
Frame_field::init_region(gr);
int NumSmooth = CTX::instance()->mesh.smoothCrossField;
if(NumSmooth){
Frame_field::init(gr);
Frame_field::save(gr,"cross_init.pos");
double enew = Frame_field::smooth(gr);
int NumIter = 0;
double eold = 0;
do{
std::cout << "Smoothing: energy(" << NumIter << ") = " << enew << std::endl;
eold = enew;
enew = Frame_field::smooth(gr);
} while((eold > enew) && (NumIter++ < NumSmooth));
Frame_field::save(gr,"cross_smooth.pos");
Frame_field::fillTreeVolume(gr);
}
Size_field::init_region(gr);
Size_field::solve(gr);
octree = new MElementOctree(gr->model());
......@@ -475,10 +470,11 @@ void Filler::treat_region(GRegion* gr){
Metric Filler::get_metric(double x,double y,double z){
Metric m;
Matrix m2;
if(!CTX::instance()->mesh.smoothCrossField)
m2 = Frame_field::search(x,y,z);
if(CTX::instance()->mesh.smoothCrossField){
m2 = Frame_field::findCross(x,y,z);
}
else
m2 = Frame_field::findNearestCross(x,y,z);
m2 = Frame_field::search(x,y,z);
m.set_m11(m2.get_m11());
m.set_m21(m2.get_m21());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment