
// wetfoam.cmd
// Evolver command to convert dry foam to wet foam.
// Dry foam assumptions:
//    In torus domain  (so no awkward boundary conditions)
//    Only singularities are triple lines and  tetrahedral points

/* parameter for initial size of Plateau borders */
spread := .2

/* some variables we'll need */
ff1 := 0; ff2 := 0; ff3 := 0;
tail1 := 0; tail2 := 0; tail3 := 0;
head1 := 0; head2 := 0; head3 := 0;
vv1 := 0; vv2 := 0;
bb1 := 0; bb2 := 0; bb3 := 0;
wrapnum := 0;
linecount := 0;
nodemode := 0;
nodebody := 0;

/* tests and preliminaries */
edgetest := { foreach edge ee where ee.valence != 2 and ee.valence != 3 do
		 printf "Edge %g has valence %g.\n",ee.id,ee.valence }
vertest := { foreach vertex vv do 
	       { plain := sum(vv.edge where valence == 2,1);
		 triple := sum(vv.edge where valence == 3,1);
		 set vv x4 triple;  /* save for later */
		 if ( triple == 4 ) then
		 { if ( plain != 6 ) then
		     printf "Vertex %g has %g triple and %g plain edges.\n",
		       vv.id,triple,plain;
                 }
                 else if ( triple == 2 ) then
		 { if ( plain != 3 ) then
		     printf "Vertex %g has %g triple and %g plain edges.\n",
		       vv.id,triple,plain;
                 }
		 else if ( triple > 0 )  then
		   printf "Vertex %g has %g triple edges.\n",vv.id,triple;
               }
            }
facettest := { foreach facet ff do
               { triple := sum(ff.edge where valence == 3, 1);
		 if ( triple >= 2 ) then
		   printf "Facet %g has %g triple edges.\n",ff.id,triple;
               }
             }
wettests := { edgetest; vertest; facettest; }

/* print vertex list */
wetverts := { voffset := vertex_count; /* start of new vertices */
	      printf "\nvertices\n";
	      foreach vertex vv do
	        if ( vv.x4 < 1 ) then 
		     printf "%g  %g %g %g\n",vv.id, vv.x,vv.y,vv.z;
              foreach edge ee where valence == 2 do
	      { fudge := spread;
		foreach ee.vertex vv  do
		  { if x4 > 1 then
		     printf "%g  %g %g %g\n",ee.id+voffset,
			vv.x+fudge*ee.x,vv.y+fudge*ee.y,vv.z+fudge*ee.z;
                    fudge := -fudge;
                  }
	      }
	    }

/* convert numerical  torus wrap to string and print */
wrapconvert := { ww := floor(1e-6 + (wrapnum % 64)); 
		 if ( ww == 0 ) then printf " *"
		 else if ( ww == 1 ) then printf " +"
		 else printf " -";
		 ww := floor(1e-6 + (floor(1e-6+wrapnum/64) % 64) );
		 if ( ww == 0 ) then printf " *"
		 else if ( ww == 1 ) then printf " +"
		 else printf " -";
		 ww := floor(1e-6 + (floor(1e-6+wrapnum/4096) % 64) );
		 if ( ww == 0 ) then printf " *"
		 else if ( ww == 1 ) then printf " +"
		 else printf " -";
               }

