// JL added code to handle transformed case
bool GPolygon::contains(double x, double y) const {
   int crossings = 0;
   int n = vertices.size();
   if (n < 2) return false;
   if (vertices[0] == vertices[n - 1]) n--;
   x = x - getX(); // BUGFIX (JL) - must translate by anchor point
   y = y - getY();
   double x0 = vertices[0].getX();
   double y0 = vertices[0].getY();
   for (int i = 1; i <= n; i++) {
      double x1 = vertices[i % n].getX();
      double y1 = vertices[i % n].getY();
      if (transformed) {
          GPoint pt = matrix.image(x1, y1);
          x1 = pt.getX();
          y1 = pt.getY();
      }
      if ((y0 > y) != (y1 > y) && x - x0 < (x1 - x0) * (y - y0) / (y1 - y0)) {
         crossings++;
      }
      x0 = x1;
      y0 = y1;
   }
   return (crossings % 2 == 1);
}
// use real space + projection at the end
static double _relocateVertex2(GFace *gf, MVertex *ver,
                               const std::vector<MElement *> &lt, double tol)
{
  SPoint3 p1(0, 0, 0);
  std::size_t counter = 0;
  for(std::size_t i = 0; i < lt.size(); i++) {
    for(std::size_t j = 0; j < lt[i]->getNumVertices(); j++) {
      MVertex *v = lt[i]->getVertex(j);
      p1 += SPoint3(v->x(), v->y(), v->z());
      counter++;
    }
  }
  p1 *= 1.0 / (double)counter;
  SPoint3 p2(ver->x(), ver->y(), ver->z());
  double worst;
  double xi = Maximize_Quality_Golden_Section(ver, gf, p1, p2, lt, tol, worst);

  SPoint3 p = p1 * (1 - xi) + p2 * xi;
  double initialGuess[2] = {0, 0};
  GPoint pp = gf->closestPoint(p, initialGuess);
  if(!pp.succeeded()) return 2.0;
  ver->x() = pp.x();
  ver->y() = pp.y();
  ver->z() = pp.z();
  return worst;
}
static double objective_function(double const xi, MVertex *const ver,
                                 GFace *const gf, SPoint3 &p1, SPoint3 &p2,
                                 const std::vector<MElement *> &lt)
{
  double const x = ver->x();
  double const y = ver->y();
  double const z = ver->z();
  SPoint3 p = p1 * (1. - xi) + p2 * xi;

  double initialGuess[2] = {0, 0};

  GPoint pp = gf->closestPoint(p, initialGuess);
  ver->x() = pp.x();
  ver->y() = pp.y();
  ver->z() = pp.z();
  double minQual = 1.0;
  for(std::size_t i = 0; i < lt.size(); i++) {
    if(lt[i]->getNumVertices() == 4)
      minQual = std::min(lt[i]->etaShapeMeasure(), minQual);
    else
      minQual = std::min(std::abs(lt[i]->gammaShapeMeasure()), minQual);
  }
  ver->x() = x;
  ver->y() = y;
  ver->z() = z;
  return minQual;
}
Beispiel #4
0
void frameFieldBackgroundMesh2D::exportCrossField(const std::string &filename)
{
    FILE *f = Fopen(filename.c_str(), "w");
    if(!f) {
        Msg::Error("Could not open file '%s'", filename.c_str());
        return;
    }
    fprintf(f,"View \"Cross Field\"{\n");
    std::vector<double> deltas(2);
    deltas[0] = 0.;
    deltas[1] = M_PI;

    for (std::vector<MVertex*>::iterator it = beginvertices(); it!=endvertices(); it++) {
        MVertex *v = *it;
        double angle_current = angle(v);
        GPoint p = get_GPoint_from_MVertex(v);
        for (int i=0; i<2; i++) {
            Pair<SVector3, SVector3> dirs = compute_crossfield_directions(v->x(),v->y(),angle_current+deltas[i]);
            fprintf(f,"VP(%g,%g,%g) {%g,%g,%g};\n",p.x(),p.y(),p.z(),dirs.first()[0], dirs.first()[1], dirs.first()[2]);
            fprintf(f,"VP(%g,%g,%g) {%g,%g,%g};\n",p.x(),p.y(),p.z(),dirs.second()[0], dirs.second()[1], dirs.second()[2]);
        }
    }
    fprintf(f,"};\n");
    fclose(f);
}
Beispiel #5
0
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);
}
Beispiel #6
0
SOrientedBoundingBox GEdge::getOBB()
{
  if (!_obb) {
    std::vector<SPoint3> vertices;
    if(getNumMeshVertices() > 0) {
      int N = getNumMeshVertices();
      for (int i = 0; i < N; i++) {
        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());
        GPoint p = point(t);
        SPoint3 pt(p.x(), p.y(), p.z());
        vertices.push_back(pt);
      }
    }
    else {
      SPoint3 dummy(0, 0, 0);
      vertices.push_back(dummy);
    }
    _obb = SOrientedBoundingBox::buildOBB(vertices);
  }
  return SOrientedBoundingBox(_obb);
}
Beispiel #7
0
/*
 * Function: horizontallyDisplacedPoint
 * Usage: points.insert(2*i+1, horizontallyDisplacedPoint(points[2*i], points[2*i+1], order));
 * --------------------------
 * Like randomClosePoint, but only displaced the point in the x direction.
 */
