From 1ced34ea05c206b5e504957813f43876dbc5d2be Mon Sep 17 00:00:00 2001 From: Koen Hillewaert <koen.hillewaert@cenaero.be> Date: Mon, 2 Feb 2009 12:36:13 +0000 Subject: [PATCH] a posteriori snapping of higher-order points on geometry --- Common/OpenFile.cpp | 8 +++ Geo/GEdge.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++ Geo/GEdge.h | 30 +++++++++++- Geo/GModelIO_Mesh.cpp | 12 +++++ Geo/MVertex.cpp | 14 ++++-- Geo/MVertex.h | 3 +- Geo/discreteEdge.cpp | 4 ++ Geo/discreteEdge.h | 1 + Mesh/HighOrder.cpp | 41 ++++++++++------ 9 files changed, 205 insertions(+), 19 deletions(-) diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp index c9a7c4b5e3..2e14e19279 100644 --- a/Common/OpenFile.cpp +++ b/Common/OpenFile.cpp @@ -31,6 +31,10 @@ #include "Draw.h" #endif +// KH: modify grid order after reading +extern Context_T CTX; +extern void SetOrderN(GModel *m, int order, bool linear, bool incomplete); +// end KH #define SQU(a) ((a)*(a)) static void FinishUpBoundingBox() @@ -346,6 +350,10 @@ int MergeFile(std::string fileName, bool warnIfMissing) #if !defined(HAVE_NO_POST) if(status > 1) status = PView::readMSH(fileName); #endif + // KH - modify mesh order after reading + if (CTX.mesh.order > 1) SetOrderN(GModel::current(),CTX.mesh.order,false,false); + // end - KH + } #if !defined(HAVE_NO_POST) else if(!strncmp(header, "$PostFormat", 11) || diff --git a/Geo/GEdge.cpp b/Geo/GEdge.cpp index a59b67bb14..44b3a04127 100644 --- a/Geo/GEdge.cpp +++ b/Geo/GEdge.cpp @@ -5,6 +5,8 @@ #include <sstream> #include <algorithm> +#include <limits> + #include "GmshConfig.h" #include "GmshDefines.h" #include "GmshMessage.h" @@ -15,8 +17,11 @@ #if !defined(HAVE_GMSH_EMBEDDED) #include "GaussLegendre1D.h" +#include "Context.h" #endif +extern Context_T CTX; + GEdge::GEdge(GModel *model, int tag, GVertex *_v0, GVertex *_v1) : GEntity(model, tag), _tooSmall(false), v0(_v0), v1(_v1) { @@ -167,6 +172,7 @@ double GEdge::curvature(double par) const const double one_over_D = 1. / D; SVector3 d = one_over_D * (n2 - n1); return norm(d); + } double GEdge::length(const double &u0, const double &u1, const int nbQuadPoints) @@ -188,3 +194,108 @@ double GEdge::length(const double &u0, const double &u1, const int nbQuadPoints) #endif } +GPoint GEdge::closestPoint(const SPoint3 & q,double& t) const { + + double tolerance = 1.e-12; + double dist = 1.; + + Range<double> interval = parBounds(0); + + double tMin = std::min(interval.high(),interval.low()); + double tMax = std::max(interval.high(),interval.low()); + double relax = 1.; + double dt,dt0,t0; + int nb = 10; + + t = (tMin + tMax) * 0.5; + + while (relax > 0.1) { + + int i = 0; + + t = 0.5 * (tMin + tMax); + dt0 = tMax - tMin; + dt = dt0; + + while (dt > tolerance * dt0 && i++ < nb) { + t0 = t; + dt0 = dt; + SVector3 dp = q - position(t); + SVector3 derP = firstDer(t); + double b = dot(derP,derP); + double c = dot(derP,dp); + dt = c / b; + t = std::max(tMin,std::min(tMax,t0+relax * dt)); + dt = fabs(t - t0); + } + if (i > nb) relax *= 0.5; + } + return point(t); +} + + +#include <iostream> + + +double GEdge::parFromPoint(const SVector3& Q) const { + double t; + bool success = XYZToU(Q,t); + return t; +} + +bool GEdge::XYZToU(const SVector3& Q,double &u, const double relax) const +{ + + + const double Precision = 1.e-8; + const int MaxIter = 25; + const int NumInitGuess = 11; + + double err, err2; + int iter; + + Range<double> uu = parBounds(0); + double uMin = uu.low(); + double uMax = uu.high(); + + SVector3 P; + + double init[NumInitGuess]; + + for (int i=0;i<NumInitGuess;i++) init[i] = uMin + (uMax-uMin)/(NumInitGuess-1)*i; + + for(int i = 0; i < NumInitGuess; i++){ + + u = init[i]; + double uNew = u; + err = 1.0; + iter = 1; + + SVector3 dPQ = P - Q; + err2 = dPQ.norm(); + + if (err2 < 1.e-8 * CTX.lc) return true; + + while(iter++ < MaxIter && err2 > 1e-8 * CTX.lc) { + SVector3 der = firstDer(u); + uNew = u - relax * dot(dPQ,der) / dot(der,der); + uNew = std::min(uMax,std::max(uMin,uNew)); + P = position(uNew); + + dPQ = P - Q; + err2 = dPQ.norm(); + err = fabs(uNew - u); + u = uNew; + } + + if (err2 < 1e-8 * CTX.lc) return true; + } + + if(relax > 1.e-2) { + Msg::Info("point %g %g %g on edge %d : Relaxation factor = %g", Q.x(), Q.y(), Q.z(), 0.75 * relax); + return XYZToU(Q, u, 0.75 * relax); + } + + Msg::Error("Could not converge reparametrisation of point (%e,%e,%e) on edge %d",Q.x(),Q.y(),Q.z(),tag()); + return false; +} diff --git a/Geo/GEdge.h b/Geo/GEdge.h index 0ac4cfc769..444847c557 100644 --- a/Geo/GEdge.h +++ b/Geo/GEdge.h @@ -16,6 +16,8 @@ class MElement; class MLine; class ExtrudeParams; +#include <set> + // A model edge. class GEdge : public GEntity { private: @@ -26,6 +28,8 @@ class GEdge : public GEntity { GVertex *v0, *v1; std::list<GFace *> l_faces; + std::set<GFace *> bl_faces; + public: GEdge(GModel *model, int tag, GVertex *_v0, GVertex *_v1); virtual ~GEdge(); @@ -58,10 +62,16 @@ class GEdge : public GEntity { // get the point for the given parameter location virtual GPoint point(double p) const = 0; - + // true if the edge contains the given parameter virtual bool containsParam(double pt) const; + // get the position for the given parameter location + virtual SVector3 position(double p) const { + GPoint gp = point(p); + return SVector3(gp.x(),gp.y(),gp.z()); + } + // get first derivative of edge at the given parameter virtual SVector3 firstDer(double par) const = 0; @@ -119,6 +129,24 @@ class GEdge : public GEntity { // true if entity is periodic in the "dim" direction. virtual bool periodic(int dim) const { return v0 == v1; } + // true if edge is used in hyperbolic layer on face gf + virtual bool inHyperbolicLayer(GFace* gf) { + return bl_faces.find(gf) != bl_faces.end(); + } + + virtual void flagInHyperbolicLayer(GFace* gf) {bl_faces.insert(gf);} + + // get bounds of parametric coordinate + virtual Range<double> parBounds(int i) const = 0; + + // return the point on the face closest to the given point + virtual GPoint closestPoint(const SPoint3 & queryPoint,double& param) const; + + // try to reparametrise the point on the edge + virtual double parFromPoint(const SVector3& Q) const; + + virtual bool XYZToU(const SVector3& Q,double& t,double relax=0.5) const; + struct { char Method; double coeffTransfinite; diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp index f5ca9880de..09e443a9bd 100644 --- a/Geo/GModelIO_Mesh.cpp +++ b/Geo/GModelIO_Mesh.cpp @@ -99,6 +99,9 @@ static void createElementMSH(GModel *m, int num, int type, int physical, if(part) m->getMeshPartitions().insert(part); } + +// extern void printDistortion(GModel *m, const char *nm,double& minR,double& maxR); + int GModel::readMSH(const std::string &name) { FILE *fp = fopen(name.c_str(), "rb"); @@ -215,6 +218,7 @@ int GModel::readMSH(const std::string &name) if(fread(uv, sizeof(double), 1, fp) != 1) return 0; if(swap) SwapBytes((char*)uv, sizeof(double), 1); } + Msg::Warning("Creating edge vertex \n"); newVertex = new MEdgeVertex(xyz[0], xyz[1], xyz[2], ge, uv[0], -1.0, num); } else if (iClasDim == 2){ @@ -386,6 +390,14 @@ int GModel::readMSH(const std::string &name) storePhysicalTagsInEntities(this, i, physicals[i]); fclose(fp); + + char nm[256] = "distorzione.pos"; + + double minR; + double maxR; + + // printDistortion(this,nm,minR,maxR); + return postpro ? 2 : 1; } diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp index 46f399ed82..41770ebb2e 100644 --- a/Geo/MVertex.cpp +++ b/Geo/MVertex.cpp @@ -361,9 +361,17 @@ bool reparamMeshVertexOnEdge(const MVertex *v, const GEdge *ge, double ¶m) param = bounds.low(); else if(ge->getEndVertex() && ge->getEndVertex()->mesh_vertices[0] == v) param = bounds.high(); - else - v->getParameter(0, param); - + else + param = ge->parFromPoint(SPoint3(v->x(), v->y(), v->z())); + + if (v->onWhat() == ge) { + const MEdgeVertex* ve = dynamic_cast<const MEdgeVertex*>(v); + if (!ve) param = ge->parFromPoint(SPoint3(v->x(), v->y(), v->z())); + else v->getParameter(0, param); + } + else + param = ge->parFromPoint(SPoint3(v->x(), v->y(), v->z())); + if(param < 1.e6) return true; return false; } diff --git a/Geo/MVertex.h b/Geo/MVertex.h index 3873f65405..d2fcfb5596 100644 --- a/Geo/MVertex.h +++ b/Geo/MVertex.h @@ -10,6 +10,7 @@ #include <set> #include "SPoint2.h" #include "SPoint3.h" +#include "GmshMessage.h" class GEntity; class GEdge; @@ -80,7 +81,7 @@ class MVertex{ // get/set the parent entity inline GEntity* onWhat() const { return _ge; } - inline void setEntity(GEntity *ge) { _ge = ge; } + inline void setEntity(GEntity *ge) {_ge = ge; } // get/set the number inline int getNum() const { return _num; } diff --git a/Geo/discreteEdge.cpp b/Geo/discreteEdge.cpp index 54dcf1fbfa..cb966f103d 100644 --- a/Geo/discreteEdge.cpp +++ b/Geo/discreteEdge.cpp @@ -32,3 +32,7 @@ SVector3 discreteEdge::firstDer(double par) const return SVector3(); } +Range<double> discreteEdge::parBounds(int i) const { + Msg::Error("Cannot specify bounds for parametric coordinate on discrete edge"); + return Range<double>(0,0); +} diff --git a/Geo/discreteEdge.h b/Geo/discreteEdge.h index 44ce0bf4cc..fc24c51275 100644 --- a/Geo/discreteEdge.h +++ b/Geo/discreteEdge.h @@ -16,6 +16,7 @@ class discreteEdge : public GEdge { virtual GeomType geomType() const { return DiscreteCurve; } virtual GPoint point(double p) const; virtual SVector3 firstDer(double par) const; + virtual Range<double> parBounds(int) const; }; #endif diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp index be7f91e87e..907122278a 100644 --- a/Mesh/HighOrder.cpp +++ b/Mesh/HighOrder.cpp @@ -237,11 +237,15 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve, else ve.insert(ve.end(), edgeVertices[p].rbegin(), edgeVertices[p].rend()); } - else{ - MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1); + + else{ + + MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1); + std::vector<MVertex*> temp; + double u0 = 0., u1 = 0., US[100]; bool reparamOK = true; - if(!linear){ + if(!linear) { reparamOK &= reparamMeshVertexOnEdge(v0, ge, u0); if(ge->periodic(0) && v1 == ge->getEndVertex()->mesh_vertices[0]) u1 = ge->parBounds(0).high(); @@ -251,40 +255,43 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve, double relax = 1.; while (1){ if(computeEquidistantParameters(ge, u0, u1, nPts + 2, US, relax)) - break; + break; relax /= 2.0; if(relax < 1.e-2) break; } if(relax < 1.e-2) - Msg::Warning("Failed to compute equidistant parameters (relax = %g)", - relax); + Msg::Warning("Failed to compute equidistant parameters (relax = %g) for edge %d-%d", + relax,v0->getNum(),v1->getNum()); } } - std::vector<MVertex*> temp; for(int j = 0; j < nPts; j++){ const double t = (double)(j + 1)/(nPts + 1); + double uc = (1. - t) * u0 + t * u1; // can be wrong, that's ok MVertex *v; if(linear || !reparamOK || uc < u0 || uc > u1){ + Msg::Warning("We don't have a valid parameter on curve %d-%d",v0->getNum(),v1->getNum()); // we don't have a (valid) parameter on the curve SPoint3 pc = edge.interpolate(t); v = new MVertex(pc.x(), pc.y(), pc.z(), ge); } - else { + else { GPoint pc = ge->point(US[j + 1]); - v = new MEdgeVertex(pc.x(), pc.y(), pc.z(), ge, US[j + 1]); - if (displ2D){ - SPoint3 pc2 = edge.interpolate(t); - displ2D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); - displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); - } + v = new MEdgeVertex(pc.x(), pc.y(), pc.z(), ge, US[j + 1]); + + if (displ2D){ + SPoint3 pc2 = edge.interpolate(t); + displ2D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); + displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); + } } temp.push_back(v); // this destroys the ordering of the mesh vertices on the edge ge->mesh_vertices.push_back(v); ve.push_back(v); } + if(edge.getVertex(0) == edge.getMinVertex()) edgeVertices[p].insert(edgeVertices[p].end(), temp.begin(), temp.end()); else @@ -1019,12 +1026,18 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete) // then create new second order vertices/elements edgeContainer edgeVertices; faceContainer faceVertices; + + Msg::StatusBar(1, true, "Meshing edges order %d...", order); for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it) setHighOrder(*it, edgeVertices, linear, nPts, displ2D, displ3D); + + Msg::StatusBar(1, true, "Meshing faces %d...", order); for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it) setHighOrder(*it, edgeVertices, faceVertices, linear, incomplete, nPts, displ2D, displ3D); + Msg::StatusBar(1, true, "Finished meshing order %d...", order); + // now we smooth mesh the internal vertices of the faces // we do that model face by model face std::vector<MElement*> bad; -- GitLab