/* print edge list */
wetedges := { eoffset := edge_count; /* start of new edges */
              printf "\nedges\n";
              /* first, old edges that we keep */
	      foreach edge ee where valence == 2 do
	      { printf "%g  ", ee.id;
		wrapnum := ee.wrap;
		foreach ee.vertex vv do
		{ if ( vv.x4 > 1 ) then 
		    printf "%g ",ee.id+voffset
                  else printf "%g ",vv.id;
                }; 
		wrapconvert;
		printf "\n";
              };
	      foreach edge ee where valence == 3 do
	      { 
		wrapnum := ee.wrap;
                /* assemble data about new vertices */
		foreach ee.vertex vv do { vv1 := vv2; vv2 := vv.id };
		foreach ee.facet ff do
		{ ff1 := ff2; ff2 := ff3; ff3 := ff.id;
		  foreach ff.edge eee where eee.id != ee.id do
		  { if max(eee.vertex,id==vv1) then
		    { tail1 := tail2; tail2 := tail3; tail3 := eee.id+voffset
		    }
		    else
		    { head1 := head2; head2 := head3; head3 := eee.id+voffset
		    }
		  } 
		 };
                 /* construct new edges */
		 printf "%g  %g %g ",ff1*3+eoffset,tail1,head1; wrapconvert;
		 printf "\n";
		 printf "%g  %g %g * * *\n",ff1*3+eoffset+1,tail1,tail2;
		 printf "%g  %g %g * * *\n",ff1*3+eoffset+2,head1,head2; 
		 printf "%g  %g %g ",ff2*3+eoffset,tail2,head2; wrapconvert;
		 printf "\n";
		 printf "%g  %g %g * * *\n",ff2*3+eoffset+1,tail2,tail3; 
		 printf "%g  %g %g * * *\n",ff2*3+eoffset+2,head2,head3; 
		 printf "%g  %g %g ",ff3*3+eoffset,tail3,head3; wrapconvert;
		 printf "\n";
		 printf "%g  %g %g * * *\n",ff3*3+eoffset+1,tail3,tail1; 
		 printf "%g  %g %g * * *\n",ff3*3+eoffset+2,head3,head1; 
              }
          } /* end wetedges */