GPoint horizontallyDisplacedPoint(GPoint a, GPoint b, int order, double deformation){
    double xAve = (a.getX()+b.getX())/2;
    double yAve = (a.getY()+b.getY())/2;
    double deform = deformation/exp(LIGHTNING_ORDER-order);
    double x = randomReal((1-deform)*xAve, (1+deform)*xAve);
    return GPoint(x,yAve);
}
void GPostscriptPort::DrawCircle (const GPoint &pt, const int radius)
{
    PostscriptStream << "newpath" << std::endl;
    PostscriptStream << pt.GetX() << " " << -pt.GetY() << " " << radius << " 0 360 arc" 		<< std::endl;
    PostscriptStream << "stroke" 										<< std::endl;
    PostscriptStream << std::endl;
}
GeoJSONPoint::GeoJSONPoint()
{
  GPoint point;
  point.set(38.91318805974, -77.03238901);
  Wt::Json::Object properties;
  properties["title"] = Wt::WString("Mapbox DC");
  properties["icon"] = Wt::WString("monument");

  GFeature feature1;
  feature1.geometry(point);
  feature1.properties(properties);

  point.set(37.776, -122.414);
  properties["title"] = Wt::WString("Mapbox SF");
  properties["icon"] = Wt::WString("harbor");

  GFeature feature2;
  feature2.geometry(point);
  feature2.properties(properties);

  featureCollection.add(feature1);
  featureCollection.add(feature2);

  source.set(&featureCollection);

  layer.set(&source);
  layer.icon.image("{icon}-15").size(2);
  layer.text.label("{title}")
            .font("['Open Sans Semibold', 'Arial Unicode MS Bold']")
            .offset(Coordinate(1.6, 0))
            .textAnchor(TEXT_ANCHOR::Top);


}
Beispiel #10
0
/*
 * Function: verticallyDisplacedPoint
 * Usage: points.insert(2*i+1, verticallyDisplacedPoint(points[2*i], points[2*i+1], order));
 * --------------------------
 * Like randomClosePoint, but only displaced the point in the y direction.
 */
GPoint verticallyDisplacedPoint(GPoint a, GPoint b, int order){
    double xAve = (a.getX()+b.getX())/2;
    double yAve = (a.getY()+b.getY())/2;
    double deform = BACK_MOUNTAIN_DEFORMATION/exp(BACK_MOUNTAIN_ORDER-order);
    double y = randomReal((1-deform)*yAve, (1+deform)*yAve);
    return GPoint(xAve,y);
}
Beispiel #11
0
void copyMesh(GEdge *from, GEdge *to, int direction)
{  
  Range<double> u_bounds = from->parBounds(0);
  double u_min = u_bounds.low();
  double u_max = u_bounds.high();

  Range<double> to_u_bounds = to->parBounds(0);
  double to_u_min = to_u_bounds.low();
  double to_u_max = to_u_bounds.high();

  for(unsigned int i = 0; i < from->mesh_vertices.size(); i++){
    int index = (direction < 0) ? (from->mesh_vertices.size() - 1 - i) : i;
    MVertex *v = from->mesh_vertices[index];
    double u; v->getParameter(0, u);
    double newu = (direction > 0) ? (u-u_min+to_u_min) : (u_max-u+to_u_min);
    GPoint gp = to->point(newu);
    MEdgeVertex *vv = new MEdgeVertex(gp.x(), gp.y(), gp.z(), to, newu);
    to->mesh_vertices.push_back(vv);
    to->correspondingVertices[vv] = v;
  }
  for(unsigned int i = 0; i < to->mesh_vertices.size() + 1; i++){
    MVertex *v0 = (i == 0) ?
      to->getBeginVertex()->mesh_vertices[0] : to->mesh_vertices[i - 1];
    MVertex *v1 = (i == to->mesh_vertices.size()) ?
      to->getEndVertex()->mesh_vertices[0] : to->mesh_vertices[i];
    to->lines.push_back(new MLine(v0, v1));
  }
}
// added by JL
bool GImage::contains(double x, double y) const {
    GPoint p = matrix.preimage(x - this->x, y - this->y);
    double xx = p.getX();
    double yy = p.getY();
    return 0 < xx && xx <= width
        &&  0 < yy && yy <= height;
}
Beispiel #13
0
void BGMBase::export_vector(const std::string &filename,
                            const VectorStorageType &_whatToPrint) const
{
  FILE *f = Fopen(filename.c_str(), "w");
  if(!f) {
    Msg::Error("Could not open file '%s'", filename.c_str());
    return;
  }

  fprintf(f, "View \"Background Mesh\"{\n");

  const MElement *elem;
  int nvertex;
  int type;

  for(unsigned int i = 0; i < getNumMeshElements(); i++) {
    elem = getElement(i);
    nvertex = elem->getNumVertices();
    type = elem->getType();
    const char *s = 0;
    switch(type) {
    case TYPE_PNT: s = "VP"; break;
    case TYPE_LIN: s = "VL"; break;
    case TYPE_TRI: s = "VT"; break;
    case TYPE_QUA: s = "VQ"; break;
    case TYPE_TET: s = "VS"; break;
    case TYPE_HEX: s = "VH"; break;
    case TYPE_PRI: s = "VI"; break;
    case TYPE_PYR: s = "VY"; break;
    default: throw;
    }

    fprintf(f, "%s(", s);
    const MVertex *v;
    std::vector<double> values(nvertex * 3);
    for(int iv = 0; iv < nvertex; iv++) {
      v = elem->getVertex(iv);
      std::vector<double> temp = get_nodal_value(v, _whatToPrint);
      for(int j = 0; j < 3; j++) values[iv * 3 + j] = temp[j];
      GPoint p = get_GPoint_from_MVertex(v);
      fprintf(f, "%g,%g,%g", p.x(), p.y(), p.z());
      if(iv != nvertex - 1)
        fprintf(f, ",");
      else
        fprintf(f, "){");
    }
    for(int iv = 0; iv < nvertex; iv++) {
      for(int j = 0; j < 3; j++) {
        fprintf(f, "%g", values[iv * 3 + j]);
        if(!((iv == nvertex - 1) && (j == 2)))
          fprintf(f, ",");
        else
          fprintf(f, "};\n");
      }
    }
  }
  fprintf(f, "};\n");
  fclose(f);
}
void drawTriangle_by_center(const GPoint& center, const double& len) {
	double center_x = center.getX();
	double center_y = center.getY();
	GPoint a(center_x-len/2, center_y-SQRT3/6*len);
	GPoint b(center_x+len/2, center_y-SQRT3/6*len);
	GPoint c(center_x, center_y+SQRT3/3*len);
	drawTriangle(a, b, c);
}
GLine::GLine(const GPoint& p0, const GPoint& p1) {
    stanfordcpplib::getPlatform()->gline_constructor(
                this, p0.getX(), p0.getY(), p1.getX(), p1.getY());
    x = p0.getX();
    y = p0.getY();
    dx = p1.getX() - p0.getX();
    dy = p1.getY() - p1.getY();
}
Beispiel #16
0
void BGMBase::export_scalar(const std::string &filename,
                            const DoubleStorageType &_whatToPrint) const
{
  FILE *f = Fopen(filename.c_str(), "w");
  if(!f) {
    Msg::Error("Could not open file '%s'", filename.c_str());
    return;
  }

  fprintf(f, "View \"Background Mesh\"{\n");

  const MElement *elem;
  int nvertex;
  int type;

  for(unsigned int i = 0; i < getNumMeshElements(); i++) {
    elem = getElement(i);
    nvertex = elem->getNumVertices();
    type = elem->getType();
    const char *s = 0;
    switch(type) {
    case TYPE_PNT: s = "SP"; break;
    case TYPE_LIN: s = "SL"; break;
    case TYPE_TRI: s = "ST"; break;
    case TYPE_QUA: s = "SQ"; break;
    case TYPE_TET: s = "SS"; break;
    case TYPE_HEX: s = "SH"; break;
    case TYPE_PRI: s = "SI"; break;
    case TYPE_PYR: s = "SY"; break;
    default: throw;
    }

    fprintf(f, "%s(", s);
    const MVertex *v;
    std::vector<double> values(nvertex);
    for(int iv = 0; iv < nvertex; iv++) {
      v = elem->getVertex(iv);
      values[iv] = get_nodal_value(v, _whatToPrint);
      // GPoint p = gf->point(SPoint2(v->x(),v->y()));
      GPoint p = get_GPoint_from_MVertex(v);
      fprintf(f, "%g,%g,%g", p.x(), p.y(), p.z());
      if(iv != nvertex - 1)
        fprintf(f, ",");
      else
        fprintf(f, "){");
    }
    for(int iv = 0; iv < nvertex; iv++) {
      fprintf(f, "%g", values[iv]);
      if(iv != nvertex - 1)
        fprintf(f, ",");
      else
        fprintf(f, "};\n");
    }
  }
  fprintf(f, "};\n");
  fclose(f);
}
void drawPathfinderNode(GPoint center, string color, string label) {
   setColor(color);
   fillCircle(center.getX(), center.getY(), NODE_RADIUS);
   if (!label.empty()) {
      setFont(LABEL_FONT);
      drawString(label, center.getX() + NODE_RADIUS + 2,
                        center.getY() + 5);
   }
}
// JL added
bool GLabel::contains(double x, double y) const {
   x -= this->x;
   y -= this->y;
   if (transformed) {
       GPoint pt = matrix.preimage(x, y);
       x = pt.getX();
       y = pt.getY();
   }
   return 0 <= x && x <= width && -ascent <= y && y <= -ascent + height;
}
Beispiel #19
0
SVector3 gmshFace::normal(const SPoint2 &param) const
{
  if(s->Typ != MSH_SURF_PLAN){
    Vertex vu = InterpolateSurface(s, param[0], param[1], 1, 1);
    Vertex vv = InterpolateSurface(s, param[0], param[1], 1, 2);
    Vertex n = vu % vv;
    n.norme();
    return SVector3(n.Pos.X, n.Pos.Y, n.Pos.Z);
  }
  else{
    // We cannot use InterpolateSurface() for plane surfaces since it
    // relies on the mean plane, which does not respect the
    // orientation

    // FIXME: move this test at the end of the MeanPlane computation
    // routine--and store the correct normal, damn it!

    double n[3] = {meanPlane.a, meanPlane.b, meanPlane.c};
    norme(n);
    GPoint pt = point(param.x(), param.y());
    double v[3] = {pt.x(), pt.y(), pt.z()};
    int NP = 10, tries = 0;
    while(1){
      tries++;
      double angle = 0.;
      for(int i = 0; i < List_Nbr(s->Generatrices); i++) {
        Curve *c;
        List_Read(s->Generatrices, i, &c);
        int N = (c->Typ == MSH_SEGM_LINE) ? 1 : NP;
        for(int j = 0; j < N; j++) {
          double u1 = (double)j / (double)N;
          double u2 = (double)(j + 1) / (double)N;
          Vertex p1 = InterpolateCurve(c, u1, 0);
          Vertex p2 = InterpolateCurve(c, u2, 0);
          double v1[3] = {p1.Pos.X, p1.Pos.Y, p1.Pos.Z};
          double v2[3] = {p2.Pos.X, p2.Pos.Y, p2.Pos.Z};
          angle += angle_plan(v, v1, v2, n);
        }
      }
      if(fabs(angle) < 0.5){ // we're outside
        NP *= 2;
        Msg::Debug("Could not compute normal of surface %d - retrying with %d points",
                   tag(), NP);
        if(tries > 10){
          Msg::Warning("Could not orient normal of surface %d", tag());
          return SVector3(n[0], n[1], n[2]);
        }
      }
      else if(angle > 0)
        return SVector3(n[0], n[1], n[2]);
      else
        return SVector3(-n[0], -n[1], -n[2]);
    }
  }
}
bool GOval::contains(double x, double y) const {
   GPoint p = matrix.preimage(x - this->x, y - this->y);
   double xx = p.getX();
   double yy = p.getY();
   double rx = width / 2;
   double ry = height / 2;
   if (rx == 0 || ry == 0) return false;
   double dx = xx - rx;
   double dy = yy - ry;
   return (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry) <= 1.0;
}
Beispiel #21
0
void GPostscriptPort::DrawArc (const GPoint &pt, const int radius,
	const double startAngleDegrees, const double endAngleDegrees)
{
    PostscriptStream << "newpath" << std::endl;
	PostscriptStream << pt.GetX() << " " << -pt.GetY()
    	<< " " << radius
        << " " << (360.0 -startAngleDegrees)
        << " " << (360.0 - endAngleDegrees)
        << " arcn" 		<< std::endl;
    PostscriptStream << "stroke" 										<< std::endl;
    PostscriptStream << std::endl;
}
Beispiel #22
0
void GPostscriptPort::FillCircle (const GPoint &pt, const int radius)
{
    PostscriptStream << "newpath" << std::endl;
    PostscriptStream << pt.GetX() << " " << -pt.GetY() << " " << radius << " 0 360 arc" 		<< std::endl;
	//PostscriptStream << "gsave" 										<< endl;
	//PostscriptStream << "0.90 setgray" 										<< endl;
    PostscriptStream << fill_r << " " << fill_g << " " <<  fill_b << " setrgbcolor" 										<< std::endl;
	
    PostscriptStream << "fill" 										<< std::endl;
	//PostscriptStream << "grestore" 										<< endl;
    PostscriptStream << std::endl;
}
// JL rewrote to include transformed case in front end
GRectangle GLine::getBounds() const {
   double tdx = dx;
   double tdy = dy;
   if (transformed) {
       GPoint pt = matrix.image(dx, dy);
       tdx = pt.getX();
       tdy = pt.getY();
   }
   double x0 = (tdx < 0) ? x + tdx : x;
   double y0 = (tdy < 0) ? y + tdy : y;
   return GRectangle(x0, y0, abs(tdx), abs(tdy));
}
Beispiel #24
0
void splitEdgePass(GFace *gf, BDS_Mesh &m, double MAXE_, int &nb_split)
{
  std::list<BDS_Edge*>::iterator it = m.edges.begin();
  std::vector<std::pair<double, BDS_Edge*> > edges;

  while (it != m.edges.end()){
    if(!(*it)->deleted && (*it)->numfaces() == 2){
      double lone = NewGetLc(*it, gf, m.scalingU, m.scalingV);
      if(lone > MAXE_){
        edges.push_back(std::make_pair(-lone, *it));
      }
    }
    ++it;
  }

  std::sort(edges.begin(), edges.end());

  for (unsigned int i = 0; i < edges.size(); ++i){
    BDS_Edge *e = edges[i].second;
    if (!e->deleted){
      const double coord = 0.5;
      BDS_Point *mid ;
      double U, V;
      U = coord * e->p1->u + (1 - coord) * e->p2->u;
      V = coord * e->p1->v + (1 - coord) * e->p2->v;

      GPoint gpp = gf->point(m.scalingU*U,m.scalingV*V);
      if (gpp.succeeded()){
        mid  = m.add_point(++m.MAXPOINTNUMBER, gpp.x(),gpp.y(),gpp.z());
        mid->u = U;
        mid->v = V;
        if (backgroundMesh::current() && 0){
          mid->lc() = mid->lcBGM() =
            backgroundMesh::current()->operator()
            ((coord * e->p1->u + (1 - coord) * e->p2->u)*m.scalingU,
             (coord * e->p1->v + (1 - coord) * e->p2->v)*m.scalingV,
             0.0);
        }
        else {
          mid->lcBGM() = BGM_MeshSize
            (gf,
             (coord * e->p1->u + (1 - coord) * e->p2->u)*m.scalingU,
             (coord * e->p1->v + (1 - coord) * e->p2->v)*m.scalingV,
             mid->X,mid->Y,mid->Z);
	  mid->lc() = 0.5 * (e->p1->lc() +  e->p2->lc());
        }
        if(!m.split_edge(e, mid)) m.del_point(mid);
        else nb_split++;
      }
    }
  }
}
Beispiel #25
0
/*
 * Function: drawBranch
 * Usage: drawBranch(gw, branchStart, GPoint(width*(xMult-.15), height*(yMult-.15)), BRANCH_THICKNESS);
 * --------------------------
 * Draws branches that continue and branch of probabilistically.
 */
