📄 delaunay.cpp
字号:
r = 0;
}
return r;
}
// Algorithm Insert(DT(a,b,c,v1,v2,...,vi-1), vi)
// 1.find the triangle vavbvc which contains vi // FindTriangle()
// 2.if (vi located at the interior of vavbvc)
// 3. then add triangle vavbvi, vbvcvi and vcvavi into DT // UpdateDT()
// FlipTest(DT, va, vb, vi)
// FlipTest(DT, vb, vc, vi)
// FlipTest(DT, vc, va, vi)
// 4.else if (vi located at one edge (E.g. edge vavb) of vavbvc)
// 5. then add triangle vavivc, vivbvc, vavdvi and vivdvb into DT (here, d is the third vertex of triangle which contains edge vavb) // UpdateDT()
// FlipTest(DT, va, vd, vi)
// FlipTest(DT, vc, va, vi)
// FlipTest(DT, vd, vb, vi)
// FlipTest(DT, vb, vc, vi)
// 6.return DT(a,b,c,v1,v2,...,vi)
void Insert(MESH_PTR pMesh, int ver_index)
{
VERTEX2D_PTR pVer = (VERTEX2D_PTR)(pMesh->pVerArr+ver_index);
TRIANGLE_PTR pTargetTri = NULL;
TRIANGLE_PTR pEqualTri1 = NULL;
TRIANGLE_PTR pEqualTri2 = NULL;
int j = 0;
TRIANGLE_PTR pTri = pMesh->pTriArr;
while (pTri != NULL)
{
REAL r = InTriangle(pMesh, pVer, pTri);
if(r > 0) // should be in triangle
{
pTargetTri = pTri;
}
else if (r == 0) // should be on edge
{
if(j == 0)
{
pEqualTri1 = pTri;
j++;
}
else
{
pEqualTri2 = pTri;
}
}
pTri = pTri->pNext;
}
if (pEqualTri1 != NULL && pEqualTri2 != NULL)
{
InsertOnEdge(pMesh, pEqualTri1, ver_index);
InsertOnEdge(pMesh, pEqualTri2, ver_index);
}
else
{
InsertInTriangle(pMesh, pTargetTri, ver_index);
}
}
void InsertInTriangle(MESH_PTR pMesh, TRIANGLE_PTR pTargetTri, int ver_index)
{
int index_a, index_b, index_c;
TRIANGLE_PTR pTri = NULL;
TRIANGLE_PTR pNewTri = NULL;
pTri = pTargetTri;
if(pTri == NULL)
{
return;
}
// Inset p into target triangle
index_a = pTri->i1;
index_b = pTri->i2;
index_c = pTri->i3;
// Insert edge pa, pb, pc
for(int i=0; i<3; i++)
{
// allocate memory
if(i == 0)
{
pNewTri = AddTriangleNode(pMesh, pTri, index_a, index_b, ver_index);
}
else if(i == 1)
{
pNewTri = AddTriangleNode(pMesh, pTri, index_b, index_c, ver_index);
}
else
{
pNewTri = AddTriangleNode(pMesh, pTri, index_c, index_a, ver_index);
}
// go to next item
if (pNewTri != NULL)
{
pTri = pNewTri;
}
else
{
pTri = pTri;
}
}
// Get the three sub-triangles
pTri = pTargetTri;
TRIANGLE_PTR pTestTri[3];
for (int i=0; i< 3; i++)
{
pTestTri[i] = pTri->pNext;
pTri = pTri->pNext;
}
// remove the Target Triangle
RemoveTriangleNode(pMesh, pTargetTri);
for (int i=0; i< 3; i++)
{
// Flip test
FlipTest(pMesh, pTestTri[i]);
}
}
void InsertOnEdge(MESH_PTR pMesh, TRIANGLE_PTR pTargetTri, int ver_index)
{
int index_a, index_b, index_c;
TRIANGLE_PTR pTri = NULL;
TRIANGLE_PTR pNewTri = NULL;
pTri = pTargetTri;
if(pTri == NULL)
{
return;
}
// Inset p into target triangle
index_a = pTri->i1;
index_b = pTri->i2;
index_c = pTri->i3;
// Insert edge pa, pb, pc
for(int i=0; i<3; i++)
{
// allocate memory
if(i == 0)
{
pNewTri = AddTriangleNode(pMesh, pTri, index_a, index_b, ver_index);
}
else if(i == 1)
{
pNewTri = AddTriangleNode(pMesh, pTri, index_b, index_c, ver_index);
}
else
{
pNewTri = AddTriangleNode(pMesh, pTri, index_c, index_a, ver_index);
}
// go to next item
if (pNewTri != NULL)
{
pTri = pNewTri;
}
else
{
pTri = pTri;
}
}
// Get the two sub-triangles
pTri = pTargetTri;
TRIANGLE_PTR pTestTri[2];
for (int i=0; i< 2; i++)
{
pTestTri[i] = pTri->pNext;
pTri = pTri->pNext;
}
// remove the Target Triangle
RemoveTriangleNode(pMesh, pTargetTri);
for (int i=0; i< 2; i++)
{
// Flip test
FlipTest(pMesh, pTestTri[i]);
}
}
// Precondition: the triangle satisfies CCW order
// Algorithm FlipTest(DT(a,b,c,v1,v2,...,vi), va, vb, vi)
// 1.find the third vertex (vd) of triangle which contains edge vavb // FindThirdVertex()
// 2.if(vi is in circumcircle of abd) // InCircle()
// 3. then remove edge vavb, add new edge vivd into DT // UpdateDT()
// FlipTest(DT, va, vd, vi)
// FlipTest(DT, vd, vb, vi)
bool FlipTest(MESH_PTR pMesh, TRIANGLE_PTR pTestTri)
{
bool flipped = false;
int index_a = pTestTri->i1;
int index_b = pTestTri->i2;
int index_p = pTestTri->i3;
int statify[3]={0,0,0};
int vertex_index;
int* pi;
int k = 1;
// find the triangle which has edge consists of start and end
TRIANGLE_PTR pTri = pMesh->pTriArr;
int index_d = -1;
while (pTri != NULL)
{
statify[0] = 0;
statify[1] = 0;
statify[2] = 0;
pi = &(pTri->i1);
for (int j=0, k = 1; j<3; j++, k*= 2)
{
vertex_index = *pi++;
if(vertex_index == index_a || vertex_index == index_b)
{
statify[j] = k;
}
}
switch(statify[0] | statify[1] | statify[2] )
{
case 3:
if(CounterClockWise((VERTEX2D_PTR)(pMesh->pVerArr+index_a), (VERTEX2D_PTR)(pMesh->pVerArr+index_b), (VERTEX2D_PTR)(pMesh->pVerArr+pTri->i3)) < 0)
{
index_d = pTri->i3;
}
break;
case 5:
if(CounterClockWise((VERTEX2D_PTR)(pMesh->pVerArr+index_a), (VERTEX2D_PTR)(pMesh->pVerArr+index_b), (VERTEX2D_PTR)(pMesh->pVerArr+pTri->i2)) < 0)
{
index_d = pTri->i2;
}
break;
case 6:
if(CounterClockWise((VERTEX2D_PTR)(pMesh->pVerArr+index_a), (VERTEX2D_PTR)(pMesh->pVerArr+index_b), (VERTEX2D_PTR)(pMesh->pVerArr+pTri->i1)) < 0)
{
index_d = pTri->i1;
}
break;
default:
break;
}
if (index_d != -1)
{
VERTEX2D_PTR pa = (VERTEX2D_PTR)(pMesh->pVerArr+index_a);
VERTEX2D_PTR pb = (VERTEX2D_PTR)(pMesh->pVerArr+index_b);
VERTEX2D_PTR pd = (VERTEX2D_PTR)(pMesh->pVerArr+index_d);
VERTEX2D_PTR pp = (VERTEX2D_PTR)(pMesh->pVerArr+index_p);
if(InCircle( pa, pb, pp, pd) < 0) // not local Delaunay
{
flipped = true;
// add new triangle adp, dbp, remove abp, abd.
// allocate memory for adp
TRIANGLE_PTR pT1 = AddTriangleNode(pMesh, pTestTri, pTestTri->i1, index_d, pTestTri->i3);
// allocate memory for dbp
TRIANGLE_PTR pT2 = AddTriangleNode(pMesh, pT1, index_d, pTestTri->i2, index_p);
// remove abp
RemoveTriangleNode(pMesh, pTestTri);
// remove abd
RemoveTriangleNode(pMesh, pTri);
FlipTest(pMesh, pT1); // pNewTestTri satisfies CCW order
FlipTest(pMesh, pT2); // pNewTestTri2 satisfies CCW order
break;
}
}
// go to next item
pTri = pTri->pNext;
}
return flipped;
}
// In circle test, use vector cross product
REAL InCircle(VERTEX2D_PTR pa, VERTEX2D_PTR pb, VERTEX2D_PTR pp, VERTEX2D_PTR pd)
{
REAL det;
REAL alift, blift, plift, bdxpdy, pdxbdy, pdxady, adxpdy, adxbdy, bdxady;
REAL adx = pa->x - pd->x;
REAL ady = pa->y - pd->y;
REAL bdx = pb->x - pd->x;
REAL bdy = pb->y - pd->y;
REAL pdx = pp->x - pd->x;
REAL pdy = pp->y - pd->y;
bdxpdy = bdx * pdy; pdxbdy = pdx * bdy; alift = adx * adx + ady * ady; pdxady = pdx * ady; adxpdy = adx * pdy; blift = bdx * bdx + bdy * bdy; adxbdy = adx * bdy; bdxady = bdx * ady; plift = pdx * pdx + pdy * pdy; det = alift * (bdxpdy - pdxbdy) + blift * (pdxady - adxpdy) + plift * (adxbdy - bdxady);
return -det;
}
// Remove a node from the triangle list and deallocate the memory
void RemoveTriangleNode(MESH_PTR pMesh, TRIANGLE_PTR pTri)
{
if (pTri == NULL)
{
return;
}
// remove from the triangle list
if (pTri->pPrev != NULL)
{
pTri->pPrev->pNext = pTri->pNext;
}
else // remove the head, need to reset the root node
{
pMesh->pTriArr = pTri->pNext;
}
if (pTri->pNext != NULL)
{
pTri->pNext->pPrev = pTri->pPrev;
}
// deallocate memory
free(pTri);
}
// Create a new node and add it into triangle list
TRIANGLE_PTR AddTriangleNode(MESH_PTR pMesh, TRIANGLE_PTR pPrevTri, int i1, int i2, int i3)
{
// test if 3 vertices are co-linear
if(CounterClockWise((VERTEX2D_PTR)(pMesh->pVerArr+i1), (VERTEX2D_PTR)(pMesh->pVerArr+i2), (VERTEX2D_PTR)(pMesh->pVerArr+i3)) == 0)
{
return NULL;
}
// allocate memory
TRIANGLE_PTR pNewTestTri = (TRIANGLE_PTR)malloc(sizeof(TRIANGLE));
pNewTestTri->i1 = i1;
pNewTestTri->i2 = i2;
pNewTestTri->i3 = i3;
// insert after prev triangle
if (pPrevTri == NULL) // add root
{
pMesh->pTriArr = pNewTestTri;
pNewTestTri->pNext = NULL;
pNewTestTri->pPrev = NULL;
}
else
{
pNewTestTri->pNext = pPrevTri->pNext;
pNewTestTri->pPrev = pPrevTri;
if(pPrevTri->pNext != NULL)
{
pPrevTri->pNext->pPrev = pNewTestTri;
}
pPrevTri->pNext = pNewTestTri;
}
return pNewTestTri;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -