delaunaytriangulation.cpp
上传用户:chinasdcnc
上传日期:2022-07-02
资源大小:2702k
文件大小:7k
源码类别:

分形几何

开发平台:

Visual C++

  1. //
  2. // Delaunay Triangulation
  3. //
  4. // Homework of CG lesson (Fall 2009) in Tsinghua University.
  5. // All rights reserved.
  6. //
  7. // temp include, delete later if necessary
  8. #include "stdafx.h"
  9. #include "delaunaytriangulation.h"
  10. // C++ headers
  11. #include <cassert>
  12. #include <algorithm>
  13. #include <stack>
  14. // User headers
  15. #include "utility.h"
  16. #include "dcel.h"
  17. using namespace std;
  18. DelaunayTriangulation::DelaunayTriangulation(void)
  19. {
  20.     isFinished = false;
  21.     nPoints = 0;
  22.     points = NULL;
  23. }
  24. Point2d* DelaunayTriangulation::point(int pos) const
  25. {
  26.     assert(pos >= 0 && pos < nPoints);
  27.     return (points + pos);
  28. }
  29. void DelaunayTriangulation::initial(int* count, Point2d* ps)
  30. {
  31.     nPoints = *count;
  32.     points = ps;
  33.     std::sort(points, points + nPoints);
  34.     // Deletes the repeated elements.
  35.     int j = 1;
  36.     for (int i = 1; i < nPoints; ++i)
  37.     {
  38.         if (points[i].x != points[i-1].x || points[i].y != points[i-1].y)
  39.         {
  40.             points[j++] = points[i];
  41.         }
  42.     }
  43.     nPoints = *count = j;
  44.     isFinished = false;
  45. }
  46. void DelaunayTriangulation::destroy(void)
  47. {
  48. if(!maxEdge.le)
  49. {
  50.     return;
  51. }
  52. // collect dcels
  53. vector<DCEL *>dcels;
  54. dcels.clear();
  55. collectDcel(maxEdge.le, dcels);
  56. collectDcel(maxEdge.re, dcels);
  57. // delete the DCEL.
  58. vector<DCEL *>::iterator iter;
  59. for(iter = dcels.begin(); iter != dcels.end(); iter++)
  60.     delete (*iter);
  61.     maxEdge.le = NULL;
  62. maxEdge.re = NULL;
  63. nPoints = 0;
  64.     isFinished = false;
  65.     points = NULL;
  66. }
  67. void DelaunayTriangulation::collectDcel(Edge* e, vector<DCEL*> &dcels)
  68. {
  69.     DCEL *pDcel;
  70. Edge *edge;
  71. std::stack<Edge *>dcelStack;
  72. dcelStack.push(e);
  73. while(!dcelStack.empty())
  74. {
  75. edge = dcelStack.top();
  76. pDcel = (DCEL *)(edge->qEdge());
  77. dcelStack.pop();
  78.     if(!pDcel->visited)
  79. {
  80. dcels.push_back(pDcel);
  81. pDcel->visited = true;
  82. dcelStack.push(edge->oNext());
  83. dcelStack.push(edge->oPrev());
  84. dcelStack.push(edge->dNext());
  85. dcelStack.push(edge->dPrev());
  86. }
  87. }
  88. }
  89. void DelaunayTriangulation::doDelaunayTriangulation(void)
  90. {
  91.     if (nPoints >= 2)
  92.     {
  93.         maxEdge = delaunay(0, nPoints - 1);
  94.         isFinished = true;
  95.     }
  96. }
  97. MaxEdge DelaunayTriangulation::delaunay(int begin, int end)
  98. {
  99.     // the number of points
  100.     int size = end - begin + 1;
  101.     // max edge
  102.     MaxEdge ret;
  103.     // delaunay triangulation
  104.     if(size == 2) // only two points
  105.     {
  106.         // let s1, s2 be two sites in sorted order.
  107.         // create an edge a from s1 to s2
  108.         Edge* a = makeEdge();
  109.         a->endPoints(point(begin), point(end));
  110.         ret.le = a;
  111.         ret.re = a->twin();
  112.         return ret;
  113.     }
  114.     else if(size == 3) // only three points
  115.     {
  116.         // let s1, s2, s3 be the three sites, in sorted order,
  117.         // create edges a connecting s1 to s2 and b connecting s2 to s3
  118.         Edge* a = makeEdge();
  119.         Edge* b = makeEdge();
  120.         splice(a->twin(), b);
  121.         a->endPoints(point(begin), point(begin + 1));
  122.         b->endPoints(point(begin + 1), point(end));
  123.         // close the triangle
  124.         Edge* c;
  125.         if(ccw(*point(begin), *point(begin + 1), *point(end)))
  126.         {
  127.             c = connect(b, a);
  128.             ret.le = a;
  129.             ret.re = b->twin();
  130.             return ret;
  131.         }
  132.         else if(ccw(*point(begin), *point(end), *point(begin + 1)))
  133.         {
  134.             c = connect(b, a);
  135.             ret.le = c->twin();
  136.             ret.re = c;
  137.             return ret;
  138.         }
  139.         else  // the three points are collinear
  140.         {
  141.             ret.le = a;
  142.             ret.re = b->twin();
  143.             return ret;
  144.         }
  145.     }
  146.     else // |sites| >= 4
  147.     {
  148.         Edge *ldo, *ldi; // left half result
  149.         Edge *rdo, *rdi; // right half result
  150.         // recursively delaunay triangulation L and R halves
  151.         MaxEdge leftRet = delaunay(begin, begin + (size / 2) - 1);
  152.         MaxEdge rightRet = delaunay(begin + (size / 2), end);
  153.         ldo = leftRet.le;
  154.         ldi = leftRet.re;
  155.         rdi = rightRet.le;
  156.         rdo = rightRet.re;
  157.         // Compute the lower commom tangent of L and R
  158.         while(1)
  159.         {
  160.             if(leftOf(*(rdi->org()), ldi))
  161.             {
  162.                 ldi = ldi->lNext();
  163.             }
  164.             else if(rightOf(*(ldi->org()), rdi))
  165.             {
  166.                 rdi = rdi->rPrev();
  167.             }
  168.             else
  169.             {
  170.                 break;
  171.             }
  172.         }
  173.         // create a first edge basel from rdi.org to ldi.org
  174.         Edge* basel = connect(rdi->twin(), ldi);
  175.         if((ldi->org()) == (ldo->org()))
  176.         {
  177.             ldo = basel->twin();
  178.         }
  179.         if((rdi->org()) == (rdo->org()))
  180.         {
  181.             rdo = basel;
  182.         }
  183.         // merge
  184.         while(1)
  185.         {
  186.             // locate the first L point (lcand.Dest) to be encountered by the rising bubble
  187.             // and delete L edges out of basel.Dest that fail the circle test
  188.             Edge* lcand = basel->twin()->oNext();
  189.             Edge* t;
  190.             if(valid(lcand, basel))
  191.             {
  192.                 while(inCircle(*(basel->dest()), *(basel->org()), *(lcand->dest()), 
  193.                                *(lcand->oNext()->dest())))
  194.                 {
  195.                     t = lcand->oNext();
  196.                     deleteEdge(lcand);
  197.                     lcand = t;
  198.                 }
  199.             }
  200.             // symmetrically, locate the first R point to be hit, and delete R edges
  201.             Edge* rcand = basel->oPrev();
  202.             if(valid(rcand, basel))
  203.             {
  204.                 while(inCircle(*(basel->dest()), *(basel->org()), *(rcand->dest()), 
  205.                                *(rcand->oPrev()->dest())))
  206.                 {
  207.                     t = rcand->oPrev();
  208.                     deleteEdge(rcand);
  209.                     rcand = t;
  210.                 }
  211.             }
  212.             // if both lcand and rcand are invalid, then basel is the upper common tangent
  213.             if((!valid(lcand, basel)) && (!valid(rcand, basel)))
  214.             {
  215.                 break;
  216.             }
  217.             // the next cross edge is to be connected to either lcand.Dest or rcand.Dest
  218.             // if both are valid, then choose the appropriate one using the inCircle test
  219.             if((!valid(lcand, basel)) || (valid(rcand, basel)
  220.                     && inCircle(*(lcand->dest()), *(lcand->org()),
  221.                                 *(rcand->org()), *(rcand->dest()))))
  222.             {
  223.                 // add cross edge basel from rcand.Dest to basel.Dest
  224.                 basel = connect(rcand, basel->twin());
  225.             }
  226.             else
  227.             {
  228.                 // add cross edge basel from basel.org to lcand.Dest
  229.                 basel = connect(basel->twin(), lcand->twin());
  230.             }
  231.         }
  232.         ret.le = ldo;
  233.         ret.re = rdo;
  234.         return ret;
  235.     }
  236. }