void drawBranch(GWindow gw, GPoint start, GPoint finish, double width){
    GPolygon *branch = branchPolygon(start, finish, width);
    branch->setFilled(true);
    branch->setColor(4270639);
    gw.add(branch);
    Vector<GPoint> points = branch->getVertices();
    start = points[points.size()/4];
    double endX = randomReal(start.getX()*(1-TREE_DEFORMATION), start.getX()*(1+TREE_DEFORMATION));
    double endY = randomReal(1+TREE_DEFORMATION, 1+2*TREE_DEFORMATION)*(finish.getY()-start.getY())+start.getY();
    if((endY-finish.getY())<-3){
        drawBranch(gw, start,GPoint(endX, endY),width/2);
    }
}
Beispiel #26
0
void GEdge::relocateMeshVertices()
{
  for(unsigned int i = 0; i < mesh_vertices.size(); i++){
    MVertex *v = mesh_vertices[i];
    double u0 = 0;
    if(v->getParameter(0, u0)){
      GPoint p = point(u0);
      v->x() = p.x();
      v->y() = p.y();
      v->z() = p.z();
    }
  }
}
Beispiel #27
0
static void fillPointCloud(GEdge *ge, double sampling, std::vector<SPoint3> &points)
{
  Range<double> t_bounds = ge->parBounds(0);
  double t_min = t_bounds.low();
  double t_max = t_bounds.high();
  double length = ge->length(t_min, t_max, 20);
  int N = length / sampling;
  for(int i = 0; i < N; i++) {
    double t = t_min + (double)i / (double)(N - 1) * (t_max - t_min);
    GPoint p = ge->point(t);
    points.push_back(SPoint3(p.x(), p.y(), p.z()));
  }
}
// JL rewrote to handle transformed case
bool GCompound::contains(double x, double y) const {
   x -= this->x;
   y -= this->y;
   if (transformed) {
       GPoint pt = matrix.preimage(x, y);
       x = pt.getX();
       y = pt.getY();
   }
   for (int i = 0; i < contents.size(); i++) {
       if (contents.get(i)->contains(x, y)) return true;
   }
   return false;
}
Beispiel #29
0
inline double computeEdgeLinearLength(BDS_Point *p1, BDS_Point *p2, GFace *f,
                                      double SCALINGU, double SCALINGV)
{
  // FIXME SUPER HACK
   // if (CTX::instance()->mesh.recombineAll || f->meshAttributes.recombine || 1){
   //   double quadAngle  = backgroundMesh::current()->getAngle (0.5 * (p1->u + p2->u) * SCALINGU, 0.5 * (p1->v + p2->v) * SCALINGV,0);
   //   const double a [2] = {p1->u,p1->v};
   //   const double b [2] = {p2->u,p2->v};
   //   return lengthInfniteNorm(a,b, quadAngle);
   // }

  GPoint GP = f->point(SPoint2(0.5 * (p1->u + p2->u) * SCALINGU,
                               0.5 * (p1->v + p2->v) * SCALINGV));

  if (!GP.succeeded())
    return computeEdgeLinearLength(p1,p2);

  const double dx1 = p1->X - GP.x();
  const double dy1 = p1->Y - GP.y();
  const double dz1 = p1->Z - GP.z();
  const double l1 = sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);
  const double dx2 = p2->X - GP.x();
  const double dy2 = p2->Y - GP.y();
  const double dz2 = p2->Z - GP.z();
  const double l2 = sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
  return l1 + l2;
}
void drawSierpinski(const GPoint& center, const double& len, const int& order) {
	drawTriangle_by_center(center, len);
	int new_order = order-1;
	if (new_order > 0) {
		double center_x = center.getX();
		double center_y = center.getY();
		GPoint center_a(center_x-len/2, center_y+SQRT3/6*len);
		GPoint center_b(center_x+len/2, center_y+SQRT3/6*len);
		GPoint center_c(center_x, center_y-SQRT3/3*len);
		drawSierpinski(center_a, len/2, new_order);
		drawSierpinski(center_b, len/2, new_order);
		drawSierpinski(center_c, len/2, new_order);
	}
}