/* subroutine for node triangle faces */
triangles := { ffoffset := max(facet,id) + 3*max(edge where valence==3,id);
	       foreach vertex vv where x4 > 3 do
	       { /* gather pertinent data around each tetra vertex */
		 nn := 1;
	         foreach vv.edge ee where valence == 3 do
		 { if ee.oid > 0 then
		   foreach ee.facet ff do
		   { foreach ff.edge eee
			where eee.id != ee.id and max(eee.vertex,id==vv.id)
			do vid := eee.id + voffset;
                     eid := ff.id*3 + 1 + eoffset;
		     foreach ff.body do bid := id;
		     if nn == 1 then { av1:=vid; ae1 := eid; ab1 := bid; }
		     else if nn == 2 then { av2:=vid; ae2 := eid; ab2 := bid; }
		     else if nn == 3 then { av3:=vid; ae3 := eid; ab3 := bid; }
		     else if nn == 4 then { bv1:=vid; be1 := eid; bb1 := bid; }
		     else if nn == 5 then { bv2:=vid; be2 := eid; bb2 := bid; }
		     else if nn == 6 then { bv3:=vid; be3 := eid; bb3 := bid; }
		     else if nn == 7 then { cv1:=vid; ce1 := eid; cb1 := bid; }
		     else if nn == 8 then { cv2:=vid; ce2 := eid; cb2 := bid; }
		     else if nn == 9 then { cv3:=vid; ce3 := eid; cb3 := bid; }
		     else if nn == 10 then { dv1:=vid; de1:=eid; db1:=bid; }
		     else if nn == 11 then { dv2:=vid; de2:=eid; db2:=bid; }
		     else if nn == 12 then { dv3:=vid; de3:=eid; db3:=bid;};
		     nn := nn + 1;
                   } /* end foreach ff */
		   else /* reversed edge */
		   foreach ee.facet ff do
		   { foreach ff.edge eee
			where eee.id != ee.id and max(eee.vertex,id==vv.id)
			do vid := eee.id + voffset;
                     eid := -(ff.id*3 + 2 + eoffset);
		     tbid:= 0;
		     foreach ff.body do { bid := tbid; tbid := id; };
		     if nn == 1 then { av3:=vid; ae2 := eid; ab2 := bid; }
		     else if nn == 2 then { av1:=vid; ae3 := eid; ab3 := bid; }
		     else if nn == 3 then { av2:=vid; ae1 := eid; ab1 := bid; }
		     else if nn == 4 then { bv3:=vid; be2 := eid; bb2 := bid; }
		     else if nn == 5 then { bv1:=vid; be3 := eid; bb3 := bid; }
		     else if nn == 6 then { bv2:=vid; be1 := eid; bb1 := bid; }
		     else if nn == 7 then { cv3:=vid; ce2 := eid; cb2 := bid; }
		     else if nn == 8 then { cv1:=vid; ce3 := eid; cb3 := bid; }
		     else if nn == 9 then { cv2:=vid; ce1 := eid; cb1 := bid; }
		     else if nn == 10 then { dv3:=vid; de2:=eid; db2:=bid; }
		     else if nn == 11 then { dv1:=vid; de3:=eid; db3:=bid; }
		     else if nn == 12 then { dv2:=vid; de1:=eid; db1:=bid;};
		     nn := nn + 1;
                   } /* end foreach ff for reversed edge */
		 }; /* end foreach ee */

if nodemode == 4 then
		 { /* debug dump */
		   printf "\nNode %g before sort\n",vv.id;
		   printf "Vertices: %g %g %g %g %g %g",
		    av1,av2,av3,bv1,bv2,bv3;
		   printf " %g %g %g %g %g %g\n",
		    cv1,cv2,cv3,dv1,dv2,dv3;
		   printf "Edges: %g %g %g %g %g %g ",
		    ae1,ae2,ae3,be1,be2,be3;
		   printf "%g %g %g %g %g %g\n",
		    ce1,ce2,ce3,de1,de2,de3;
		   printf "Bodies: %g %g %g %g %g %g ",
		    ab1,ab2,ab3,bb1,bb2,bb3;
		   printf "%g %g %g %g %g %g\n",
		    cb1,cb2,cb3,db1,db2,db3;
                 };
		 /* now rearrange into canonical order */
		 if av1 == cv1 or av1 == cv2 or av1 == cv3 then
		 { tv1 := cv1; cv1 := bv1; bv1 := tv1;
		   te1 := ce1; ce1 := be1; be1 := te1;
		   tb1 := cb1; cb1 := bb1; bb1 := tb1;
		   tv2 := cv2; cv2 := bv2; bv2 := tv2;
		   te2 := ce2; ce2 := be2; be2 := te2;
		   tb2 := cb2; cb2 := bb2; bb2 := tb2;
		   tv3 := cv3; cv3 := bv3; bv3 := tv3;
		   te3 := ce3; ce3 := be3; be3 := te3;
		   tb3 := cb3; cb3 := bb3; bb3 := tb3;
                 };
		 if av1 == dv1 or av1 == dv2 or av1 == dv3 then
		 { tv1 := dv1; dv1 := bv1; bv1 := tv1;
		   te1 := de1; de1 := be1; be1 := te1;
		   tb1 := db1; db1 := bb1; bb1 := tb1;
		   tv2 := dv2; dv2 := bv2; bv2 := tv2;
		   te2 := de2; de2 := be2; be2 := te2;
		   tb2 := db2; db2 := bb2; bb2 := tb2;
		   tv3 := dv3; dv3 := bv3; bv3 := tv3;
		   te3 := de3; de3 := be3; be3 := te3;
		   tb3 := db3; db3 := bb3; bb3 := tb3;
                 };
		 if av2 == dv1 or av2 == dv2 or av2 == dv3 then
		 { tv1 := dv1; dv1 := cv1; cv1 := tv1;
		   te1 := de1; de1 := ce1; ce1 := te1;
		   tb1 := db1; db1 := cb1; cb1 := tb1;
		   tv2 := dv2; dv2 := cv2; cv2 := tv2;
		   te2 := de2; de2 := ce2; ce2 := te2;
		   tb2 := db2; db2 := cb2; cb2 := tb2;
		   tv3 := dv3; dv3 := cv3; cv3 := tv3;
		   te3 := de3; de3 := ce3; ce3 := te3;
		   tb3 := db3; db3 := cb3; cb3 := tb3;
                 };
                 if av1 == bv2 then
		 { tv1 := bv1; bv1 := bv2; bv2 := bv3; bv3 := tv1;
		   te1 := be1; be1 := be2; be2 := be3; be3 := te1;
		   tb1 := bb1; bb1 := bb2; bb2 := bb3; bb3 := tb1;
                 }
		 else if av1 == bv3 then
		 { tv1 := bv1; bv1 := bv3; bv3 := bv2; bv2 := tv1;
		   te1 := be1; be1 := be3; be3 := be2; be2 := te1;
		   tb1 := bb1; bb1 := bb3; bb3 := bb2; bb2 := tb1;
                 };
                 if av2 == cv3 then
		 { tv1 := cv1; cv1 := cv2; cv2 := cv3; cv3 := tv1;
		   te1 := ce1; ce1 := ce2; ce2 := ce3; ce3 := te1;
		   tb1 := cb1; cb1 := cb2; cb2 := cb3; cb3 := tb1;
                 }
		 else if av2 == cv1 then
		 { tv1 := cv1; cv1 := cv3; cv3 := cv2; cv2 := tv1;
		   te1 := ce1; ce1 := ce3; ce3 := ce2; ce2 := te1;
		   tb1 := cb1; cb1 := cb3; cb3 := cb2; cb2 := tb1;
                 };
                 if av3 == dv1 then
		 { tv1 := dv1; dv1 := dv2; dv2 := dv3; dv3 := tv1;
		   te1 := de1; de1 := de2; de2 := de3; de3 := te1;
		   tb1 := db1; db1 := db2; db2 := db3; db3 := tb1;
                 }
		 else if av3 == dv2 then
		 { tv1 := dv1; dv1 := dv3; dv3 := dv2; dv2 := tv1;
		   te1 := de1; de1 := de3; de3 := de2; de2 := te1;
		   tb1 := db1; db1 := db3; db3 := db2; db2 := tb1;
                 };
		 ff1 := ffoffset + vv.id*4 + 1;
		 ff2 := ff1 + 1; ff3 := ff1 + 2; ff4 := ff1 + 3;
		 if ( nodemode == 1 ) then
		 { /* now print out facets */
                   printf "%g   %g %g %g tension 0.5\n",ff1,-ae1,-be3,-ce2;
                   printf "%g   %g %g %g tension 0.5\n",ff2,-ae3,-de2,-be1;
                   printf "%g   %g %g %g tension 0.5\n",ff3,-ae2,-ce1,-de3;
                   printf "%g   %g %g %g tension 0.5\n",ff4,-be2,-de1,-ce3;
                 }
		 else if nodemode == 2 then
		 { /* print facets for border body */
		   printf "%g %g %g %g ",ff1,ff2,ff3,ff4;
		   linecount := linecount + 4;
		   if ( linecount >= 10 )  then
		       { printf "\\\n    "; linecount := 0; }
		 }
		 else if nodemode == 3 then
		 { 
		   /* print for matching body */
		   if nodebody == ab1 then
		    { printf "%g ",-ff1; linecount := linecount + 1; };
		   if nodebody == ab3 then
		    { printf "%g ",-ff2; linecount := linecount + 1; };
		   if nodebody == ab2 then
		    { printf "%g ",-ff3; linecount := linecount + 1; };
		   if nodebody == bb2 then
		    { printf "%g ",-ff4; linecount := linecount + 1; };
		   if ( linecount >= 10 )  then
		       { printf "\\\n    "; linecount := 0; }
		 }
		 else if nodemode == 4 then
		 { /* debug dump */
		   printf "\nNode %g after sort\n",vv.id;
		   printf "Vertices: %g %g %g %g %g %g",
		    av1,av2,av3,bv1,bv2,bv3;
		   printf " %g %g %g %g %g %g\n",
		    cv1,cv2,cv3,dv1,dv2,dv3;
		   printf "Edges: %g %g %g %g %g %g ",
		    ae1,ae2,ae3,be1,be2,be3;
		   printf "%g %g %g %g %g %g\n",
		    ce1,ce2,ce3,de1,de2,de3;
		   printf "Bodies: %g %g %g %g %g %g ",
		    ab1,ab2,ab3,bb1,bb2,bb3;
		   printf "%g %g %g %g %g %g\n",
		    cb1,cb2,cb3,db1,db2,db3;
if ( ab1 != bb3 or ab1 != cb2 ) then 
   printf " ab1 %g bb3 %g cb2 %g\n",ab1,bb3,cb2;
if ( ab3 != bb1 or ab3 != db2 ) then 
   printf " ab3 %g bb1 %g db2 %g\n",ab3,bb1,db2;
if ( db3 != ab2 or db3 != cb1 ) 
   then printf " cb1 %g db3 %g ab2 %g\n",cb1,db3,ab2;
if ( db1 != cb3 or db1 != bb2 ) 
   then printf " db1 %g cb3 %g bb2 %g\n",db1,cb3,bb2;
                 }
	       } /* end foreach vv */
              } /* end triangles */

