Skip to content
Snippets Groups Projects
GEdge.cpp 13.1 KiB
Newer Older
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// See the LICENSE.txt file for license information. Please report all
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// bugs and problems to the public mailing list <gmsh@geuz.org>.
#include <sstream>
#include <algorithm>
#include "GmshConfig.h"
#include "GmshDefines.h"
#include "GmshMessage.h"
#include "GModel.h"
#include "GEdge.h"
#include "GFace.h"
#include "MLine.h"
#include "GaussLegendre1D.h"
#include "Context.h"
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
GEdge::GEdge(GModel *model, int tag, GVertex *_v0, GVertex *_v1)
  : GEntity(model, tag), _tooSmall(false), v0(_v0), v1(_v1), compound(0)
  if(v0) v0->addEdge(this);
  if(v1 && v1 != v0) v1->addEdge(this);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  meshStatistics.status = GEdge::PENDING;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  resetMeshAttributes();
Laurent Van Migroet's avatar
Laurent Van Migroet committed
GEdge::~GEdge()
  if(v0) v0->delEdge(this);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  if(v1 && v1 != v0) v1->delEdge(this);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  deleteMesh();
}
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
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();
  deleteVertexArrays();
  model()->destroyMeshCaches();
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  GVertex* tmp = v0;
  v0 = v1;
  v1 = tmp;
  for(std::vector<MLine*>::iterator line = lines.begin(); line != lines.end(); line++)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
unsigned int GEdge::getNumMeshElements()
Gaetan Bricteux's avatar
Gaetan Bricteux committed
{
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  return lines.size();
}

Gaetan Bricteux's avatar
Gaetan Bricteux committed
unsigned int GEdge::getNumMeshParentElements()
{
  unsigned int n = 0;
  for(unsigned int i = 0; i < lines.size(); i++)
    if(lines[i]->ownsParent())
      n++;
  return n;
}

Stefen Guzik's avatar
Stefen Guzik committed
void GEdge::getNumMeshElements(unsigned *const c) const
{
  c[0] += lines.size();
}

MElement *const *GEdge::getStartElementType(int type) const
{
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  if(lines.empty()) return 0; // msvc would throw an exception
Stefen Guzik's avatar
Stefen Guzik committed
  return reinterpret_cast<MElement *const *>(&lines[0]);
}

Christophe Geuzaine's avatar
Christophe Geuzaine committed
MElement *GEdge::getMeshElement(unsigned int index)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  if(index < lines.size())
    return lines[index];
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  return 0;
}

Laurent Van Migroet's avatar
Laurent Van Migroet committed
void GEdge::resetMeshAttributes()
{
  meshAttributes.method = MESH_UNSTRUCTURED;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  meshAttributes.coeffTransfinite = 0.;
  meshAttributes.nbPointsTransfinite = 0;
  meshAttributes.typeTransfinite = 0;
  meshAttributes.extrude = 0;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  meshAttributes.meshSize = MAX_LC;
  meshAttributes.minimumMeshSegments = 1;
  meshAttributes.reverseMesh = false;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}

Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
void GEdge::addFace(GFace *e)
Laurent Van Migroet's avatar
Laurent Van Migroet committed
{
  if (std::find(l_faces.begin(), l_faces.end(), e) == l_faces.end())
    l_faces.push_back(e);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}

void GEdge::delFace(GFace *e)
Laurent Van Migroet's avatar
Laurent Van Migroet committed
{
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  l_faces.erase(std::find(l_faces.begin(), l_faces.end(), e));
}

SBoundingBox3d GEdge::bounds() const
{
  SBoundingBox3d bbox;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  if(geomType() != DiscreteCurve && geomType() != BoundaryLayerCurve){
    Range<double> tr = parBounds(0);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
    const int N = 10;
    for(int i = 0; i < N; i++){
      double t = tr.low() + (double)i / (double)(N - 1) * (tr.high() - tr.low());
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
      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();
        MVertex* mv = getMeshVertex(i);
        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());
      vertices.push_back(pt1);
      vertices.push_back(pt2);
    else if(geomType() != DiscreteCurve && geomType() != BoundaryLayerCurve){
      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());
        SPoint3 pt(p.x(), p.y(), p.z());
    else {
      SPoint3 dummy(0, 0, 0);
    _obb = SOrientedBoundingBox::buildOBB(vertices);
  return SOrientedBoundingBox(_obb);
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()
{
  std::ostringstream sstream;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  if(v0 && v1) sstream << "{" << v0->tag() << " " << v1->tag() << "}";
  if(meshAttributes.method == MESH_TRANSFINITE)
    sstream << " transfinite";
  if(meshAttributes.extrude)
    sstream << " extruded";

  return sstream.str();
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);
      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());
    for(int i = 1; i < N; i++)
      fprintf(fp, ", p%d + %d", tag(), i);
    fprintf(fp, ", %d};\n", getEndVertex()->tag());
  }
  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");
  }

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

