# CV笔记（二）——Delaunay三角剖分的Java实现

## Bowyer-Watson

### 算法原理

Bowyer-Watson算法是逐点插入算法，每次插入后分割插入点所在的三角形，如下图：

### 实现思路

class mTriangle{
dPoint a;
dPoint b;
dPoint c;
dPoint center;
double Rsq;
/** share points a&b*/
int neighbor1;
/** share points b&c*/
int neighbor2;
/** share points c&a*/
int neighbor3;
public mTriangle(dPoint p1, dPoint p2, dPoint p3){
this.a = p1;
this.b = p2;
this.c = p3;
this.neighbor1 = -1;
this.neighbor2 = -1;
this.neighbor3 = -1;
center = new dPoint();
getCenter();
}
/* calculate External circle center*/
protected void getCenter(){
double A1,A2,B1,B2,C1,C2;
/* l1(b,c):A1x+B1y+C1*/
A1 = c.x-b.x;
B1 = c.y-b.y;
C1 = (-(b.y+c.y)*B1-A1*(b.x+c.x))/2;
/* l2(a,c):A2x+B2y+C2*/
A2 = c.x-a.x;
B2 = c.y-a.y;
C2 = (-(a.y+c.y)*B2-A2*(a.x+c.x))/2;
if(A1!=0 && A2!=0 && B1!=0 && B2!=0)
{
if(A1*B2==B1*A2)
{
System.out.println("Triangle error: edge parallel");
return;
}
center.y = (C1*A2-C2*A1)/(A1*B2-B1*A2);
center.x = -(B1*center.y+C1)/A1;
Rsq = dPoint.sdist(center,c);
return;
}
else
{
if((A1==0 && B1==0) || (A2==0 && B2==0))
{
System.out.println("Triangle error: same two point");
return;
}
if((A1==0 && A2==0) || (B1==0 && B2==0))
{
System.out.println("Triangle error: three points collinear");
return;
}
if(A1==0)
{
center.y = -C1/B1;
center.x = -(B2*center.y+C2)/A2;
Rsq = dPoint.sdist(center,c);
return;
}
if(A2==0)
{
center.y = -C2/B2;
center.x = -(B1*center.y+C1)/A1;
Rsq = dPoint.sdist(center,c);
return;
}
if(B1==0)
{
center.x = -C1/A1;
center.y = -(C2+A2*center.x)/B2;
Rsq = dPoint.sdist(center,c);
return;
}
center.x = -C2/A2;
center.y = -(C1+A1*center.x)/B1;
Rsq = dPoint.sdist(center,c);
return;
}
}

/* judge if p is in triangle */
public boolean inTriangle(dPoint p)
{
/* cross prod*/
dPoint MA = new dPoint(p.x - a.x,p.y - a.y);
dPoint MB = new dPoint(p.x - b.x,p.y - b.y);
dPoint MC = new dPoint(p.x - c.x,p.y - c.y);
double cp1 = MA.x * MB.y - MA.y * MB.x;
double cp2 = MB.x * MC.y - MB.y * MC.x;
double cp3 = MC.x * MA.y - MC.y * MA.x;
if(cp1>=0 && cp2>=0 && cp3>=0)
return true;
if(cp1<=0 && cp2<=0 && cp3<=0)
return true;
return false;
}

public boolean inExternalCircle(dPoint p)
{
if(dPoint.sdist(p,center)<=Rsq)
return true;
return false;
}
}


protected void addPoint(dPoint p) {
int Tidx=0;
/* find which triangle p is in */
for(;Tidx<triangles.size();Tidx++)
if(triangles.get(Tidx).inTriangle(p))
break;
if(Tidx>=triangles.size())
{
System.out.println("addPoint error: point out of super triangles");
return;
}
mTriangle oldt = triangles.get(Tidx);
mTriangle nt1,nt2,nt3;
/* replace the old triangle by three new triangle*/
nt1=new mTriangle(oldt.a,oldt.b,p);
nt1.neighbor1 = oldt.neighbor1;
nt1.neighbor2 = triangles.size();
nt1.neighbor3 = triangles.size()+1;
// this one has no need to update
// updateNeighbor(oldt.neighbor1, Tidx, Tidx);

nt2=new mTriangle(oldt.b,oldt.c,p);
nt2.neighbor1 = oldt.neighbor2;
nt2.neighbor2 = triangles.size()+1;
nt2.neighbor3 = Tidx;
updateNeighbor(oldt.neighbor2, Tidx, triangles.size());

nt3=new mTriangle(oldt.c,oldt.a,p);
nt3.neighbor1 = oldt.neighbor2;
nt3.neighbor2 = Tidx;
nt3.neighbor3 = triangles.size();
updateNeighbor(oldt.neighbor3, Tidx, triangles.size()+1);

triangles.set(Tidx,nt1);

if(needUpdate(Tidx,nt1.neighbor1))
else if(needUpdate(triangles.size()-2,nt2.neighbor1))
else if(needUpdate(triangles.size()-1,nt3.neighbor1))

}


    protected void deleteSuperTriangle() {
for(int i=0,len=triangles.size();i<len;i++){
if(useSuperTrianglePoints(i))
{
triangles.remove(i);
--len;
--i;
}
}
}


mTriangle t1 = new mTriangle(superp1,superp2,superp4);
mTriangle t2 = new mTriangle(superp2,superp3,superp4);
t1.neighbor2=1;
t2.neighbor3=0;
for(dPoint x:pointlist)
deleteSuperTriangle();


10-23
11-04 852

04-16 880
05-04 2万+
08-21 859
05-26 862
05-05 3032