Newer
Older
// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@geuz.org>.
#include "GmshConfig.h"
#include "GmshDefines.h"
#include "GmshMessage.h"
: GEntity(model, tag), _tooSmall(false), v0(_v0), v1(_v1), compound(0)
void GEdge::deleteMesh()
{
for(unsigned int i = 0; i < mesh_vertices.size(); i++) delete mesh_vertices[i];
mesh_vertices.clear();
for(unsigned int i = 0; i < lines.size(); i++) delete lines[i];
lines.clear();

Christophe Geuzaine
committed
_normals.clear();
deleteVertexArrays();
model()->destroyMeshCaches();
void GEdge::reverse()
{
GVertex* tmp = v0;
v0 = v1;
v1 = tmp;
for(std::vector<MLine*>::iterator line = lines.begin(); line != lines.end(); line++)

Christophe Geuzaine
committed
(*line)->reverse();
}
unsigned int GEdge::getNumMeshParentElements()
{
unsigned int n = 0;
for(unsigned int i = 0; i < lines.size(); i++)
if(lines[i]->ownsParent())
n++;
return n;
}
void GEdge::getNumMeshElements(unsigned *const c) const
{
c[0] += lines.size();
}
MElement *const *GEdge::getStartElementType(int type) const
{
if(lines.empty()) return 0; // msvc would throw an exception
return reinterpret_cast<MElement *const *>(&lines[0]);
}
MElement *GEdge::getMeshElement(unsigned int index)

Christophe Geuzaine
committed
meshAttributes.method = MESH_UNSTRUCTURED;
meshAttributes.coeffTransfinite = 0.;
meshAttributes.nbPointsTransfinite = 0;
meshAttributes.typeTransfinite = 0;
meshAttributes.extrude = 0;
meshAttributes.minimumMeshSegments = 1;
meshAttributes.reverseMesh = false;
if (std::find(l_faces.begin(), l_faces.end(), e) == l_faces.end())
l_faces.push_back(e);
l_faces.erase(std::find(l_faces.begin(), l_faces.end(), e));
}
SBoundingBox3d GEdge::bounds() const
{
SBoundingBox3d bbox;
if(geomType() != DiscreteCurve && geomType() != BoundaryLayerCurve){
Range<double> tr = parBounds(0);
double t = tr.low() + (double)i / (double)(N - 1) * (tr.high() - tr.low());
GPoint p = point(t);
bbox += SPoint3(p.x(), p.y(), p.z());
}
}
else{
for(unsigned int i = 0; i < mesh_vertices.size(); i++)
bbox += mesh_vertices[i]->point();
SOrientedBoundingBox GEdge::getOBB()
{
if (!_obb) {
std::vector<SPoint3> vertices;
if(getNumMeshVertices() > 0) {
int N = getNumMeshVertices();

Jean-François Remacle
committed
for (int i = 0; i < N; i++) {
MVertex* mv = getMeshVertex(i);

Jean-François Remacle
committed
vertices.push_back(mv->point());
}
// Don't forget to add the first and last vertices...
SPoint3 pt1(getBeginVertex()->x(), getBeginVertex()->y(), getBeginVertex()->z());
SPoint3 pt2(getEndVertex()->x(), getEndVertex()->y(), getEndVertex()->z());

Jean-François Remacle
committed
vertices.push_back(pt1);
vertices.push_back(pt2);
else if(geomType() != DiscreteCurve && geomType() != BoundaryLayerCurve){

Jean-François Remacle
committed
Range<double> tr = this->parBounds(0);
// N can be choosen arbitrarily, but 10 points seems reasonable
int N = 10;
for (int i = 0; i < N; i++) {
double t = tr.low() + (double)i / (double)(N - 1) * (tr.high() - tr.low());

Jean-François Remacle
committed
GPoint p = point(t);
SPoint3 pt(p.x(), p.y(), p.z());

Jean-François Remacle
committed
vertices.push_back(pt);
}
else {
SPoint3 dummy(0, 0, 0);

Jean-François Remacle
committed
vertices.push_back(dummy);
}
_obb = SOrientedBoundingBox::buildOBB(vertices);

Jean-François Remacle
committed
}
return SOrientedBoundingBox(_obb);

Jean-François Remacle
committed
}
void GEdge::setVisibility(char val, bool recursive)
GEntity::setVisibility(val);
if(recursive){
if(v0) v0->setVisibility(val);
if(v1) v1->setVisibility(val);
std::string GEdge::getAdditionalInfoString()
{
if(v0 && v1) sstream << "{" << v0->tag() << " " << v1->tag() << "}";

Christophe Geuzaine
committed
if(meshAttributes.method == MESH_TRANSFINITE)
sstream << " transfinite";
if(meshAttributes.extrude)
sstream << " extruded";
void GEdge::writeGEO(FILE *fp)
{
if(!getBeginVertex() || !getEndVertex() || geomType() == DiscreteCurve) return;
if(geomType() == Line){
fprintf(fp, "Line(%d) = {%d, %d};\n",
tag(), getBeginVertex()->tag(), getEndVertex()->tag());
}
else{
// approximate other curves by splines
Range<double> bounds = parBounds(0);
double umin = bounds.low();
double umax = bounds.high();
fprintf(fp, "p%d = newp;\n", tag());
int N = minimumDrawSegments();
for(int i = 1; i < N; i++){
double u = umin + (double)i / N * (umax - umin);
GPoint p = point(u);
fprintf(fp, "Point(p%d + %d) = {%.16g, %.16g, %.16g};\n",
tag(), i, p.x(), p.y(), p.z());
}
fprintf(fp, "Spline(%d) = {%d", tag(), getBeginVertex()->tag());
fprintf(fp, ", p%d + %d", tag(), i);
fprintf(fp, ", %d};\n", getEndVertex()->tag());
}

Christophe Geuzaine
committed
if(meshAttributes.method == MESH_TRANSFINITE){
fprintf(fp, "Transfinite Line {%d} = %d",
tag() * (meshAttributes.typeTransfinite > 0 ? 1 : -1),
meshAttributes.nbPointsTransfinite);
if(meshAttributes.typeTransfinite){
if(std::abs(meshAttributes.typeTransfinite) == 1)
fprintf(fp, " Using Progression ");
else
fprintf(fp, " Using Bump ");
fprintf(fp, "%g", meshAttributes.coeffTransfinite);
}
fprintf(fp, ";\n");
}

Christophe Geuzaine
committed
if(meshAttributes.reverseMesh)
fprintf(fp, "Reverse Line {%d};\n", tag());
}
bool GEdge::containsParam(double pt) const
{
Range<double> rg = parBounds(0);
return (pt >= rg.low() && pt <= rg.high());
}

Jean-François Remacle
committed
Range<double> rg = parBounds(0);
if (par-eps <= rg.low()){
SVector3 x1 = firstDer(par);
SVector3 x2 = firstDer(par + eps);
return 1000 * (x2 - x1);
}
else if (par+eps >= rg.high()){
SVector3 x1 = firstDer(par-eps);
SVector3 x2 = firstDer(par);
return 1000 * (x2 - x1);
}
SVector3 x1 = firstDer(par - eps);
SVector3 x2 = firstDer(par + eps);
return 500 * (x2 - x1);
Stefen Guzik
committed
SPoint2 GEdge::reparamOnFace(const GFace *face, double epar,int dir) const
// reparametrize the point onto the given face.
const GPoint p3 = point(epar);
SPoint3 sp3(p3.x(), p3.y(), p3.z());
return face->parFromPoint(sp3);
}
SVector3 d1 = firstDer(par);
SVector3 d2 = secondDer(par);
double one_over_norm = 1. / norm(d1);
SVector3 cross_prod = crossprod(d1,d2);
return ( norm(cross_prod) * one_over_norm * one_over_norm * one_over_norm );
double GEdge::length(const double &u0, const double &u1, const int nbQuadPoints)
{
double *t = 0, *w = 0;
gmshGaussLegendre1D(nbQuadPoints, &t, &w);
const double rapJ = (u1 - u0) * .5;
for (int i = 0; i < nbQuadPoints; i++){
const double ui = u0 * 0.5 * (1. - t[i]) + u1 * 0.5 * (1. + t[i]);
SVector3 der = firstDer(ui);
const double d = norm(der);
L += d * w[i] * rapJ;
}
return L;
}
/*
consider a curve x(t) and a point y
use a golden section algorithm that minimizes
min_t \|x(t)-y\|
const double GOLDEN = (1. + sqrt(5.)) / 2.;
// x1 and x3 are the current bounds; the minimum is between them.
// x2 is the center point, which is closer to x1 than to x3
double goldenSectionSearch(const GEdge *ge, const SPoint3 &q, double x1,
// Create a new possible center in the area between x2 and x3, closer to x2
double x4 = x2 + GOLDEN2 * (x3 - x2);
// Evaluate termination criterion
if (fabs(x3 - x1) < tau * (fabs(x2) + fabs(x4)))
return (x3 + x1) / 2;
const SVector3 dp4 = q - ge->position(x4);
const SVector3 dp2 = q - ge->position(x2);
const double d4 = dp4.norm();
const double d2 = dp2.norm();
if (d4 < d2)
return goldenSectionSearch(ge, q, x2, x4, x3, tau);
else
return goldenSectionSearch(ge,q , x4, x2, x1, tau);
}
GPoint GEdge::closestPoint(const SPoint3 &q, double &t) const
// printf("looking for closest point in curve %d to point %g %g\n",tag(),q.x(),q.y());
Range<double> interval = parBounds(0);
double tMin = std::min(interval.high(), interval.low());
double tMax = std::max(interval.high(), interval.low());
double topt = tMin;
const double DT = (tMax - tMin) / (nbSamples - 1.) ;
for (int i = 0; i < nbSamples; i++){
t = tMin + i * DT;
const SVector3 dp = q - position(t);
const double D = dp.norm();
if (D < DMIN) {
topt = t;
DMIN = D;
// printf("parameter %g as an initial guess (dist = %g)\n",topt,DMIN);
t = goldenSectionSearch (this, q, topt, topt + DT/2, topt + DT, 1.e-9);
t = goldenSectionSearch (this, q, topt - DT, topt - DT/2 , topt, 1.e-9);
t = goldenSectionSearch (this, q, topt - DT, topt, topt + DT, 1.e-9);
// const double D = dp.norm();
// printf("after golden section parameter %g (dist = %g)\n",t,D);
return point(t);
}
bool GEdge::computeDistanceFromMeshToGeometry (double &d2, double &dmax)
{
d2 = 0.0; dmax = 0.0;
if (geomType() == Line) return true;
if (!lines.size())return false;
IntPt *pts;
int npts;
lines[0]->getIntegrationPoints(2*lines[0]->getPolynomialOrder(), &npts, &pts);
MLine *l = lines[i];
double t[256];
for (int j=0; j< l->getNumVertices();j++){
MVertex *v = l->getVertex(j);
if (v->onWhat() == getBeginVertex()){
t[j] = getLowerBound();
}
else if (v->onWhat() == getEndVertex()){
t[j] = getUpperBound();
}
else {
v->getParameter(0,t[j]);
}
}
for (int j=0;j<npts;j++){
SPoint3 p;
l->pnt(pts[j].pt[0],0,0,p);
double tinit = l->interpolate(t,pts[j].pt[0],0,0);
GPoint pc = closestPoint(p, tinit);
if (!pc.succeeded())continue;
double dsq =
(pc.x()-p.x())*(pc.x()-p.x()) +
(pc.y()-p.y())*(pc.y()-p.y()) +
(pc.z()-p.z())*(pc.z()-p.z());
d2 += pts[i].weight * fabs(l->getJacobianDeterminant(pts[j].pt[0],0,0)) * dsq;
dmax = std::max(dmax,sqrt(dsq));
}
}
d2 = sqrt(d2);
return true;
}

Christophe Geuzaine
committed
double GEdge::parFromPoint(const SPoint3 &P) const

Christophe Geuzaine
committed
XYZToU(P.x(), P.y(), P.z(), t);
return t;
}
bool GEdge::XYZToU(const double X, const double Y, const double Z,

Christophe Geuzaine
committed
double &u, const double relax) const
{
const int MaxIter = 25;
const int NumInitGuess = 11;
int iter;
Range<double> uu = parBounds(0);
double uMin = uu.low();
double uMax = uu.high();

Christophe Geuzaine
committed
SVector3 Q(X, Y, Z), 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;
iter = 1;
SVector3 dPQ = P - Q;
while(iter++ < MaxIter && err > 1e-8 * CTX::instance()->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);
if(relax > 1.e-2) {
// Msg::Info("point %g %g %g on edge %d : Relaxation factor = %g",

Christophe Geuzaine
committed
return XYZToU(Q.x(), Q.y(), Q.z(), 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;
}
void GEdge::replaceEndingPoints(GVertex *replOfv0, GVertex *replOfv1)
if (replOfv0 != v0){
v0->delEdge(this);
replOfv0->addEdge(this);
v0 = replOfv0;
}
if (replOfv1 != v1){
v1->delEdge(this);
replOfv1->addEdge(this);
v1 = replOfv1;
// regions that bound this entity or that this entity bounds.
std::list<GRegion*> GEdge::regions() const
std::list<GFace*> _faces = faces();
std::list<GFace*>::const_iterator it = _faces.begin();
std::set<GRegion*> _r;
for ( ; it != _faces.end() ; ++it){
std::list<GRegion*> temp = (*it)->regions();
_r.insert (temp.begin(), temp.end());
}
std::list<GRegion*> ret;
ret.insert (ret.begin(), _r.begin(), _r.end());
return ret;
}