Laurent Van Migroet's avatar
Laurent Van Migroet committed
SVector3 GEdge::secondDer(double par) const
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  // use central differences
  const double eps = 1.e-3;
  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);
  }
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  SVector3 x1 = firstDer(par - eps);
  SVector3 x2 = firstDer(par + eps);
  return 500 * (x2 - x1);
SPoint2 GEdge::reparamOnFace(const GFace *face, double epar,int dir) const
  // reparametrize the point onto the given face.
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  const GPoint p3 = point(epar);
  SPoint3 sp3(p3.x(), p3.y(), p3.z());
  return face->parFromPoint(sp3);
}

Laurent Van Migroet's avatar
Laurent Van Migroet committed
double GEdge::curvature(double par) const
  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 );
Christophe Geuzaine's avatar
Christophe Geuzaine committed
double GEdge::length(const double &u0, const double &u1, const int nbQuadPoints)
{
  double *t = 0, *w = 0;
  gmshGaussLegendre1D(nbQuadPoints, &t, &w);
  double L = 0.0;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  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;
}
Laurent Van Migroet's avatar
Laurent Van Migroet committed

/*
  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.;
const double GOLDEN2 = 2 - GOLDEN;
// 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,
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
                           double x2, double x3, double tau)
  // 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
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // printf("looking for closest point in curve %d to point %g %g\n",tag(),q.x(),q.y());
  const int nbSamples = 100;
  Range<double> interval = parBounds(0);
  double tMin = std::min(interval.high(), interval.low());
  double tMax = std::max(interval.high(), interval.low());

  double DMIN = 1.e22;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  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;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // printf("parameter %g as an initial guess (dist = %g)\n",topt,DMIN);

  if (topt == tMin)
    t = goldenSectionSearch (this, q, topt, topt + DT/2, topt + DT,  1.e-9);
  else if (topt == tMax)
    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 SVector3 dp = q - position(t);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // const double D = dp.norm();
  // printf("after golden section parameter %g  (dist = %g)\n",t,D);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
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);

Christophe Geuzaine's avatar
Christophe Geuzaine committed
  for (unsigned int i = 0; i < lines.size(); i++){
    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;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      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());
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      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;
}

double GEdge::parFromPoint(const SPoint3 &P) const
bool GEdge::XYZToU(const double X, const double Y, const double Z,
{
  const int MaxIter = 25;
  const int NumInitGuess = 11;

Gaetan Bricteux's avatar
Gaetan Bricteux committed
  double err;//, err2;
  int iter;

  Range<double> uu = parBounds(0);
  double uMin = uu.low();
  double uMax = uu.high();

  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;
Gaetan Bricteux's avatar
Gaetan Bricteux committed
    //err2 = 1.0;
Gaetan Bricteux's avatar
Gaetan Bricteux committed
    err = dPQ.norm();
Gaetan Bricteux's avatar
Gaetan Bricteux committed
    if (err < 1.e-8 * CTX::instance()->lc) return true;
Gaetan Bricteux's avatar
Gaetan Bricteux committed
    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);
Gaetan Bricteux's avatar
Gaetan Bricteux committed
      err = dPQ.norm();
      //err2 = fabs(uNew - u);
Gaetan Bricteux's avatar
Gaetan Bricteux committed
    if (err < 1e-8 * CTX::instance()->lc) return true;
    //    Msg::Info("point %g %g %g on edge %d : Relaxation factor = %g",
    //              Q.x(), Q.y(), Q.z(), 0.75 * relax);
    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());
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
void GEdge::replaceEndingPoints(GVertex *replOfv0, GVertex *replOfv1)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  replaceEndingPointsInternals(replOfv0, 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;
}