Как перенести алгоритм триангуляции 2D-полигонов в 3D? - PullRequest
0 голосов
/ 03 октября 2018

Я пришел по коду в этой ссылке: 2D триангуляция Джона Рэтклиффа .Код представляет алгоритм триангуляции в C ++ для 2D полигонов.Я пытался перенести его на 3D полигоны, но безуспешно.Как я могу изменить этот код, чтобы он использовал трехмерные плоские многоугольники?Я знаю, что могу использовать проекцию, но есть ли способ сделать 3D-версию кода, указанного выше?Благодарю.NB: Ниже моя попытка портирования.

double Triangulate::Area(const std::vector<int> &poly)
{

  int n = poly.size();

  if (n < 3) // not a plane - no area
        return 0;

  std::vector<double> total = {0, 0, 0};
  int vi1, vi2;
  std::vector<double> prod;
  std::vector<double> v1, v2, v3;
  double* point = NULL;
  for(int i = 0; i < n; i++){
        v1.clear();
        v2.clear();
        vi1 = poly[i];
        if (i == n-1)
            vi2 = poly[0];
        else
            vi2 = poly[i+1];
        point = input.GetPoint(vi1);
        v1.insert(v1.begin(), point, point+3);

        point = input.GetPoint(vi2);
        v2.insert(v2.begin(), point, point+3);

        prod = Cross(v1, v2);
        total[0] += prod[0];
        total[1] += prod[1];
        total[2] += prod[2];
    }
    v1.clear();
    v2.clear();
    v3.clear();
    point = input.GetPoint(poly[0]);
    v1.insert(v1.begin(), point, point+3);

    point = input.GetPoint(poly[1]);
    v2.insert(v2.begin(), point, point+3);

    point = input.GetPoint(poly[2]);
    v3.insert(v3.begin(), point, point+3);

    double result = Dot(total, UnitNormal(v1, v2, v3));
    return result/2;
}

bool Triangulate::SameSide(double P1x,  double P1y, double P1z, 
                    double P2x,  double P2y, double P2z,
                    double Ax,  double Ay, double Az,
                    double Bx,  double By, double Bz){
    double ABx, ABy, ABz, AP1x, AP1y, AP1z,
        AP2x, AP2y, AP2z;

    double cp1x, cp1y, cp1z, cp2x, cp2y, cp2z;

    double dot;
    std::vector<double> AB = {Bx - Ax, By - Ay, Bz - Az};

    std::vector<double> AP1 = {P1x - Ax,P1y - Ay,  P1z - Az};

    std::vector<double> AP2 = {P2x - Ax, P2y - Ay, P2z - Az};

    std::vector<double> cp1 = Cross(AB, AP1);
    std::vector<double> cp2 = Cross(AB, AP2);

    dot = Dot(cp1, cp2);

   return (dot >= 0);
}

   /*
     InsideTriangle decides if a point P is Inside of the triangle
     defined by A, B, C.
   */
bool Triangulate::InsideTriangle(double Ax, double Ay, double Az,
                      double Bx, double By, double Bz,
                      double Cx, double Cy, double Cz,
                      double Px, double Py, double Pz)

{
    return SameSide(Px, Py, Pz, Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz) 
      || SameSide(Px, Py, Pz, Bx, By, Bz, Ax, Ay, Az, Cx, Cy, Cz) 
      || SameSide(Px, Py, Pz, Cx, Cy, Cz, Ax, Ay, Az, Bx, By, Bz) ;
}

bool Triangulate::Snip(const std::vector<int> &contour,
   int u,int v,int w,int n,int *V)
{
  int p;
  double Ax, Ay,Az, Bx, By,Bz, Cx, Cy, Cz, Px, Py, Pz;
  double BAx, BAy, BAz, CAx, CAy, CAz;

  Ax = input.GetPoint(V[u])[X];
  Ay = input.GetPoint(V[u])[Y];
  Az = input.GetPoint(V[u])[Z];

  Bx = input.GetPoint(V[v])[X];
  By = input.GetPoint(V[v])[Y];
  Bz = input.GetPoint(V[v])[Z];

  Cx = input.GetPoint(V[w])[X];
  Cy = input.GetPoint(V[w])[Y];
  Cz = input.GetPoint(V[w])[Z];

  BAx = Bx-Ax;
  BAy = By - Ay;
  BAz = Bz - Az;

  CAx = Cx-Ax;
  CAy = Cy - Ay;
  CAz = Cz - Az;

  if ( EPSILON > ( (BAy*CAz-BAz*CAy)*(BAy*CAz-BAz*CAy)+ 
   (BAx*CAz-BAz*CAx)*(BAx*CAz-BAz*CAx) +
   (BAx*CAy-BAy*CAx)*(BAx*CAy-BAy*CAx))  ) return false;

  for (p=0;p<n;p++)
  {
    if( (p == u) || (p == v) || (p == w) ) continue;
    Px = input.GetPoint(V[p])[X];
    Py = input.GetPoint(V[p])[Y];
    Pz = input.GetPoint(V[p])[Z];

    if (InsideTriangle(Ax,Ay,Az,Bx,By,Bz,Cx,Cy,Cz,Px,Py,Pz)) return false;
  }

  return true;
}

int Triangulate::Process(const std::vector<int> &contour,
std::vector<std::vector<int>> &result)
{
  /* allocate and initialize list of Vertices in polygon */

  int n = contour.size();
  if ( n < 3 ) {
    LOG_VAL("Cannot happen: contour is a line", "")
   return 0;
  }

  int *V = new int[n];

  /* we want a counter-clockwise polygon in V */

  if ( 0.0f < Area(contour) )
    for (int v=0; v<n; v++) V[v] = v;
  else
    for(int v=0; v<n; v++) V[v] = (n-1)-v;

  int nv = n;

  /*  remove nv-2 Vertices, creating 1 triangle every time */
  int count = 2*nv;   /* error detection */
  std::vector<int> tri;
  int trinum = 0;

  for(int m=0, v=nv-1; nv>2; )
  {
    /* if we loop, it is probably a non-simple polygon */
    if (0 >= (count--))
    {
      //** Triangulate: ERROR - probable bad polygon!
      LOG_VAL("Bad polygon:", trinum)
      return trinum;
    }

    /* three consecutive vertices in current polygon, <u,v,w> */
    int u = v  ; if (nv <= u) u = 0;     /* previous */
    v = u+1; if (nv <= v) v = 0;     /* new v    */
    int w = v+1; if (nv <= w) w = 0;     /* next     */

    if ( Snip(contour,u,v,w,nv,V) )
    {
      int a,b,c,s,t;

      /* true names of the vertices */
      a = V[u]; b = V[v]; c = V[w];

      /* output Triangle */
      tri.clear();
      tri.push_back( contour[a] );
      tri.push_back( contour[b] );
      tri.push_back( contour[c] );
      result.push_back(tri);
      trinum++;

      m++;

      /* remove v from remaining polygon */
      for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--;

      /* resest error detection counter */
      count = 2*nv;
    }
  }



  delete V;

  if(result.size() < 1){
      LOG_VAL("Result Is Empty:", "")
      exit(1);
  }

  return trinum;
}
...