/* print face list, less triangles at nodes */
wetfaces := { foffset := max(facet,id);
              printf "\nfaces\n";
	      /* old facets, replacing triple edges with new */
	      foreach facet ff do
	      { printf "%g   ",ff.id;
		foreach ff.edge ee do
		{ if ( ee.valence == 2 ) then printf "%g ",ee.oid
		  else 
		    printf "%g ",(ee.oid<0?-(eoffset+ff.id*3):eoffset+ff.id*3)
                };
		printf "\n";
	      };
              /* tube faces around triple lines */
	      foreach edge ee where valence == 3 do
	      { 
                /* assemble data about new vertices */
		foreach ee.vertex vv do { vv1 := vv2; vv2 := vv.id };
		foreach ee.facet ff do
		{ ff1 := ff2; ff2 := ff3; ff3 := ff.id;
		  foreach ff.edge eee where eee.id != ee.id do
		  { if max(eee.vertex,id==vv1) then
		    { tail1 := tail2; tail2 := tail3; tail3 := eee.id+voffset
		    }
		    else
		    { head1 := head2; head2 := head3; head3 := eee.id+voffset
		    }
		  } 
		 };
		 /* construct faces */
		 printf "%g   %g %g %g %g density 0.5 \n",foffset+ff1,
		    -(ff1*3+eoffset),ff1*3+eoffset+1,
		    ff2*3+eoffset,-(ff1*3+eoffset+2);
		 printf "%g   %g %g %g %g density 0.5\n",foffset+ff2,
		    -(ff2*3+eoffset),ff2*3+eoffset+1,
		    ff3*3+eoffset,-(ff2*3+eoffset+2);
		 printf "%g   %g %g %g %g density 0.5\n",foffset+ff3,
		    -(ff3*3+eoffset),ff3*3+eoffset+1,
		    ff1*3+eoffset,-(ff3*3+eoffset+2);
               };
	       /* node triangle facets */
	       nodemode := 1;
	       triangles;
            } /* end wetfaces */


