/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* isect.c GRAPHICS * * maart/april 1992 (traces) * maart 95 * * */ #include "blender.h" #include "edit.h" extern short cox, coy; /* scanfill.c */ extern ListBase fillvertbase, filledgebase; /* scanfill.c */ extern EditVert *addvertlist(); typedef struct ISEdge { struct ISEdge *next,*prev; EditVert *v1,*v2; EditVlak *vl1,*vl2; short edflag1,edflag2; } ISEdge; ListBase isedgebase = {0,0}; ListBase isvertbase = {0,0}; /* **** ARITH *************************** */ short IsectFL(v1,v2,v3,v4,v5,vec) /* Intersect Face and Linesegment */ float *v1,*v2,*v3,*v4,*v5,*vec; /* 1,2,3=face 4,5=line vec=answer */ { /* return: -1: colliniar 0: no intersection 1: exact intersection of edge and line 2: cross-intersection */ double x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22; double m0,m1,m2,deeldet,det1,det2,det3; double rtu,rtv,rtlabda; t00= (double)v3[0]-(double)v1[0]; t01= (double)v3[1]-(double)v1[1]; t02= (double)v3[2]-(double)v1[2]; t10= (double)v3[0]-(double)v2[0]; t11= (double)v3[1]-(double)v2[1]; t12= (double)v3[2]-(double)v2[2]; t20= (double)v4[0]-(double)v5[0]; t21= (double)v4[1]-(double)v5[1]; t22= (double)v4[2]-(double)v5[2]; x0=t11*t22-t12*t21; x1=t12*t20-t10*t22; x2=t10*t21-t11*t20; deeldet=t00*x0+t01*x1+t02*x2; if(deeldet==0.0) return -1; m0= (double)v4[0]-(double)v3[0]; m1= (double)v4[1]-(double)v3[1]; m2= (double)v4[2]-(double)v3[2]; det1=m0*x0+m1*x1+m2*x2; rtu= det1/deeldet; if(rtu<=0.0) { det2=t00*(m1*t22-m2*t21); det2+=t01*(m2*t20-m0*t22); det2+=t02*(m0*t21-m1*t20); rtv= det2/deeldet; if(rtv<=0.0) { if(rtu+rtv>= -1.0) { det3=t00*(t11*m2-t12*m1); det3+=t01*(t12*m0-t10*m2); det3+=t02*(t10*m1-t11*m0); rtlabda=det3/deeldet; if(rtlabda>= 0.0 && rtlabda<=1.0) { vec[0]= v4[0]+ rtlabda*(v5[0]-v4[0]); vec[1]= v4[1]+ rtlabda*(v5[1]-v4[1]); vec[2]= v4[2]+ rtlabda*(v5[2]-v4[2]); if(rtu==0.0 || rtv==0.0 || (rtu+rtv== -1.0) || rtlabda==0.0 || rtlabda==1.0) return 1; return 2; } } } } return 0; } short IsectLL(v1,v2,v3,v4,cox,coy,labda,mu,vec) /* intersect Line-Line */ float *v1,*v2,*v3,*v4; /* vertices */ short cox,coy; /* projection */ float *labda,*mu,*vec; /* = answer */ { /* return: -1: colliniar 0: no intersection of segments 1: exact intersection of segments 2: cross-intersection of segments */ float deler; deler= (v1[cox]-v2[cox])*(v3[coy]-v4[coy])-(v3[cox]-v4[cox])*(v1[coy]-v2[coy]); if(deler==0.0) return -1; *labda= (v1[coy]-v3[coy])*(v3[cox]-v4[cox])-(v1[cox]-v3[cox])*(v3[coy]-v4[coy]); *labda= -(*labda/deler); deler= v3[coy]-v4[coy]; if(deler==0) { deler=v3[cox]-v4[cox]; *mu= -(*labda*(v2[cox]-v1[cox])+v1[cox]-v3[cox])/deler; } else { *mu= -(*labda*(v2[coy]-v1[coy])+v1[coy]-v3[coy])/deler; } vec[cox]= *labda*(v2[cox]-v1[cox])+v1[cox]; vec[coy]= *labda*(v2[coy]-v1[coy])+v1[coy]; if(*labda>=0.0 && *labda<=1.0 && *mu>=0.0 && *mu<=1.0) { if(*labda==0.0 || *labda==1.0 || *mu==0.0 || *mu==1.0) return 1; return 2; } return 0; } /* **** INTERSECT ******************** */ int count_comparevlak(vl1, vl2) EditVlak *vl1, *vl2; { EditVert *v1, *v2, *v3; int tot= 0; if(vl1->v4 && vl2->v4) { } else if(vl1->v4==0 && vl2->v4==0) { v1= vl2->v1; v2= vl2->v2; v3= vl2->v3; if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) tot++; if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) tot++; if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) tot++; } return tot; } void empty() { } /* #define printf empty */ void addisedge(vec,edflag,vl1,vl2,tel) float *vec; short *edflag; EditVlak *vl1,*vl2; short tel; { /* maakt edge en zo nodig nieuwe vertices */ ISEdge *ise; EditVert *eve,*v1=0,*v2=0; float swapvec[3]; short sw; /* test op volgorde snijpunten, dubbels swappen */ if(tel>2) { if(FloatCompare(vec, vec+3, COMPLIMIT)) { VECCOPY(swapvec,vec); VECCOPY(vec,vec+6); VECCOPY(vec+6,swapvec); sw= edflag[0]; edflag[0]= edflag[2]; edflag[2]= sw; } } if(FloatCompare(vec, vec+3, COMPLIMIT)) return; /* test op dubbele vertices */ eve= isvertbase.first; while(eve) { if(v1==0) if(FloatCompare(eve->co,vec, COMPLIMIT)) v1= eve; if(v2==0) if(FloatCompare(eve->co,vec+3, COMPLIMIT)) v2= eve; if(v1!=0 && v2!=0) break; eve= eve->next; } if(v1!=0 || v2!=0) if(v1==v2) return; /* if(v1!=0) printf("double removed\n"); */ /* if(v2!=0) printf("double removed\n"); */ /* nieuwe vertices? */ if(v1==0) { v1= (EditVert *)calloc(sizeof(EditVert),1); addtail(&isvertbase,v1); VECCOPY(v1->co,vec); } if(v2==0) { v2= (EditVert *)calloc(sizeof(EditVert),1); addtail(&isvertbase,v2); VECCOPY(v2->co,vec+3); } /* de nieuwe ISEdge */ ise= (ISEdge *)calloc(sizeof(ISEdge),1); addtail(&isedgebase,ise); ise->v1= v1; ise->v2= v2; ise->vl1= vl1; ise->vl2= vl2; ise->edflag1= edflag[0]; ise->edflag2= edflag[1]; /* printf("edflag: %d %d %d %d\n",edflag[0],edflag[1],edflag[2],edflag[3]); */ if(tel>2) { if(FloatCompare(vec+6,vec, COMPLIMIT)) ise->edflag1|= edflag[2]; else ise->edflag2|= edflag[2]; if(tel>3) { if(FloatCompare(vec+9,vec, COMPLIMIT)) ise->edflag1|= edflag[3]; else ise->edflag2|= edflag[3]; } } /* printf("edflag: %d %d \n",ise->edflag1,ise->edflag2); */ } void oldedsort_andmake(olded, edcount, proj) EditVert **olded; int edcount, proj; { EditVert *eve; int a, ok= 1; if(edcount==2) { ok= 0; } while(ok) { ok= 0; for(a=1; aco[proj] > olded[a]->co[proj]) { eve= olded[a-1]; olded[a-1]= olded[a]; olded[a]= eve; ok= 1; } } } for(a=1;a=y && x>=z) return 0; else if(y>=x && y>=z) return 1; return 2; } void newfillvert(v1) EditVert *v1; { /* v1 is vert uit ISEdge struct bestaat deze al in fill lijst ? */ EditVert *eve,*vn; eve= fillvertbase.first; while(eve) { if(eve->vn==v1) return; eve= eve->next; } eve= addfillvert(v1->co); v1->vn= eve; eve->vn= v1; } void addisfaces(evl) EditVlak *evl; { /* -pak alle ISEdges bij elkaar en genereer filledge lijst -genereer fillvert lijst (geen dubbels) ise->v1,v2: nieuwe vertices ise->vl1,vl2: vlakken waarin de voornoemde edges liggen. ise->edflag: code welke edges zijn gesneden */ EditVlak *evln; ISEdge *ise; EditVert *eve,*v1,*v2,*v3,*nextve; EditEdge *eed; EditVert **olded1,**olded2,**olded3; int edcount1=2, edcount2=2, edcount3=2, edcount=0; int a, proj, ok=1, bitmask; /* printf("\n in addisfaces \n"); */ /* hoeveel edges doen mee? kun je oldedgeblock size berekenen */ ise= isedgebase.first; while(ise) { if(ise->vl1==evl || ise->vl2==evl) edcount++; ise= ise->next; } if(edcount==0) return; /* printf("edcount: %d\n",edcount); */ olded1= (EditVert **)mallocN(8+8*edcount,"addisfaces1"); olded2= (EditVert **)mallocN(8+8*edcount,"addisfaces2"); olded3= (EditVert **)mallocN(8+8*edcount,"addisfaces3"); olded1[0]= evl->v1; olded1[1]= evl->v2; olded2[0]= evl->v2; olded2[1]= evl->v3; olded3[0]= evl->v3; olded3[1]= evl->v1; /* fill edges maken en oldedge arrays maken*/ ise= isedgebase.first; while(ise) { if(ise->vl1==evl || ise->vl2==evl) { eed= addfilledge(ise->v1, ise->v2); bitmask= 1; if(evl== ise->vl2) bitmask= 8; /* moet olded1 doormidden? */ if(ise->edflag1 & bitmask) olded1[edcount1++]= ise->v1; if(ise->edflag2 & bitmask) olded1[edcount1++]= ise->v2; bitmask*=2; /* moet olded2 doormidden? */ if(ise->edflag1 & bitmask) olded2[edcount2++]= ise->v1; if(ise->edflag2 & bitmask) olded2[edcount2++]= ise->v2; bitmask*=2; /* moet olded3 doormidden? */ if(ise->edflag1 & bitmask) olded3[edcount3++]= ise->v1; if(ise->edflag2 & bitmask) olded3[edcount3++]= ise->v2; } ise= ise->next; } /* van oude edges vertices sorteren en filledges maken */ /* printf("edcount123 %d %d %d\n", edcount1, edcount2, edcount3); */ proj= maxco(evl->v1->co, evl->v2->co); oldedsort_andmake(olded1, edcount1, proj); proj= maxco(evl->v2->co, evl->v3->co); oldedsort_andmake(olded2, edcount2, proj); proj= maxco(evl->v3->co, evl->v1->co); oldedsort_andmake(olded3, edcount3, proj); freeN(olded1); freeN(olded2); freeN(olded3); /* - de filledges verwijzen naar oude(Edit) en nieuwe(Isect) vertices met deze verts een tijdelijke fill lijst maken - als een fillvert uiteindelijk een ->vn heeft is het een 'oude' vertex */ ise= isedgebase.first; while(ise) { if(ise->vl1==evl || ise->vl2==evl) { newfillvert(ise->v1); newfillvert(ise->v2); /* printf("verts uit ISEdge %x %x\n",ise->v1->vn, ise->v2->vn); */ } ise= ise->next; } /* oude vertices kopieeren, flag zetten */ v1= addfillvert(evl->v1->co); evl->v1->vn= v1; v1->vn= evl->v1; v1->f= 1; /* printf("oude vert %x\n",v1); */ v1= addfillvert(evl->v2->co); evl->v2->vn= v1; v1->vn= evl->v2; v1->f= 1; /* printf("oude vert %x\n",v1); */ v1= addfillvert(evl->v3->co); evl->v3->vn= v1; v1->vn= evl->v3; v1->f= 1; /* printf("oude vert %x\n",v1); */ /* nieuwe pointers in edges schrijven */ eed= filledgebase.first; edcount= 0; while(eed) { edcount++; eed->v1= eed->v1->vn; eed->v2= eed->v2->vn; /* printf("edge: %x %x\n",eed->v1,eed->v2); */ eed= eed->next; } /* printf("voor fill: %d edges\n",edcount); */ /* de ->vn pointers van nieuwe vertices wissen */ eve= fillvertbase.first; while(eve) { /* printf("vert: %x\n",eve); */ if(eve->f==0) eve->vn=0; eve= eve->next; } /* FILL */ ok= edgefill(0); /* (1) is kruispunten testen */ /* printf("FILL\n"); */ if(ok) { /* De nieuwe vlakken */ edcount= 0; evl= fillvlakbase.first; while(evl) { edcount++; v1= evl->v1->vn; if(v1==0) { v1= addvertlist(evl->v1->co); /* evl->v1->vn= v1; */ } v2= evl->v2->vn; if(v2==0) { v2= addvertlist(evl->v2->co); /* evl->v2->vn= v2; */ } v3= evl->v3->vn; if(v3==0) { v3= addvertlist(evl->v3->co); /* evl->v3->vn= v3; */ } evln= addvlaklist(v1, v2, v3, 0, evl->mat_nr, evl->flag, evl->tface); evln->f= 3; /* printf("EdVl %x %x %x\n",v1,v2,v3); */ evl= evl->next; } /* printf("Na fill: %d vlakken\n", edcount); */ } else printf("error in fill\n"); end_edgefill(); } void intersect_mesh() { static long numberofcalls=0; ISEdge *ise; EditVlak *evl,*evl1,*evl2,**eld,**evlist,*nextvl; EditVert *eve,*v1,*v2; EditEdge *eed, *nexted, *edar[8]; float min[3], max[3], afm[3], vec[15], *fp; ulong *octlist, *oct, *oct1; long a, b, c, totvlak; short ok, tel, oc1, oc2, oc3, ocmin, ocmax, edflag[8]; if(G.obedit==0 || G.obedit->type!=OB_MESH) return; /* (voorlopig) alles naar driehoeken omzetten */ convert_to_triface(0); /* 0=alleen selected */ isedgebase.first=isedgebase.last= 0; isvertbase.first=isvertbase.last= 0; /* array van vlakpointers maken */ evl= G.edvl.first; totvlak= 0; while(evl) { if( (evl->v1->f & 1) && (evl->v2->f & 1) && (evl->v3->f & 1) ) { totvlak++; evl->f= 1; } else evl->f= 0; evl= evl->next; } if(totvlak<2) return; waitcursor(1); eld=evlist= (EditVlak **)mallocN(totvlak*4,"intersectVV"); evl= G.edvl.first; while(evl) { if(evl->f==1) { *(eld++)= evl; } evl= evl->next; } /* min en max bepalen */ eld= evlist; min[0]=min[1]=min[2]= 1.0e20; max[0]=max[1]=max[2]= -1.0e20; for(a=0;av1->co[c],evl->v2->co[c],evl->v3->co[c]); max[c]= MAX4(max[c],evl->v1->co[c],evl->v2->co[c],evl->v3->co[c]); } } /* array octreegetallen maken en invullen */ oct=octlist= (ulong *)callocN(totvlak*12,"intersectVV2"); afm[0]= max[0]-min[0]+0.0001; afm[1]= max[1]-min[1]+0.0001; afm[2]= max[2]-min[2]+0.0001; eld= evlist; for(a=0;av1->co[c]-min[c])/afm[c]); oc2= (short)(31.9*(evl->v2->co[c]-min[c])/afm[c]); oc3= (short)(31.9*(evl->v3->co[c]-min[c])/afm[c]); ocmin= MIN3(oc1, oc2, oc3); ocmax= MAX3(oc1, oc2, oc3); for(b=ocmin; b<=ocmax; b++) { *oct= BSET(*oct, b); } oct++; } } eed= G.eded.first; while(eed) { eed->f= 0; eed= eed->next; } /* snijlus */ eld= evlist; oct= octlist; for(a=0;av1->co,evl->v2->co,evl->v3->co,evl1->v1->co,evl1->v2->co,fp)>0) { edflag[tel]= 1; edar[tel]= evl1->e1; tel++; fp+=3; } if(IsectFL(evl->v1->co,evl->v2->co,evl->v3->co,evl1->v2->co,evl1->v3->co,fp)>0) { edflag[tel]= 2; edar[tel]= evl1->e2; tel++; fp+=3; } if(IsectFL(evl->v1->co,evl->v2->co,evl->v3->co,evl1->v3->co,evl1->v1->co,fp)>0) { edflag[tel]= 4; edar[tel]= evl1->e3; tel++; fp+=3; } if(IsectFL(evl1->v1->co,evl1->v2->co,evl1->v3->co,evl->v1->co,evl->v2->co,fp)>0) { edflag[tel]= 8; edar[tel]= evl->e1; tel++; fp+=3; } if(IsectFL(evl1->v1->co,evl1->v2->co,evl1->v3->co,evl->v2->co,evl->v3->co,fp)>0) { edflag[tel]= 16; edar[tel]= evl->e2; tel++; fp+=3; } if(IsectFL(evl1->v1->co,evl1->v2->co,evl1->v3->co,evl->v3->co,evl->v1->co,fp)>0) { edflag[tel]= 32; edar[tel]= evl->e3; tel++; fp+=3; } /* printf("aantal snijps: %d\n",tel); */ /* intersect edge gevonden? */ if(tel>=2) { addisedge(vec, edflag, evl1, evl, tel); for(tel--;tel>=0;tel--) { if(edar[tel]) edar[tel]->f= 1; } evl->f= 2; evl1->f= 2; } } } oct1+=3; } oct+=3; } /* DEBUG: nu even tijdelijk de snijedges wegschrijven? ise= isedgebase.first; while(ise) { v1= addvertlist(ise->v1->co); v2= addvertlist(ise->v2->co); addedgelist(v1,v2); ise= ise->next; } */ /* gesneden edges verwijderen */ eed= G.eded.first; while(eed) { nexted= eed->next; if(eed->f) { /* printf("edge verwijderd %x %x\n",eed->v1,eed->v2); */ remedge(eed); } eed= nexted; } /* nieuwe vlakken maken met fill en verwijderen */ eld= evlist; for(a=0; af==2) { addisfaces(evl); remlink(&G.edvl, evl); /* printf("vlak verwijderd %x %x %x\n",evl->v1,evl->v2,evl->v3); */ } } freeN(evlist); freeN(octlist); freelist(&isedgebase); freelist(&isvertbase); /* BEVEILIGING */ /* #undef printf */ /* loop edgelijst af en controleer of alle vertices bestaan */ eve= G.edve.first; v1= (EditVert *)numberofcalls; numberofcalls++; while(eve) { eve->vn= v1; eve= eve->next; } a= 0; eed= G.eded.first; while(eed) { nexted= eed->next; if(eed->v1->vn!=v1 || eed->v2->vn!=v1) { a++; remlink(&G.eded, eed); } eed= nexted; } if(a) printf("error na intersect: %d edges wijzen naar niet bestaande vertices\n", a); /* loop vlakkenlijst af en controleer of alle edges bestaan */ a= 0; evl= G.edvl.first; while(evl) { /* nieuw vlak */ if(evl->f==3) { evl->e1= findedgelist(evl->v1,evl->v2); if(evl->e1==0) { a++; evl->e1= addedgelist(evl->v1,evl->v2); } evl->e2= findedgelist(evl->v2,evl->v3); if(evl->e2==0) { a++; evl->e2= addedgelist(evl->v2,evl->v3); } evl->e3= findedgelist(evl->v3,evl->v1); if(evl->e3==0) { a++; evl->e3= addedgelist(evl->v3,evl->v1); } } evl= evl->next; } if(a) printf("error na intersect: %d edges in vlakken bestonden niet\n", a); /* HET UIT ELKAAR PLUKKEN VAN DE ONDERDELEN */ /* nu zijn alle oude select, zet f1 flag */ eve= G.edve.first; while(eve) { if(eve->h==0) { if(eve->f & 1) { eve->f1= 1; } eve->f= 0; } eve= eve->next; } /* begin met een oude vertex, selecteer connected zonder nieuwe vertices * te passeren, removedoubles en clear f1 vlag. */ eve= G.edve.first; while(eve) { if(eve->f1==1) { ok= 1; while(ok) { ok= 0; eve->f= 1; eed= G.eded.first; while(eed) { if(eed->h==0) { if( (eed->v1->f & 1) && (eed->v2->f & 1)==0) { eed->v2->f= 1; ok= 1; } else if( (eed->v2->f & 1) && (eed->v1->f & 1)==0) { eed->v1->f= 1; ok= 1; } } eed= eed->next; } } removedoublesflag(1, (float)0.0003); /* en flags wissen */ v1= G.edve.first; while(v1) { if(v1->f & 1) { v1->f= 0; v1->f1= 0; } v1= v1->next; } eve= G.edve.first; /* ivm removedoubles */ } eve= eve->next; } waitcursor(0); countall(); allqueue(REDRAWVIEW3D, 0); }