Dear all,
regarding the Powell-Sabin division, I have written some FreeFem lines that work. This can be helpful for some of you. Given a mesh Th0 it produces a mesh Th by subdivision of each initial triangle into 6.
Best,
Francois.
// produce mesh1.msh as a Powell-Sabin division of Th0
// Cf Shangyou Zhang J. Comput. Math. 26 no3, 456-470, 2008.
int[int] dofmesh1vertex0(Th0.nv); //new numbering of old vertices
dofmesh1vertex0=-1;// value -1 means not yet defined
real[int] dofmesh1x(7*Th0.nt),dofmesh1y(7*Th0.nt);// x,y components of new vertices
int[int] dofmesh1label(7*Th0.nt);// labels of new vertices
dofmesh1label=-1;
int[int,int] edgesmesh0(Th0.nt,3);//new numbering of old edges, in terms of old triangles and edges
int[int,int] trianglesmesh1(6*Th0.nt,4);//list of new triangles, by 3 vertices and label
int countdofmesh1=0;
int[int]countcenter(Th0.nt);//new numbering of old triangles
for (int k=0;k<Th0.nt;k++) {//begin loop on triangles
int v0=Th0[k][0];
int v1=Th0[k][1];
int v2=Th0[k][2];
real v0x=Th0[k][0].x;
real v0y=Th0[k][0].y;
real v1x=Th0[k][1].x;
real v1y=Th0[k][1].y;
real v2x=Th0[k][2].x;
real v2y=Th0[k][2].y;
// vertices of Th0
if (dofmesh1vertex0(v0)==-1) {
dofmesh1x(countdofmesh1)=v0x;
dofmesh1y(countdofmesh1)=v0y;
dofmesh1label(countdofmesh1)=Th0[k][0].label;
dofmesh1vertex0(v0)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
if (dofmesh1vertex0(v1)==-1) {
dofmesh1x(countdofmesh1)=v1x;
dofmesh1y(countdofmesh1)=v1y;
dofmesh1label(countdofmesh1)=Th0[k][1].label;
dofmesh1vertex0(v1)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
if (dofmesh1vertex0(v2)==-1) {
dofmesh1x(countdofmesh1)=v2x;
dofmesh1y(countdofmesh1)=v2y;
dofmesh1label(countdofmesh1)=Th0[k][2].label;
dofmesh1vertex0(v2)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
//// center of triangles of Th0
//// gravity center
//dofmesh1x(countdofmesh1)=(v0x+v1x+v2x)/3.;
//dofmesh1y(countdofmesh1)=(v0y+v1y+v2y)/3.;
// center of the inscribed circle
real length0,length1,length2,w0x,w0y,w1x,w1y;
length0=sqrt((v2x-v1x)^2+(v2y-v1y)^2);
length1=sqrt((v0x-v2x)^2+(v0y-v2y)^2);
length2=sqrt((v1x-v0x)^2+(v1y-v0y)^2);
w0x=(v1x-v0x)/length2+(v2x-v0x)/length1;
w0y=(v1y-v0y)/length2+(v2y-v0y)/length1;
w1x=(v2x-v1x)/length0+(v0x-v1x)/length2;
w1y=(v2y-v1y)/length0+(v0y-v1y)/length2;
real lambda0=((v1x-v0x)*w1y-(v1y-v0y)*w1x)/(w0x*w1y-w0y*w1x);
dofmesh1x(countdofmesh1)=v0x+lambda0*w0x;
dofmesh1y(countdofmesh1)=v0y+lambda0*w0y;//end of def center of the inscribed circle
dofmesh1label(countdofmesh1)=Th0[k].label;
countcenter(k)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
// edges of Th0 (cut by line between two centers)
int ee;
if (int(Th0[k].adj((ee=0)))>=k) {
if (int(Th0[k].adj((ee=0)))!=k){
dofmesh1label(countdofmesh1)=0;
}
else {
dofmesh1x(countdofmesh1)=(v1x+v2x)/2.;
dofmesh1y(countdofmesh1)=(v1y+v2y)/2.;
}
edgesmesh0(k,0)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
else {
int k0=int(Th0[k].adj((ee=0)));
edgesmesh0(k,0)=edgesmesh0(k0,ee);
real centerkx0=dofmesh1x(countcenter(k));
real centerky0=dofmesh1y(countcenter(k));
real centeradjx0=dofmesh1x(countcenter(k0));
real centeradjy0=dofmesh1y(countcenter(k0));
real scalinters0=((v1x-centerkx0)*(v2y-v1y)-(v1y-centerky0)*(v2x-v1x))/((centeradjx0-centerkx0)*(v2y-v1y)-(centeradjy0-centerky0)*(v2x-v1x));
dofmesh1x(edgesmesh0(k0,ee))=centerkx0+scalinters0*(centeradjx0-centerkx0);
dofmesh1y(edgesmesh0(k0,ee))=centerky0+scalinters0*(centeradjy0-centerky0);
}
if (int(Th0[k].adj((ee=1)))>=k) {
if (int(Th0[k].adj((ee=1)))!=k){
dofmesh1label(countdofmesh1)=0;
}
else {
dofmesh1x(countdofmesh1)=(v2x+v0x)/2.;
dofmesh1y(countdofmesh1)=(v2y+v0y)/2.;
}
edgesmesh0(k,1)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
else {
int k1=int(Th0[k].adj((ee=1)));
edgesmesh0(k,1)=edgesmesh0(k1,ee);
real centerkx1=dofmesh1x(countcenter(k));
real centerky1=dofmesh1y(countcenter(k));
real centeradjx1=dofmesh1x(countcenter(k1));
real centeradjy1=dofmesh1y(countcenter(k1));
real scalinters1=((v2x-centerkx1)*(v0y-v2y)-(v2y-centerky1)*(v0x-v2x))/((centeradjx1-centerkx1)*(v0y-v2y)-(centeradjy1-centerky1)*(v0x-v2x));
dofmesh1x(edgesmesh0(k1,ee))=centerkx1+scalinters1*(centeradjx1-centerkx1);
dofmesh1y(edgesmesh0(k1,ee))=centerky1+scalinters1*(centeradjy1-centerky1);
}
if (int(Th0[k].adj((ee=2)))>=k) {
if (int(Th0[k].adj((ee=2)))!=k){
dofmesh1label(countdofmesh1)=0;
}
else {
dofmesh1x(countdofmesh1)=(v0x+v1x)/2.;
dofmesh1y(countdofmesh1)=(v0y+v1y)/2.;
}
edgesmesh0(k,2)=countdofmesh1;
countdofmesh1=countdofmesh1+1;
}
else {
int k2=int(Th0[k].adj((ee=2)));
edgesmesh0(k,2)=edgesmesh0(k2,ee);
real centerkx2=dofmesh1x(countcenter(k));
real centerky2=dofmesh1y(countcenter(k));
real centeradjx2=dofmesh1x(countcenter(k2));
real centeradjy2=dofmesh1y(countcenter(k2));
real scalinters2=((v0x-centerkx2)*(v1y-v0y)-(v0y-centerky2)*(v1x-v0x))/((centeradjx2-centerkx2)*(v1y-v0y)-(centeradjy2-centerky2)*(v1x-v0x));
dofmesh1x(edgesmesh0(k2,ee))=centerkx2+scalinters2*(centeradjx2-centerkx2);
dofmesh1y(edgesmesh0(k2,ee))=centerky2+scalinters2*(centeradjy2-centerky2);
}
}//end of loop on triangles
//cout << "countdofmesh1= " << countdofmesh1 << endl;
dofmesh1x.resize(countdofmesh1);
dofmesh1y.resize(countdofmesh1);
dofmesh1label.resize(countdofmesh1);
// def of 6 subtriangles
for (int k=0;k<Th0.nt;k++) {
trianglesmesh1(6*k,0)=dofmesh1vertex0(Th0[k][0]);
trianglesmesh1(6*k,1)=edgesmesh0(k,2);
trianglesmesh1(6*k,2)=countcenter(k);
trianglesmesh1(6*k,3)=Th0[k].label;
trianglesmesh1(6*k+1,0)=dofmesh1vertex0(Th0[k][1]);
trianglesmesh1(6*k+1,1)=countcenter(k);
trianglesmesh1(6*k+1,2)=edgesmesh0(k,2);
trianglesmesh1(6*k+1,3)=Th0[k].label;
trianglesmesh1(6*k+2,0)=dofmesh1vertex0(Th0[k][1]);
trianglesmesh1(6*k+2,1)=edgesmesh0(k,0);
trianglesmesh1(6*k+2,2)=countcenter(k);
trianglesmesh1(6*k+2,3)=Th0[k].label;
trianglesmesh1(6*k+3,0)=dofmesh1vertex0(Th0[k][2]);
trianglesmesh1(6*k+3,1)=countcenter(k);
trianglesmesh1(6*k+3,2)=edgesmesh0(k,0);
trianglesmesh1(6*k+3,3)=Th0[k].label;
trianglesmesh1(6*k+4,0)=dofmesh1vertex0(Th0[k][2]);
trianglesmesh1(6*k+4,1)=edgesmesh0(k,1);
trianglesmesh1(6*k+4,2)=countcenter(k);
trianglesmesh1(6*k+4,3)=Th0[k].label;
trianglesmesh1(6*k+5,0)=dofmesh1vertex0(Th0[k][0]);
trianglesmesh1(6*k+5,1)=countcenter(k);
trianglesmesh1(6*k+5,2)=edgesmesh0(k,1);
trianglesmesh1(6*k+5,3)=Th0[k].label;
}
int[int,int]vertexbdryel(2*Th0.nbe,3);//list of new boundary elements, by 2 vertices and label
// loop on boundary
for (int l=0;l<Th0.nbe;l++) {
vertexbdryel(2*l,0)=dofmesh1vertex0(Th0.be(l)[0]);
int triel=int(Th0.be(l).Element);
int edgetriel=Th0.be(l).whoinElement;
vertexbdryel(2*l,1)=edgesmesh0(triel,edgetriel);
vertexbdryel(2*l,2)=Th0.be(l).label;
vertexbdryel(2*l+1,0)=edgesmesh0(triel,edgetriel);
vertexbdryel(2*l+1,1)=dofmesh1vertex0(Th0.be(l)[1]);
vertexbdryel(2*l+1,2)=Th0.be(l).label;
dofmesh1label(edgesmesh0(triel,edgetriel))=Th0.be(l).label;
}
{ofstream filemesh1("mesh1.msh");
filemesh1 << countdofmesh1 << " " << 6*Th0.nt << " " << 2*Th0.nbe << endl;
};
{ofstream filemesh1("mesh1.msh",append);
int nold=filemesh1.precision(30);// it is important to have really straight intersections
for (int i=0;i<countdofmesh1;i++) {
filemesh1 << dofmesh1x(i) << " " << dofmesh1y(i) << " " << dofmesh1label(i) << endl;
}
for (int k=0;k<6*Th0.nt;k++) {
filemesh1 << trianglesmesh1(k,0)+1 << " " << trianglesmesh1(k,1)+1 << " " << trianglesmesh1(k,2)+1 << " " << trianglesmesh1(k,3) << endl;
}
for (int l=0;l<2*Th0.nbe;l++) {
filemesh1 << vertexbdryel(l,0)+1 << " " << vertexbdryel(l,1)+1 << " " << vertexbdryel(l,2) << endl;
}
};
//end of Powell-Sabin division
mesh Th=readmesh("mesh1.msh");