/* print body list */
wetbodies := { printf "\nbodies \n";
               ss := spread*avg(edge where valence==2,length);
	       border_volume := sum(edge where valence==3,length)*
	          ss*ss*0.8;
	       foreach body bod do 
		 { printf "%g   ",bod.id;
		   linecount := 0;
		   /* first, old facets */
		   foreach bod.facet do 
		   { printf "%g ",oid;
		     linecount := linecount + 1;
		     if ( linecount >= 10 )  then
		       { printf "\\\n    "; linecount := 0; }
                   };
                   /* now, tube faces around triple lines */
	           foreach edge ee where valence == 3 do
	           { foreach ee.vertex vv do { vv1 := vv2; vv2 := vv.id };
		     foreach ee.facet ff do
		     { side  := 0;
		       foreach ff.body do 
			{ if side == 1 and id == bod.id then
		          { printf "%g ",-(ff.id+foffset);
		            linecount := linecount + 1;
		            if ( linecount >= 10 ) then 
			      { printf "\\\n    "; linecount := 0; }
                          };
			  side := side + 1;
			};
                      }
		    };
		    /* node triangles */
		    nodemode := 3; nodebody := bod.id;
		    triangles;
		    printf "volume %g",bod.volume - border_volume/body_count;
		    printf "\n";
                 };  /* end foreach body */

                 /* and body for Plateau border */ 
		 printf "%g   ",body_count ? max(body,id)+1 : 1;
		 linecount := 0;
	         foreach edge ee where valence == 3 do
	           { foreach ee.vertex vv do { vv1 := vv2; vv2 := vv.id };
		     foreach ee.facet ff do
		     { printf "%g ",ff.id+foffset;
		       linecount := linecount + 1;
		       if ( linecount >= 10 ) then
			 { printf "\\\n    "; linecount := 0; }
                      }
                    };
	         /* node triangles */
		 nodemode := 2;
		 triangles;
		 printf "volume %g",border_volume;
		 printf "\n";
     } /* end wetbodies */

wetfoam := { wettests; list topinfo; wetverts; wetedges; wetfaces; wetbodies;
 /* printf"\n\nDebug\n";   nodemode := 4; triangles; printf "\n" */      }


