TOOLS3.C

Go to the documentation of this file.
00001 /* --
00002 OpenFX - Modelling, Animation and Rendering Package
00003 -- */
00004 
00005 
00006 /* file TOOLS3.C  designer's 3rd tools file */
00007 
00008 #define MODULE_TOOLS3 1
00009 
00010 #include "design.h"
00011 
00012 
00013 void ShatterEffect(void){
00014  face *fp;
00015  FILE *tf;
00016  vertex *vp1,*vp2,*vp3;
00017  long count,i,k,v1,v2,v3;
00018  char workfile[64];
00019  char t1[64],t2[64];
00020  Save_Undo(2);
00021  if(NvertSelect == 0 || MainFp == NULL){
00022    SendPrgmQuery(IDQ_NOSHATTER,0);
00023    return;
00024  }
00025  if(NvertSelect > 32000){
00026    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00027    return;
00028  }
00029  LoadString(ghinst_main,IDX_MISC_CONFIRM,t1,63);
00030  LoadString(ghinst_main,IDS_DEFAULT,t2,63);
00031  if(MessageBox(NULL,t1,t2,
00032                MB_YESNO|MB_ICONQUESTION|MB_TASKMODAL) != IDYES)return;
00033  count=0;
00034  sprintf(workfile,"%swork_$.$$$",TempPath);
00035  if((tf=fopen(workfile,"wb")) == NULL){
00036    SendPrgmQuery(IDQ_TFWE,0);
00037    return;
00038  }
00039  fp=MainFp; for(k=0;k<Nface;k++){
00040    vp1=(MainVp+fp->V[0]); vp2=(MainVp+fp->V[1]); vp3=(MainVp+fp->V[2]);
00041    if(vp1->status == SELECTED ||
00042       vp1->status == SELECTED ||
00043       vp1->status == SELECTED){
00044      count++;
00045      if((fwrite(vp1->xyz,sizeof(long),3,tf) != 3) ||
00046         (fwrite(vp2->xyz,sizeof(long),3,tf) != 3) ||
00047         (fwrite(vp3->xyz,sizeof(long),3,tf) != 3) ||
00048         (fwrite(fp->color,sizeof(unsigned char),3,tf) != 3) ||
00049         (fwrite(&fp->bSmooth,sizeof(unsigned char),1,tf) != 1) ||
00050         (fwrite(&fp->imagemap,sizeof(short),1,tf) != 1) ||
00051         (fwrite(&fp->material,sizeof(short),1,tf) != 1)){
00052        SendPrgmQuery(IDQ_TFWE,0);
00053        fclose(tf);
00054        remove(workfile);
00055        return;
00056      }
00057    }
00058    fp++;
00059  }
00060  fclose(tf);
00061  if(count > 0){
00062    if((tf=fopen(workfile,"rb")) == NULL){
00063      SendPrgmQuery(IDQ_NOOPENWORKFILE,0);
00064      return;
00065    }
00066    EraseVertex(0);
00067    if(!UpdateVertexHeap(Nvert+count*3))goto EP1;
00068    if(!UpdateEdgeHeap(Nedge+count*3))goto EP1;
00069    if(!UpdateFaceHeap(Nface+count))goto EP1;
00070    for(i=0;i<count;i++){
00071      CreateVertex(); v1=Nvert-1; vp1=(MainVp+v1);
00072      CreateVertex(); v2=Nvert-1; vp2=(MainVp+v2);
00073      CreateVertex(); v3=Nvert-1; vp3=(MainVp+v3);
00074      CreateEdge(v1,v2);
00075      CreateEdge(v2,v3);
00076      CreateEdge(v3,v1);
00077      CreateFace(v1,v2,v3); fp=(MainFp+Nface-1);
00078      fread(vp1->xyz,sizeof(long),3,tf);
00079      fread(vp2->xyz,sizeof(long),3,tf);
00080      fread(vp3->xyz,sizeof(long),3,tf);
00081      fread(fp->color,sizeof(unsigned char),3,tf);
00082      fread(&fp->bSmooth,sizeof(unsigned char),1,tf);
00083      fread(&fp->imagemap,sizeof(short),1,tf);
00084      fread(&fp->material,sizeof(short),1,tf);
00085    }
00086    UpdateCounters();
00087    fclose(tf);
00088  }
00089  remove(workfile);
00090  return;
00091  EP1:
00092  SendPrgmQuery(IDQ_NOMEM1,0);
00093  DrawModel();
00094  UpdateCounters();
00095  fclose(tf);
00096  remove(workfile);
00097  return;
00098 }
00099 
00100 long *GetPathList(long *np){
00101  vertex *Vp;
00102  long vp,vf,*va;
00103  double d,dmin,drange;
00104  long Npath=0;
00105  if(NvertSelect < 1)return NULL;
00106  dmin=(double)TVsizeX*(double)TVsizeX;
00107  drange=dmin/1024;
00108  vf= -1; vp=0; while(vp < Nvert){
00109    Vp=(MainVp+vp);
00110    if(Vp->status == SELECTED && intriview(Vp)){
00111      d=(double)(Vp->xyz[0]-NpointerX)*(double)(Vp->xyz[0]-NpointerX)
00112       +(double)(Vp->xyz[1]-NpointerY)*(double)(Vp->xyz[1]-NpointerY)
00113       +(double)(Vp->xyz[2]-NpointerZ)*(double)(Vp->xyz[2]-NpointerZ);
00114      if(d < dmin && d < drange){
00115        dmin=d;
00116        vf=vp;
00117      }
00118    }
00119    Vp->id=0; /* use this bit for found flag */
00120    vp++;
00121  }
00122  if(vf < 0){
00123    SendPrgmQuery(IDQ_NOPATHSTART,0);
00124    return NULL;
00125  }
00126  if((va=(long *)X__Malloc(NvertSelect*sizeof(long))) == NULL){
00127    SendPrgmQuery(IDQ_NOMEM2,0);
00128    return NULL;
00129  }
00130  Npath=0; va[0]=vf; (MainVp+va[0])->id=1;
00131  (MainVp+vf)->status=DESELECTED; NvertSelect--; NvertDeselect++;
00132  vp=0; while(vp < Nvert){
00133    Vp=(MainVp+vp);
00134    if(Vp->status == SELECTED && Vp->id == 0 && connected(va[Npath],vp)){
00135      Npath++;
00136      va[Npath]=vp;
00137      Vp->id=1;
00138      Vp->status=DESELECTED;
00139      NvertSelect--; NvertDeselect++;
00140      vp=0;
00141    }
00142    else vp++;
00143  }
00144  Npath++;
00145  *np=Npath;
00146  return va;
00147 }
00148 
00149 static void SetAccurateControl(HWND hwnd,int ID, double value){
00150  char tempstr[16];
00151  sprintf(tempstr,"%.2lf",value);
00152  SendDlgItemMessage(hwnd,ID,WM_SETTEXT,0,(LPARAM)tempstr);
00153  SendDlgItemMessage(hwnd,ID,EM_LIMITTEXT,(WPARAM)12,0);
00154 }
00155 
00156 static double GetAccurateControl(HWND hwnd,int ID, double value){
00157  char tempstr[16];
00158  if(GetDlgItemText(hwnd,ID,tempstr,12) == 0)return value;
00159  value=atof(tempstr);
00160  return value;
00161 }
00162 
00163 BOOL CALLBACK BuildAccurateCurveDlgProc(HWND hwnd, UINT msg,
00164                                     WPARAM wparam, LPARAM lparam){
00165  static double x,y,z,rx,ry,rz,x0,y0,z0;
00166  static long LastAccurateVertex= -1;
00167  static BOOL locked;
00168  switch( msg ) {
00169    case WM_PAINT:
00170      PaintDialogBackground(hwnd,ghinst_main);
00171      break;
00172    case WM_INITDIALOG:
00173      x0=x=(double)(NpointerX-rulerx)/ruler; rx=0.0;
00174      y0=y=(double)(NpointerY-rulery)/ruler; ry=0.0;
00175      z0=z=(double)(NpointerZ-rulerz)/ruler; rz=0.0;
00176      locked=TRUE;
00177      SetAccurateControl(hwnd,DLG_BUILD_AX,x);
00178      SetAccurateControl(hwnd,DLG_BUILD_AY,y);
00179      SetAccurateControl(hwnd,DLG_BUILD_AZ,z);
00180      SetAccurateControl(hwnd,DLG_BUILD_RX,rx);
00181      SetAccurateControl(hwnd,DLG_BUILD_RY,ry);
00182      SetAccurateControl(hwnd,DLG_BUILD_RZ,rz);
00183      locked=FALSE;
00184      CentreDialogOnCursor(hwnd);
00185      return (TRUE);
00186    case WM_COMMAND:
00187       switch(HIWORD(wparam)){
00188         case EN_CHANGE:
00189           if(LOWORD(wparam) == DLG_BUILD_AX && !locked){
00190             locked=TRUE;
00191             x=GetAccurateControl(hwnd,DLG_BUILD_AX,x);
00192             rx=x-x0;
00193             SetAccurateControl(hwnd,DLG_BUILD_RX,rx);
00194             locked=FALSE;
00195           }
00196           else if(LOWORD(wparam) == DLG_BUILD_RX && !locked){
00197             locked=TRUE;
00198             rx=GetAccurateControl(hwnd,DLG_BUILD_RX,rx);
00199             x=x0+rx;
00200             SetAccurateControl(hwnd,DLG_BUILD_AX,x);
00201             locked=FALSE;
00202           }
00203           if(LOWORD(wparam) == DLG_BUILD_AY && !locked){
00204             locked=TRUE;
00205             y=GetAccurateControl(hwnd,DLG_BUILD_AY,y);
00206             ry=y-y0;
00207             SetAccurateControl(hwnd,DLG_BUILD_RY,ry);
00208             locked=FALSE;
00209           }
00210           else if(LOWORD(wparam) == DLG_BUILD_RY && !locked){
00211             locked=TRUE;
00212             ry=GetAccurateControl(hwnd,DLG_BUILD_RY,ry);
00213             y=y0+ry;
00214             SetAccurateControl(hwnd,DLG_BUILD_AY,y);
00215             locked=FALSE;
00216           }
00217           if(LOWORD(wparam) == DLG_BUILD_AZ && !locked){
00218             locked=TRUE;
00219             z=GetAccurateControl(hwnd,DLG_BUILD_AZ,z);
00220             rz=z-z0;
00221             SetAccurateControl(hwnd,DLG_BUILD_RZ,rz);
00222             locked=FALSE;
00223           }
00224           else if(LOWORD(wparam) == DLG_BUILD_RZ && !locked){
00225             locked=TRUE;
00226             rz=GetAccurateControl(hwnd,DLG_BUILD_RZ,rz);
00227             z=z0+rz;
00228             SetAccurateControl(hwnd,DLG_BUILD_AZ,z);
00229             locked=FALSE;
00230           }
00231           break;
00232         default: break;
00233       }
00234       switch(LOWORD(wparam)){
00235         case DLG_BUILD_START:
00236           LastAccurateVertex= -1;
00237         case DLG_BUILD_MAKE:
00238           UpdateVertexHeap(Nvert+1);  CreateVertex();
00239           (MainVp+Nvert-1)->xyz[0]=(long)(x*ruler)+rulerx;
00240           (MainVp+Nvert-1)->xyz[1]=(long)(y*ruler)+rulery;
00241           (MainVp+Nvert-1)->xyz[2]=(long)(z*ruler)+rulerz;
00242           DrawVerticesOnly((MainVp+Nvert-1));
00243           if(LastAccurateVertex >= 0){
00244             UpdateEdgeHeap(Nedge+1);
00245             CreateEdge(Nvert-1,LastAccurateVertex);
00246             DrawOneEdgeOnly((MainVp+Nvert-1),(MainVp+LastAccurateVertex));
00247           }
00248           LastAccurateVertex=Nvert-1;
00249           rx=ry=rz=0.0; x0=x; y0=y; z0=z;
00250           UpdateCounters();
00251           locked=TRUE;
00252           SetAccurateControl(hwnd,DLG_BUILD_AX,x);
00253           SetAccurateControl(hwnd,DLG_BUILD_AY,y);
00254           SetAccurateControl(hwnd,DLG_BUILD_AZ,z);
00255           SetAccurateControl(hwnd,DLG_BUILD_RX,rx);
00256           SetAccurateControl(hwnd,DLG_BUILD_RY,ry);
00257           SetAccurateControl(hwnd,DLG_BUILD_RZ,rz);
00258          locked=FALSE;
00259           break;
00260         case DLG_BUILD_DONE:
00261           LastAccurateVertex= -1;
00262           EndDialog(hwnd,0);
00263           return(TRUE);
00264         default:
00265           break;
00266       }
00267       break;
00268     default: break;
00269  }
00270  return(FALSE);
00271 }
00272 
00273 typedef struct FACEEDGE {
00274   long   v;
00275   long   last,next,inc;
00276   vector n;   /* normal defining plane with edge; plane parallel to curve N */
00277   vector p;   /* vector corresponding to vertex v */
00278 } faceedge;
00279 
00280 typedef struct FACEEDGELIST {
00281   struct FACEEDGE *f;
00282   long   n,I,done_count;
00283   vector normal;
00284 } faceedgelist;
00285 
00286 typedef struct NORMALS {
00287   vector n,nav;
00288 } normals;
00289 
00290 static void  ReverseCurve(faceedge *af, long Npath);
00291 static int CurveNormal(faceedgelist *fli);
00292 static void MakeNewCurveNormals(long i, faceedgelist *facelist);
00293 static long  CurveInside(faceedgelist *fl, long i, long Ncurves);
00294 static void RemakeTheCurve(long i, long Ncurves,faceedgelist *facelist);
00295 static int edge_is_internal(faceedge *af, long Npath,
00296                               long te, long ne, long fe,
00297                               vector new_normal, vector N,
00298                               int allow_all);
00299 static int edge_is_ok(long n,faceedge *f, vector ph, vector po,
00300                         long ex1, long ex2);
00301 static void BevelCurve(long Ncurves, faceedgelist *facelist, double d,
00302                        double angle, vector direction);
00303 static int point_inside_curve(vector v2, vector Nav, faceedge *af,
00304                                 long Npath, vector N);
00305 double GetDistanceFromCurves(point c_point, long Ncurves,
00306                              faceedgelist *facelist);
00307 
00308 static double bevel_angle=45.0;
00309 
00310 static void MakeNewCurveNormals(long i, faceedgelist *facelist){
00311  long j,k,Npath;
00312  faceedge *af;
00313  vector v1,v2,v3;
00314  Npath=facelist[i].n;
00315  af=facelist[i].f;
00316  for(j=0;j<Npath;j++){ /* need an inside edge */
00317    VECCOPY(af[j].p,v1)
00318    k=af[j].next;
00319    VECCOPY(af[k].p,v2)
00320    VECSUB(v2,v1,v3)
00321    O_normalize(v3);
00322    CROSS(v3,facelist[i].normal,af[j].n)
00323    O_normalize(af[j].n);
00324  }
00325 }
00326 
00327 static int edge_is_internal(faceedge *af, long Npath,
00328                               long te, long ne, long fe,
00329                               vector new_normal, vector N,
00330                               int allow_all){
00331  vector p0,p1,pa,pb,p10,pba,pc; /* p0/1 define the potential internal edge */
00332  vector pte,pne,pac,n,vi,da,db,p01,vilast;
00333  vector vj,pn,pnb;
00334  long i,j,k,le,cross_count=0,last_allowed;
00335  double mu,mu1,dmin,d0,d1,d01;
00336  VECCOPY(af[te].p,pa)
00337  VECCOPY(af[ne].p,pb)
00338  VECSUB(pb,pa,pte)
00339  if(O_normalize(pte) == FAIL)return 0;
00340  VECCOPY(af[ne].p,pa)
00341  VECCOPY(af[fe].p,pb)
00342  VECSUB(pb,pa,pne)
00343  if(O_normalize(pne) == FAIL)return 0;
00344  if((d0=DOT(pte,pne)) > 0.9999){  /* 0.99 is too restrictive */
00345    return 0; /* co-linear */
00346  }
00347  else if(allow_all == 0 && d0 < -0.95){
00348    return 0; /* angle too acute */
00349  }
00350  VECCOPY(af[te].p,p0)
00351  VECCOPY(af[fe].p,p1)
00352  VECSUB(p1,p0,p10)
00353  VECCOPY(p10,p01)
00354  if(O_normalize(p01) == FAIL)return 0;
00355  CROSS(p01,N,new_normal)
00356  if(O_normalize(new_normal) == FAIL)return 0;
00357  VECSCALE(0.5,p10,pc)
00358  VECSUM(p0,pc,pc)      /* half way along new edge  */
00359  last_allowed = -1;    /* id of last edge with intersect at end*/
00360  for(i=0;i<Npath;i++){ /* check to see if internal */
00361    if(af[i].inc == 1){
00362      VECCOPY(af[i].p,pa)
00363      j=af[i].next;
00364      VECCOPY(af[j].p,pb)
00365      VECCOPY(af[i].n,n)
00366      VECSUB(pa,pc,pac)
00367      mu1=DOT(n,new_normal);
00368      if(fabs(mu1) > 0.0001){
00369        mu=DOT(pac,n)/mu1;
00370        if(mu > 0.0000){ /* look for intersections on one side */
00371          VECSCALE(mu,new_normal,vi) /* intersection to plane of test edge */
00372          VECSUM(pc,vi,vi)
00373          VECSUB(pb,pa,pba)
00374          k = -1; dmin = 1.0;
00375          if(fabs(pba[0]) > dmin){k=0; dmin =fabs(pba[0]);}
00376          if(fabs(pba[1]) > dmin){k=1; dmin =fabs(pba[1]);}
00377          if(fabs(pba[2]) > dmin){k=2; dmin =fabs(pba[2]);}
00378          if(k >= 0){
00379            mu1=(vi[k]-pa[k])/pba[k];
00380            if(fabs(mu1) < 0.0000001){ /* at start of segment */
00381              k=af[i].last;  /* for vector leading up to edge i */
00382              VECCOPY(af[k].p,pn)
00383              VECSUB(pa,pn,pnb)
00384              d0=DOT(pba,p01); d1=DOT(pnb,p01);
00385              if(d0*d1 > 0.0 && k != last_allowed){
00386                cross_count++;
00387              }
00388            }
00389            else if(fabs(1.0-mu1) < 0.0000001){
00390              k=af[j].next;   /* k is at end of edge next to end of i  */
00391              VECCOPY(af[k].p,pn)
00392              VECSUB(pn,pb,pnb)
00393              d0=DOT(pba,p01); d1=DOT(pnb,p01);
00394              if(d0*d1 > 0.0){
00395                cross_count++; last_allowed=i;
00396              }
00397            }
00398            else if(mu1 > 0.0 && mu1 < 1.0){
00399              cross_count++;
00400            }
00401          }
00402        }
00403      }
00404    }
00405  }
00406  if(cross_count%2 == 0)return 0; /* external to curve */
00407  le = af[te].last;
00408  for(i=0;i<Npath;i++){ /* check for edge in way */
00409    /* if either end of the edge is at the same place as vertices at        */
00410    /* TE or LE then it must be ignored (it is probably a hole join         */
00411    /* we also must not consider edges taking part in the possible new edge */
00412    /* edges with a vertex at the same place as NE must be considered       */
00413    if( !( i == le || i == te || i == ne || i == fe)  && af[i].inc == 1){
00414      j=af[i].next;
00415      VECCOPY(af[i].p,pa)
00416      VECCOPY(af[j].p,pb)
00417      VECCOPY(af[i].n,n)
00418      VECSUB(pa,p0,da)  d0=DOT(da,n);
00419      VECSUB(pa,p1,db)  d1=DOT(db,n);
00420      d01=d0*d1;
00421      if(d01 < 0.0){ /* new edge crosses other edge plane, is it inside ? */
00422        mu1=DOT(p10,n);
00423        if(fabs(mu1) > 1.0){
00424          mu=d0/mu1;
00425          VECSCALE(mu,p10,vi)
00426          VECSUM(p0,vi,vi)
00427          VECSUB(pb,pa,pba)
00428          k = -1; dmin = 1.0;
00429          if(fabs(pba[0]) > dmin){k=0; dmin =fabs(pba[0]);}
00430          if(fabs(pba[1]) > dmin){k=1; dmin =fabs(pba[1]);}
00431          if(fabs(pba[2]) > dmin){k=2; dmin =fabs(pba[2]);}
00432          if(k >= 0){
00433            mu1=(vi[k]-pa[k])/pba[k];
00434            if(mu1 >= -0.0001 && mu1 < 1.0001){
00435              return 0;
00436            }
00437          }
00438        }
00439      }
00440    }
00441  }
00442  return 1;
00443 }
00444 
00445 static int CurveNormal(faceedgelist *fli){
00446 /* return a normal to the plane of the curve, the normal may point to */
00447 /* either side a consistant normal will be calculated later.          */
00448 /* This must use the Vertex pointer since the curve point vector has  */
00449 /* not yet been assigned.                                             */
00450  long i,j,Npath;
00451  faceedge *af;
00452  vector v1,v2,v3,new_normal;
00453  Npath=fli->n;
00454  af=fli->f;
00455  POINT2VECTOR((MainVp+(af[0].v))->xyz,v1)
00456  j=1; /* try to get the normal to the plane */
00457  RETRY:
00458  for(i=1;i<Npath-j;i++){
00459    POINT2VECTOR((MainVp+(af[i  ].v))->xyz,v2)
00460    POINT2VECTOR((MainVp+(af[i+j].v))->xyz,v3)
00461    VECSUB(v2,v1,v2)
00462    VECSUB(v3,v1,v3)
00463    if(O_normalize(v2) != FAIL && O_normalize(v3) != FAIL &&
00464      fabs(DOT(v2,v3)) < 0.9){
00465      CROSS(v2,v3,new_normal)
00466      if(O_normalize(new_normal) != FAIL){
00467        goto GOTNORMAL;
00468      }
00469    }
00470  }
00471  if(j < Npath-3){
00472    j++;
00473    goto RETRY;
00474  }
00475  SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00476  return FAIL;
00477  GOTNORMAL:
00478  VECCOPY(new_normal,fli->normal);
00479  return OK;
00480 }
00481 
00482 static long CurveInside(faceedgelist *fl, long ii, long Ncurves){
00483 /* this may use either the vertex pointer or vertex vector since they */
00484 /* are still co-incident at this point in the algorithm               */
00485  vector pc,p0,p1,p10,p01,new_normal,pa,pb,n,pac,pn,pnb,pba,vi;
00486  long i,j,k,l,cross_count,Npath,curvid = -1;
00487  double mu,mu1,dmin,mumin,mumumin=1.0e35;
00488  faceedge *af;
00489  af=fl[ii].f;
00490  POINT2VECTOR((MainVp+(af[0].v))->xyz,p0)
00491  POINT2VECTOR((MainVp+(af[1].v))->xyz,p1)
00492  VECSUB(p1,p0,p10)
00493  VECCOPY(p10,p01)
00494  if(O_normalize(p01) == FAIL)return -1;
00495  CROSS(p01,fl[ii].normal,new_normal)
00496  if(O_normalize(new_normal) == FAIL)return -1; /* rt angl to first edge */
00497  VECSCALE(0.5,p10,pc)
00498  VECSUM(p0,pc,pc)   /* mid point of first edge */
00499  for(l=0;l<Ncurves;l++){
00500    if(l == ii)continue;
00501    cross_count=0;
00502    af=fl[l].f;
00503    Npath=fl[l].n;
00504    mumin=1.0e35;
00505    for(i=0;i<Npath;i++){ /* check to see if new_normal crosses edges in path */
00506      POINT2VECTOR((MainVp+(af[i].v))->xyz,pa)
00507      j=af[i].next;
00508      POINT2VECTOR((MainVp+(af[j].v))->xyz,pb)
00509      VECCOPY(af[i].n,n)
00510      VECSUB(pa,pc,pac)
00511      mu1=DOT(n,new_normal);
00512      if(fabs(mu1) > 0.0001){
00513        mu=DOT(pac,n)/mu1;
00514        if(mu > 0.0000){   /* look for intersections on one side */
00515          VECSCALE(mu,new_normal,vi)
00516          VECSUM(pc,vi,vi) /* intersection to plane of test edge */
00517          VECSUB(pb,pa,pba)
00518          k = -1; dmin = 1.0;
00519          if(fabs(pba[0]) > dmin){k=0; dmin =fabs(pba[0]);}
00520          if(fabs(pba[1]) > dmin){k=1; dmin =fabs(pba[1]);}
00521          if(fabs(pba[2]) > dmin){k=2; dmin =fabs(pba[2]);}
00522          if(k >= 0){
00523            mu1=(vi[k]-pa[k])/pba[k];
00524            if(fabs(mu1) < 0.0000001){ /* at start of segment */
00525              k=af[i].last;
00526              POINT2VECTOR((MainVp+(af[k].v))->xyz,pn)
00527              VECSUB(pa,pn,pnb)
00528              if(DOT(pba,p01)*DOT(pnb,p01) > 0.0)cross_count++;
00529            }
00530            else if(fabs(1.0-mu1) < 0.0000001){ /* at end of segment */
00531              k=af[j].next;
00532              POINT2VECTOR((MainVp+(af[k].v))->xyz,pn)
00533              VECSUB(pn,pb,pnb)
00534              if(DOT(pba,p01)*DOT(pnb,p01) > 0.0)cross_count++;
00535            }
00536            else if(mu1 > 0.0 && mu1 < 1.0){
00537              cross_count++;
00538            }
00539            if(mu < mumin)mumin=mu;
00540          }
00541        }
00542      }
00543    }
00544    if(cross_count%2 == 1 && mumin <= mumumin){curvid=l; mumumin=mumin;}
00545  }
00546  return curvid;
00547 }
00548 
00549 static int edge_is_ok(long Npath, faceedge *af, vector p0, vector p1,
00550                         long ex1, long ex2){
00551 /* check whether the vector po->p1 crosses any edges in the curve  */
00552 /* with the exception of edges ex1 and ex2                         */
00553  vector n,pa,pb,pba,vi,da,db,p10;
00554  double d0,d1,d01,mu,mu1,dmin;
00555  long i,j,k;
00556  VECSUB(p1,p0,p10)
00557  for(i=0;i<Npath;i++){
00558    if(i != ex1 && i != ex2){
00559      VECCOPY(af[i].p,pa)
00560      j=af[i].next;
00561      VECCOPY(af[j].p,pb)
00562      VECCOPY(af[i].n,n)
00563      VECSUB(pa,p0,da)  d0=DOT(da,n);
00564      VECSUB(pa,p1,db)  d1=DOT(db,n);
00565      d01=d0*d1;
00566      if(d01 < 0.0){ /* new edge crosses other edge plane, is it inside ? */
00567        mu1=DOT(p10,n);
00568        if(fabs(mu1) > 1.0){
00569          mu=d0/mu1;
00570          VECSCALE(mu,p10,vi)
00571          VECSUM(p0,vi,vi)
00572          VECSUB(pb,pa,pba)
00573          k = -1; dmin = 1.0;
00574          if(fabs(pba[0]) > dmin){k=0; dmin =fabs(pba[0]);}
00575          if(fabs(pba[1]) > dmin){k=1; dmin =fabs(pba[1]);}
00576          if(fabs(pba[2]) > dmin){k=2; dmin =fabs(pba[2]);}
00577          if(k >= 0){
00578            mu1=(vi[k]-pa[k])/pba[k];
00579            if(mu1 >= -0.0001 && mu1 < 1.0001){
00580              return 0;
00581            }
00582          }
00583        }
00584      }
00585    }
00586  }
00587  return 1;
00588 }
00589 
00590 static void RemakeTheCurve(long ii, long Ncurves, faceedgelist *fl){
00591 /* first find a point of attachment for the hole to the curve         */
00592 /* this is the edge of closest approach that does not cross the hole  */
00593 /* the curve of any hole that is a hole of the curve                  */
00594  vector ph,po,pho,jv;
00595  long vh,vo;
00596  long i,j,k,id,nph,npo,npk,idh = -1,ido = -1,NNpath,je1,je2,j0,j1,j2,j3;
00597  faceedge *afh,*afo,*afk,*afn;
00598  double d,dmin=1.e35;
00599  nph=fl[ii].n;
00600  afh=fl[ii].f;
00601  id=fl[ii].I;
00602  npo=fl[id].n;
00603  afo=fl[id].f;
00604  for(i=0;i<nph;i++){
00605     for(j=0;j<npo;j++){
00606        vh=afh[i].v; vo=afo[j].v;
00607        VECCOPY(afh[i].p,ph)
00608        VECCOPY(afo[j].p,po)
00609        if(edge_is_ok(nph,afh,ph,po,i,afh[i].last) &&
00610           edge_is_ok(npo,afo,ph,po,j,afo[j].last) ){
00611          for(k=0;k<Ncurves;k++){         /* check the other holes   */
00612            if(k != ii && fl[k].I == id){ /* in curve round this one */
00613              npk=fl[k].n;
00614              afk=fl[k].f;
00615              if( ! edge_is_ok(npk,afk,ph,po, -1, -1))goto NOTOK;
00616            }
00617          }
00618          d=(po[0]-ph[0])*(po[0]-ph[0]) +
00619            (po[1]-ph[1])*(po[1]-ph[1]) +
00620            (po[2]-ph[2])*(po[2]-ph[2]);
00621          if(d < dmin){
00622            dmin=d; idh=i, ido=j;
00623          }
00624          NOTOK:;
00625        }
00626     }
00627  }
00628  if(idh == -1 || ido == -1)return;   /* defer or can't do attachment */
00629  fl[ii].done_count=YES;              /* this hole has been processed */
00630  NNpath=nph+npo+2;
00631  /* make space for the new curve  do it in 6 bits  */
00632  if((afn=(faceedge *)X__Malloc(NNpath*sizeof(faceedge))) == NULL)return;
00633  j=0;
00634  if(ido > 0)for(i=0;i<ido;i++){
00635    afn[j].v=afo[i].v; VECCOPY(afo[i].n,afn[j].n) VECCOPY(afo[i].p,afn[j].p)
00636    j++;
00637  }
00638  afn[j].v=afo[ido].v; je1=j; VECCOPY(afo[ido].p,afn[j].p) j++;
00639  if(idh < nph)for(i=idh;i<nph;i++){
00640    afn[j].v=afh[i].v; VECCOPY(afh[i].n,afn[j].n) VECCOPY(afh[i].p,afn[j].p)
00641    j++;
00642  }
00643  if(idh > 0)for(i=0;i<idh;i++){
00644    afn[j].v=afh[i].v; VECCOPY(afh[i].n,afn[j].n) VECCOPY(afh[i].p,afn[j].p)
00645    j++;
00646  }
00647  afn[j].v=afh[idh].v; je2=j; VECCOPY(afh[idh].p,afn[j].p) j++;
00648  if(ido < npo)for(i=ido;i<npo;i++){
00649    afn[j].v=afo[i].v; VECCOPY(afo[i].n,afn[j].n) VECCOPY(afo[i].p,afn[j].p)
00650    j++;
00651  }
00652  /* now update the conectivity matrix */
00653  for(j=0;j<NNpath;j++){
00654    afn[j].inc=1;
00655    if     (j == 0)       {afn[j].last=NNpath-1; afn[j].next=1;  }
00656    else if(j == NNpath-1){afn[j].last=j-1;      afn[j].next=0;  }
00657    else                  {afn[j].last=j-1;      afn[j].next=j+1;}
00658  }
00659  /* separate the curve at the join and calculate normals for the new edges */
00660  /* add a small displacement to the vector */
00661  for(j1=0;j1<NNpath;j1++){
00662    if(j1 == je1 || j1== je2){
00663      j0=afn[j1].last; j2=afn[j1].next; j3=afn[j2].next;
00664      VECSUB(afn[j1].p,afn[j0].p,pho) /* up to edge j */
00665      d=(pho[0]*pho[0])+(pho[1]*pho[1])+(pho[2]*pho[2]);
00666      if(d > 5.0e4){ /* arbitrary */
00667        VECSCALE((1.0 - 200.0/sqrt(d)),pho,pho)
00668        VECSUM(afn[j0].p,pho,afn[j1].p)
00669      }
00670      VECSUB(afn[j3].p,afn[j2].p,pho) /* after edge j */
00671      d=(pho[0]*pho[0])+(pho[1]*pho[1])+(pho[2]*pho[2]);
00672      if(d > 5.0e4){ /* arbitrary */
00673        VECSCALE((1.0 - 200.0/sqrt(d)),pho,pho)
00674        VECSUB(afn[j3].p,pho,afn[j2].p)
00675      }
00676      VECSUB(afn[j2].p,afn[j1].p,pho) /* make the normal */
00677      CROSS(pho,fl[id].normal,afn[j1].n)
00678      O_normalize(afn[j1].n); /* vector WILL be OK it it got here */
00679    }
00680  }
00681  vh=afh[idh].v; vo=afo[ido].v;
00682 
00683  /* free up the old memory */
00684  X__Free(afo); fl[id].f=afn;  fl[id].n=NNpath;
00685  X__Free(afh); fl[ii].f=NULL; fl[ii].n=0; fl[ii].I = -1;
00686  /* update the new curve (curve + hole) normmals */
00687  MakeNewCurveNormals(id,fl);
00688  CreateEdge(vh,vo); /* draw in new edge */
00689 // DrawOneEdge(vh,vo);
00690  return;
00691 }
00692 
00693 int AutoFacetCurveWithHoles(int function, int visible, int atm,
00694                               double ba, double bd){
00695  HCURSOR hSave;
00696  long vp,vf,lastface[3],vstart,vrestart;
00697  long i,j,k,Ncurves,Npath,NpathMax,te,ne,fe,iteration_count,iteration_max;
00698  int allow_all,loop_count,hole_cross_count,round_count,nround,ifail=OK;
00699  faceedgelist *facelist,*newfacelist;
00700  faceedge *af;
00701  double d,dx,angle;
00702  point c_point;
00703  vector v1,v2,v3,N,new_normal,bevel_normal;
00704  if(NvertSelect < 1 || NvertSelect > 32000)return FAIL;
00705  vrestart=-1;
00706  round_count=0; nround=0;
00707  if(function == 1){
00708    angle=(double)RequestNumEntry((short)bevel_angle,
00709                 5,90,"Bevel angle"," Angle");
00710    if(angle < 0)return FAIL;
00711    bevel_angle=angle;
00712  }
00713  else if(function == 2){
00714   angle=90;
00715   nround=4;
00716   angle /= nround;
00717  }
00718  else if(function == 3){ /* bevel from font  -ve for back face*/
00719    bevel_angle=ba;
00720  }
00721  EDIT_ACTION=YES;
00722  if(visible){
00723    hSave=SetCursor(ghcurWait);
00724    Save_Undo(0);
00725  }
00726  STARTAGAIN:
00727  vstart=vrestart;
00728  vrestart=Nvert-1;
00729  vp=Nvert-1; while(vp != vstart){(MainVp+vp)->id=0; vp--;}
00730  Ncurves=0; facelist=NULL; newfacelist=NULL;
00731  STILLCOUNTING:
00732  vp=Nvert-1; vf = -1; while(vp != vstart){
00733    if((MainVp+vp)->status == SELECTED && (MainVp+vp)->id == 0){vf=vp; break;}
00734    vp--;
00735  }
00736  if(vf < 0){
00737    if(Ncurves > 0)goto PROCESSNOW;
00738    else {ifail=FAIL; goto EXIT;}
00739  }
00740  Ncurves++;
00741  if(facelist == NULL)newfacelist=
00742    (faceedgelist *)X__Malloc(sizeof(faceedgelist)*Ncurves);
00743  else newfacelist=(faceedgelist *)X__Realloc(facelist,
00744                      sizeof(faceedgelist)*Ncurves);
00745  if(newfacelist == NULL){
00746    if(facelist != NULL){
00747      for(i=0;i<Ncurves-1;i++){
00748        if(facelist[i].n > 0 && facelist[i].f != NULL)X__Free(facelist[i].f);
00749      }
00750      X__Free(facelist);
00751      SendPrgmQuery(IDQ_NOMEM2,0);
00752    }
00753    ifail=FAIL;
00754    goto EXIT;
00755  }
00756  facelist=newfacelist; facelist[Ncurves-1].n=0;
00757  if((af = /* this is over estimate but who's counting */
00758        (faceedge *)X__Malloc(NvertSelect*sizeof(faceedge))) == NULL){
00759    for(i=0;i<Ncurves;i++){
00760      if(facelist[i].n > 0 && facelist[i].f != NULL)X__Free(facelist[i].f);
00761    }
00762    X__Free(facelist);
00763    SendPrgmQuery(IDQ_NOMEM2,0);
00764    ifail=FAIL;
00765    goto EXIT;
00766  }
00767  facelist[Ncurves-1].f=af;
00768  af[0].v=vf; (MainVp+(af[0].v))->id=1; Npath=1;
00769  vp=Nvert-1; while(vp != vstart){ /* get the next curve */
00770    if((MainVp+vp)->status == SELECTED &&
00771       (MainVp+vp)->id == 0 && connected(af[Npath-1].v,vp)){
00772      af[Npath  ].v=vp;
00773      (MainVp+vp)->id=1;
00774      vp=Nvert-1;
00775      Npath++;    /* add the point to the path list */
00776    }
00777    else vp--;
00778  }
00779  facelist[Ncurves-1].n=Npath;
00780  facelist[Ncurves-1].f = (faceedge *)X__Realloc(facelist[Ncurves-1].f,
00781                       Npath*sizeof(faceedge)); /* cut back */
00782  goto STILLCOUNTING;
00783  PROCESSNOW:  /* we now have all the curves */
00784  for(k=0;k<Ncurves;k++){ /* get curve normals and get normal to each edge */
00785    if(CurveNormal(&(facelist[k])) == FAIL){
00786      goto TERMINATE;
00787      ifail=FAIL;
00788    }
00789    Npath=facelist[k].n;
00790    af=facelist[k].f;
00791    for(i=0;i<Npath;i++){
00792      af[i].inc=1;
00793      if     (i == 0)      {af[i].next=1;   af[i].last=Npath-1;}
00794      else if(i == Npath-1){af[i].next=0;   af[i].last=i-1;    }
00795      else                 {af[i].next=i+1; af[i].last=i-1;    }
00796      POINT2VECTOR((MainVp+(af[i].v))->xyz,v1)
00797      VECCOPY(v1,af[i].p)                /* set up the point vector */
00798      j=af[i].next;
00799      POINT2VECTOR((MainVp+(af[j].v))->xyz,v2)
00800      VECSUB(v2,v1,v3)
00801      if(O_normalize(v3) == FAIL){
00802        SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00803        ifail=FAIL; goto TERMINATE;
00804      }
00805      if(fabs(DOT(v3,facelist[k].normal)) > 0.05){
00806        SendPrgmQuery(IDQ_NOTPLANECURVE,0);
00807        ifail=FAIL; goto TERMINATE;
00808      }
00809      CROSS(v3,facelist[k].normal,af[i].n)
00810      if(O_normalize(af[i].n) == FAIL){
00811        SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00812        ifail=FAIL; goto TERMINATE;
00813      }
00814    }
00815  }
00816  if(Ncurves > 1){ /* check all curves are same planar  */
00817    for(i=0;i<Ncurves-1;i++)for(j=i+1;j<Ncurves;j++){
00818     if(fabs(DOT(facelist[i].normal,facelist[j].normal)) < 0.99999){
00819        SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00820        ifail=FAIL; goto TERMINATE;
00821     }
00822   }
00823  }
00824  for(i=0;i<Ncurves;i++){ /* is curve inside another curve */
00825    facelist[i].I=CurveInside(facelist,i,Ncurves); /* return -1 if not   */
00826    facelist[i].done_count=NO;
00827  }
00828  for(i=0;i<Ncurves;i++){/* is it a hole or inside a hole ? */
00829    hole_cross_count=0;
00830    if((j=facelist[i].I) >= 0)while(j >= 0){
00831      hole_cross_count++;
00832      j=facelist[j].I;
00833    }
00834    if(hole_cross_count %2 == 0)facelist[i].I = -1; /* curve inside a hole */
00835  }
00836  for(i=0;i<Ncurves;i++){  /* make normals consistent for outline curves */
00837    if(facelist[i].I < 0){
00838      Npath=facelist[i].n;
00839      af=facelist[i].f;
00840      for(j=0;j<Npath;j++){ /* we need an inside edge to make the normal */
00841        te=j; ne=af[te].next; fe=af[ne].next;
00842        if(edge_is_internal(af,Npath,te,ne,fe,v1,facelist[i].normal,1)){
00843          goto FOUNDPLANENORMAL1;
00844        }
00845      }
00846      SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00847      ifail=FAIL;
00848      goto TERMINATE;
00849      FOUNDPLANENORMAL1:
00850      VECCOPY(af[te].p,v1) /* v1 returned is not required */
00851      VECCOPY(af[ne].p,v2)
00852      VECCOPY(af[fe].p,v3)
00853      VECSUB(v2,v1,v2)
00854      VECSUB(v3,v1,v3)
00855      CROSS(v2,v3,v1)
00856      if(O_normalize(v1) == FAIL){
00857        SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00858        ifail=FAIL; goto TERMINATE;
00859      }
00860      VECCOPY(v1,facelist[i].normal) /* overwrite the temp normal */
00861      /* update the normals for each edge to reflect this new curve normal */
00862      MakeNewCurveNormals(i,facelist);
00863    }
00864  }
00865  for(i=0;i<Ncurves;i++){  /* make normals consistent for hole curves*/
00866    if(facelist[i].I >= 0){
00867      Npath=facelist[i].n;  /* v2 will be the normal for hole         */
00868      af=facelist[i].f;
00869      for(j=0;j<Npath;j++){ /* need an inside edge */
00870        te=j; ne=af[te].next; fe=af[ne].next;
00871        if(edge_is_internal(af,Npath,te,ne,fe,v1,facelist[i].normal,1)){
00872          goto FOUNDPLANENORMAL2;
00873        }
00874      }
00875      SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00876      ifail=FAIL;
00877      goto TERMINATE;
00878      FOUNDPLANENORMAL2:
00879      VECCOPY(af[te].p,v1) /* v1 returned was not required */
00880      VECCOPY(af[ne].p,v2)
00881      VECCOPY(af[fe].p,v3)
00882      VECSUB(v2,v1,v2)
00883      VECSUB(v3,v1,v3)
00884      CROSS(v2,v3,v1)
00885      if(O_normalize(v1) == FAIL){
00886        SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00887        ifail=FAIL; goto TERMINATE;
00888      } /* if the hole N is same direction as the outer N reverse hole */
00889      if(DOT(v1,facelist[facelist[i].I].normal) > 0.0){
00890        ReverseCurve(af,Npath);
00891        VECSCALE( -1.0,v1,facelist[i].normal)
00892      }
00893      else  VECCOPY(v1,facelist[i].normal)
00894      /* update the normals for this new hole curve */
00895      MakeNewCurveNormals(i,facelist);
00896    }
00897  }
00898  if(function > 0){
00899    if(function == 3){ /* bevel from font */
00900      dx=bd;
00901      if(bevel_angle >= 0.0)bevel_normal[0]=1.0;
00902      else{
00903        bevel_normal[0] = -1.0;
00904        bevel_angle *= -1.0;
00905      }
00906      bevel_normal[1]=0.0;
00907      bevel_normal[2]=0.0;
00908    }
00909    else if(round_count == 0){
00910      c_point[0]=NpointerX; c_point[1]=NpointerY; c_point[2]=NpointerZ;
00911      dx=d=GetDistanceFromCurves(c_point,Ncurves,facelist);
00912      v1[0]= (double)NpointerX - facelist[0].f[0].p[0]; /* Np - Pi */
00913      v1[1]= (double)NpointerY - facelist[0].f[0].p[1]; /* any point will do */
00914      v1[2]= (double)NpointerZ - facelist[0].f[0].p[2];
00915      VECCOPY(facelist[0].normal,bevel_normal); /* bevel to side of cursor */
00916      if(DOT(bevel_normal,v1) < 0.0)VECSCALE(-1.0,bevel_normal,bevel_normal);
00917    }
00918    if(function == 2){
00919      dx=d*(cos((double)(round_count)*angle*PI/180.0) -
00920            cos((double)(round_count+1)*angle*PI/180.0));
00921      bevel_angle=angle*((double)round_count+0.5);
00922    }
00923    BevelCurve(Ncurves,facelist,dx,bevel_angle,bevel_normal);
00924    goto TERMINATE;
00925  }
00926 /* Set an upper bound on the number of edges and faces required */
00927  Npath=2*Ncurves;
00928  for(k=0;k<Ncurves;k++){
00929    i=facelist[k].n+1;
00930    Npath += ((i+1)*i)/2;
00931  }
00932  if(!UpdateEdgeHeap(Nedge+Npath))goto TERMINATE;
00933  if(!UpdateFaceHeap(Nface+Npath+2))goto TERMINATE;
00934 /* NB NB  we must have some iteration here in case hole inside    */
00935 /* a piece cannot be attached due to another hole in the way, in  */
00936 /* such a case the intervening hole must be attached first        */
00937  for(k=0;k<2;k++){ /* 2 iterations may be enough */
00938    for(i=0;i<Ncurves;i++){
00939      if(facelist[i].I >= 0 && facelist[i].done_count == NO)
00940         RemakeTheCurve(i,Ncurves,facelist);
00941    }
00942  }
00943  /* now fill the curves */
00944  for(k=0;k<Ncurves;k++){
00945    Npath=facelist[k].n;
00946    if(Npath >=4){ /* at least 4 points  Npath set to 0 for hole outlines */
00947      af=facelist[k].f;
00948      VECCOPY(facelist[k].normal,N);
00949      NpathMax=Npath;
00950      te=0; loop_count=0; allow_all=0;
00951      iteration_count=0; iteration_max=2*Npath;
00952      while(Npath > 3){
00953        ne=af[te].next; fe=af[ne].next;
00954        if(edge_is_internal(af,NpathMax,te,ne,fe,new_normal,N,allow_all)){
00955          CreateEdge(af[te].v,af[fe].v);
00956          CreateFace(af[te].v,af[ne].v,af[fe].v);
00957 //         DrawOneEdge(af[te].v,af[fe].v);
00958          af[ne].inc=0;
00959          af[te].next=fe;
00960          af[fe].last=te;
00961          VECCOPY(new_normal,af[te].n)
00962          Npath--;
00963          loop_count=0;
00964          allow_all=0;
00965          iteration_count=0;
00966          te=fe; /* move on - not really necesary */
00967        }
00968        else{ /* move to next edge to try again */
00969          te=ne;
00970        }
00971        loop_count++;
00972        if(loop_count > Npath+3)allow_all=1;
00973        if(allow_all)iteration_count++;
00974        if(iteration_count > iteration_max){
00975          if(atm)SendPrgmQuery(IDQ_ATMFILLFAIL,0);
00976          else   SendPrgmQuery(IDQ_FAILED,0);
00977          ifail=FAIL; goto TERMINATE;
00978        }
00979        if(GetAsyncKeyState(VK_ESCAPE) & 0x8000){ifail=FAIL; goto TERMINATE;}
00980      }
00981      for(j=0,i=0;i<NpathMax;i++){
00982        if(af[i].inc == 1){
00983          if(j > 2){
00984            if(atm)SendPrgmQuery(IDQ_ATMFILLFAIL,0);
00985            else   SendPrgmQuery(IDQ_FAILED,0);
00986            ifail=FAIL; goto TERMINATE;
00987          }
00988          lastface[j++]=af[i].v;
00989        }
00990      }
00991      CreateFace(lastface[0],lastface[1],lastface[2]);
00992    }
00993  }
00994  TERMINATE:
00995  for(i=0;i<Ncurves;i++){
00996    if(facelist[i].n > 0 && facelist[i].f != NULL)X__Free(facelist[i].f);
00997  }
00998  X__Free(facelist);
00999  UpdateEdgeHeap(Nedge);
01000  UpdateFaceHeap(Nface);
01001  if(++round_count < nround)goto STARTAGAIN;
01002  if(visible){
01003    DrawModel();
01004    UpdateCounters();
01005  }
01006  EXIT:
01007  if(visible){
01008    SetCursor(hSave);
01009  }
01010  return ifail;
01011 }
01012 
01013 static void  ReverseCurve(faceedge *af, long Npath){
01014   long i;
01015   long vt;
01016   vector pt;
01017   for(i=0;i<Npath/2;i++){
01018      vt=af[i].v; af[i].v = af[Npath-1-i].v; af[Npath-1-i].v=vt;
01019      VECCOPY(af[i].p,pt)
01020      VECCOPY(af[Npath-1-i].p,af[i].p)
01021      VECCOPY(pt,af[Npath-1-i].p)
01022   }
01023 }
01024 
01025 static void BevelCurve(long Ncurves, faceedgelist *facelist, double d,
01026                        double angle, vector direction){
01027  long i,j,k,Npath;
01028  faceedge *af;
01029  normals *VV;
01030  vector N,Nav,v1,v2,v3,vab;
01031  double dd,dplane;
01032  int inside,add_point,first_vertex;
01033  long lv,fv,sv,vp;
01034 /* Set an upper bound on the number of edges and faces required */
01035  Npath=1; for(k=0;k<Ncurves;k++)Npath +=facelist[k].n+1;
01036  if(!UpdateVertexHeap(Nvert+Npath*2))return;  /* gross over estimates */
01037  if(!UpdateEdgeHeap(Nedge+Npath*4))return;
01038  if(!UpdateFaceHeap(Nface+Npath*4))return;
01039 /* now do the bevel */
01040  sv=Nvert-1;
01041  for(i=0;i<Ncurves;i++){
01042    Npath=facelist[i].n;
01043    af=facelist[i].f;
01044    VECCOPY(facelist[i].normal,N)
01045    if((VV=(normals *)X__Malloc(Npath*sizeof(normals))) == NULL){
01046    SendPrgmQuery(IDQ_NOMEM2,0);
01047      continue; /* continue on to next curve */
01048    }
01049    for(j=0;j<Npath;j++){ /* make each edge normal point in same way */
01050      POINT2VECTOR((MainVp+(af[j].v))->xyz,v1)
01051      k=af[j].next;
01052      POINT2VECTOR((MainVp+(af[k].v))->xyz,v2)
01053      VECSUB(v2,v1,v3)
01054      O_normalize(v3);
01055      CROSS(v3,N,af[j].n)
01056      O_normalize(af[j].n);
01057    }
01058    for(j=0;j<Npath;j++){ /* set up direction vectors */
01059      k=af[j].last;
01060      VECSUM(af[j].n,af[k].n,Nav);
01061      O_normalize(Nav);   /* may point to the inside or outside */
01062      POINT2VECTOR((MainVp+(af[j].v))->xyz,v1)
01063      VECSUM(v1,Nav,v2)
01064      inside=point_inside_curve(v2,Nav,af,Npath,N);
01065      if((inside && facelist[i].I >= 0) || ((! inside) && facelist[i].I < 0)){
01066        VECSCALE(-1.0,Nav,VV[j].nav)
01067        VECSCALE(-1.0,af[j].n,VV[j].n)
01068      }
01069      else{
01070        VECCOPY(Nav,VV[j].nav)
01071        VECCOPY(af[j].n,VV[j].n)
01072      }
01073    }
01074    lv = -1, fv = -1; first_vertex=YES;
01075    for(j=0;j<Npath;j++){
01076      POINT2VECTOR((MainVp+(af[j].v))->xyz,v1)
01077      k=af[j].next;
01078      POINT2VECTOR((MainVp+(af[k].v))->xyz,v2)
01079      VECSUB(v2,v1,vab)
01080      O_normalize(vab); /* vab will be non zero */
01081      k=af[j].last;
01082 #define OBTUSE_A -0.7071
01083      if(DOT(vab,VV[j].nav) < OBTUSE_A){ /* large obtuse angle add vertex */
01084        VECSCALE(d,VV[k].n,v2)
01085        VECSUM(v1,v2,v3)
01086        CreateVertex(); if(fv < 0)fv=Nvert-1;
01087        VECTOR2POINT(v3,(MainVp+Nvert-1)->xyz)
01088        CreateEdge(af[j].v,Nvert-1);
01089        if(lv >= 0){
01090          CreateEdge(Nvert-1,lv);
01091          CreateEdge(Nvert-1,af[k].v);
01092          CreateFace(Nvert-1,af[k].v,af[j].v);
01093          CreateFace(Nvert-1,lv,af[k].v);
01094        }
01095        lv=Nvert-1;
01096        VECSCALE(d,VV[j].n,v2)
01097        VECSUM(v1,v2,v3)
01098        CreateVertex(); if(fv < 0)fv=Nvert-1;
01099        VECTOR2POINT(v3,(MainVp+Nvert-1)->xyz)
01100        CreateEdge(af[j].v,Nvert-1);
01101        CreateEdge(lv,Nvert-1);
01102        CreateFace(lv,Nvert-1,af[j].v);
01103        lv=Nvert-1;
01104      }
01105      else{   /* acute angle check to see if a vertex should be added */
01106        dd=fabs(DOT(VV[j].nav,VV[j].n)); /* get angular distance    */
01107        if(dd < 1.e-10)dd=d;             /* to keep bevel same size */
01108        else           dd=d/dd;
01109        POINT2VECTOR((MainVp+(af[k].v))->xyz,v2)
01110        CROSS(N,VV[k].nav,Nav)
01111        O_normalize(Nav);  /* normal vector to plane of Nav of last bevel */
01112        dplane=DOT(VV[j].nav,Nav);
01113        if(fabs(dplane) < 1.e-10)add_point=YES;
01114        else{
01115          VECSUB(v2,v1,v3);
01116          dplane=DOT(v3,Nav)/dplane;
01117          if(dplane < 0.0 || dplane >= dd)add_point=YES;
01118          else add_point=NO;
01119        }
01120        if(add_point == YES){ /* add a vertex */
01121          VECSCALE(dd,VV[j].nav,v2)
01122          VECSUM(v1,v2,v3)
01123          CreateVertex(); if(fv < 0)fv=Nvert-1;
01124          if(lv >= 0){
01125            CreateEdge(lv,Nvert-1);
01126            CreateEdge(Nvert-1,af[k].v);
01127            CreateFace(Nvert-1,af[k].v,af[j].v);
01128            CreateFace(Nvert-1,lv,af[k].v);
01129          }
01130          lv=Nvert-1;
01131          VECTOR2POINT(v3,(MainVp+Nvert-1)->xyz)
01132          CreateEdge(af[j].v,Nvert-1);
01133        }
01134        else{
01135          if(lv >= 0){
01136            CreateEdge(af[j].v,lv);
01137            CreateFace(af[j].v,lv,af[k].v);
01138            /* update the average normal for edge j to take account of   */
01139            /* fact that it must be shifted forward to line up with last */
01140            VV[j].nav[0]=(double)((MainVp+lv)->xyz[0] - (MainVp+af[j].v)->xyz[0]);
01141            VV[j].nav[1]=(double)((MainVp+lv)->xyz[1] - (MainVp+af[j].v)->xyz[1]);
01142            VV[j].nav[2]=(double)((MainVp+lv)->xyz[2] - (MainVp+af[j].v)->xyz[2]);
01143            O_normalize(VV[j].nav);
01144          }
01145          if(j == 0)first_vertex=NO;
01146        }
01147      }
01148      (MainVp+af[j].v)->status=DESELECTED; NvertSelect--; NvertDeselect++;
01149    }
01150    /* now fix up the loop end->start */
01151    if(fv >= 0 && lv >= 0){
01152      CreateEdge(lv,fv);
01153      CreateEdge(lv,af[0].v);
01154      CreateFace(lv,fv,af[0].v);
01155      CreateFace(lv,af[0].v,af[Npath-1].v);
01156      if(first_vertex == NO){
01157        CreateEdge(fv,af[0].v);
01158        CreateFace(fv,af[1].v,af[0].v);
01159      }
01160    }
01161    X__Free(VV);
01162  }
01163  if(angle < 89){ /* move the vertices to their new position */
01164    d=d/tan(angle/180.0*PI);
01165    vp=Nvert-1; while(vp != sv){
01166      (MainVp+vp)->xyz[0]=(long)((double)(MainVp+vp)->xyz[0] + d*direction[0]);
01167      (MainVp+vp)->xyz[1]=(long)((double)(MainVp+vp)->xyz[1] + d*direction[1]);
01168      (MainVp+vp)->xyz[2]=(long)((double)(MainVp+vp)->xyz[2] + d*direction[2]);
01169      vp--;
01170    }
01171  }
01172  UpdateVertexHeap(Nvert);  /* edge heaps are fixed in main routine */
01173  return;
01174 }
01175 
01176 static int point_inside_curve(vector v2, vector Nav, faceedge *af,
01177                                 long Npath, vector N){
01178 /* determine wheter point v2 is inside the curve  Nav is the vector v1->v2 */
01179  vector pa,pb,pba,pav,n,vi,pn,pnb,p01;
01180  double mu,mu1,dmin;
01181  long i,j,k,cross_count=0;
01182  CROSS(Nav,N,p01)
01183  for(i=0;i<Npath;i++){ /* check to see if new_normal crosses edges in path */
01184    POINT2VECTOR((MainVp+(af[i].v))->xyz,pa)
01185    j=af[i].next;
01186    POINT2VECTOR((MainVp+(af[j].v))->xyz,pb)
01187    VECCOPY(af[i].n,n)
01188    VECSUB(pa,v2,pav)
01189    mu1=DOT(n,Nav);
01190    if(fabs(mu1) > 0.0001){
01191      mu=DOT(pav,n)/mu1;
01192      if(mu > 0.0000){   /* look for intersections on one side */
01193        VECSCALE(mu,Nav,vi)
01194        VECSUM(v2,vi,vi) /* intersection to plane of test edge */
01195        VECSUB(pb,pa,pba)
01196        k = -1; dmin = 1.0;
01197        if(fabs(pba[0]) > dmin){k=0; dmin =fabs(pba[0]);}
01198         if(fabs(pba[1]) > dmin){k=1; dmin =fabs(pba[1]);}
01199        if(fabs(pba[2]) > dmin){k=2; dmin =fabs(pba[2]);}
01200        if(k >= 0){
01201          mu1=(vi[k]-pa[k])/pba[k];
01202          /* as above needs a test for edge along normal */
01203          if(fabs(mu1) < 0.0001){ /* at start of segment */
01204            k=af[j].last;
01205            POINT2VECTOR((MainVp+(af[k].v))->xyz,pn)
01206            VECSUB(pa,pn,pnb)
01207            if(DOT(pba,p01)*DOT(pnb,p01) > 0.0)cross_count++;
01208          }
01209          else if(fabs(1.0-mu1) < 0.0001){ /* at end of segment */
01210            k=af[j].next;
01211            POINT2VECTOR((MainVp+(af[k].v))->xyz,pn)
01212            VECSUB(pn,pb,pnb)
01213            if(DOT(pba,p01)*DOT(pnb,p01) > 0.0)cross_count++;
01214          }
01215          else if(mu1 >= 0.0001 && mu1 <= 0.9999)cross_count++;
01216        }
01217      }
01218    }
01219  }
01220  if(cross_count%2 == 1)return 1;
01221  return 0;
01222 }
01223 
01224 double GetDistanceFromCurves(point c_point, long Ncurves,
01225                              faceedgelist *facelist){
01226 /* check from point and then from the edge */
01227   vector dp;
01228   double a,b,c,d,dmin=1.e35,mu;
01229   long i,j,Npath,found=0;
01230   faceedge *af;
01231   vertex *vp1,*vp2;
01232   for(i=0;i<Ncurves;i++){
01233     Npath=facelist[i].n;
01234     af=facelist[i].f;
01235     for(j=0;j<Npath;j++){
01236       vp1=(MainVp+af[j].v); vp2=(MainVp+af[af[j].next].v);
01237       a=(double)(vp2->xyz[0]-vp1->xyz[0]);
01238       b=(double)(vp2->xyz[1]-vp1->xyz[1]);
01239       c=(double)(vp2->xyz[2]-vp1->xyz[2]);
01240       mu=(a*((double)c_point[0]-(double)(vp1->xyz[0]))
01241          +b*((double)c_point[1]-(double)(vp1->xyz[1]))
01242          +c*((double)c_point[2]-(double)(vp1->xyz[2])))/(a*a+b*b+c*c);
01243       if(mu > 0.0 && mu < 1.0){
01244         found=1;
01245         dp[0]=(double)(vp1->xyz[0] - c_point[0]);
01246         dp[1]=(double)(vp1->xyz[1] - c_point[1]);
01247         dp[2]=(double)(vp1->xyz[2] - c_point[2]);
01248         d=fabs(DOT(af[j].n,dp));
01249         if(d < dmin)dmin=d;
01250       }
01251     }
01252   }
01253   if(found)return dmin;
01254   else     return TVsizeX/20;
01255 }
01256 
01257 // Functions for UNPLAN action
01258 
01259 static int sort_sections(long *i, long *j){
01260   if     (*i < *j)return -1;
01261   else if(*i > *j)return  1;
01262   else            return  0;
01263 }
01264 
01265 static long section_intersect(long x, long x1, long x2, long y1, long y2){
01266  double grad;
01267  grad = (double)(y2-y1)/(double)(x2-x1);
01268  return (long)( (double)y1 + grad*((double)(x-x1)) );
01269 }
01270 
01271 void UnPlan(void){
01272  HCURSOR hSave;
01273  vertex *Vp,*V0,*V1;
01274  long vp,vx,*vo=NULL,vlast,vend;
01275  double d,dmin,drange,zscale,xscale,zdif,xdif;
01276  long NpathX,Nsections=0,i,j,k,l,m,ymin1,ymax1,ymin2,ymax2,
01277       ymax,ymin,xmin,xmax,zmin,zmax,zcentre,xcentre,zc,xc,
01278       y,z1,z2,x1,x2,*sections=NULL,Ne1=0,Ne2=0,Nvo=0,TOLL=MINUNIT;
01279  long ep,*el1=NULL,*el2=NULL;
01280  int p,special=0;
01281  if(NvertSelect > 32000){
01282    SendPrgmQuery(IDQ_WIRETOOBIG,0);
01283    return;
01284  }
01285  if(NvertSelect == 0){
01286 #if 0
01287    vlast=MainVp;
01288    LoadDXF(0);
01289    if(MainVp == vlast)goto EXIT;
01290    special=1;
01291    vp=vlast; while(vp != NULL){
01292      if(vp->status == DESELECTED)vp->status=INEDITOR;
01293      vp->id=0;
01294      vp=vp->last;
01295    }
01296    vend=MainVp;
01297    HideCursor();  DrawCursor(waiticon);  ShowCursor();
01298    j=k=l=0;
01299    vp=MainVp; while(vp != vlast){ /* go thro all vertices fixing up */
01300      if(vp->id == 20){          /* plan */
01301        m=vp->xyz[0]; vp->xyz[0]=vp->xyz[1]; vp->xyz[1] = -m;
01302        vp->id=0; j++;
01303      }
01304      else if(vp->id == 40){     /* rear */
01305        m=vp->xyz[0]; vp->xyz[0]=vp->xyz[1]; vp->xyz[1] = -m;
01306        m=vp->xyz[2]; vp->xyz[2]=vp->xyz[1]; vp->xyz[1] =  m;
01307        vp->id=1; k++;
01308      }
01309      else if(vp->id == 30){     /* side */
01310        m=vp->xyz[0]; vp->xyz[0]=vp->xyz[1]; vp->xyz[1] = -m;
01311        m=vp->xyz[0]; vp->xyz[0]=vp->xyz[2]; vp->xyz[2] = -m;
01312        vp->id=0; vp->status=DESELECTED; NvertSelect--; NvertDeselect++; l++;
01313      }
01314      else{
01315        vp->id=0; vp->status=INEDITOR; NvertSelect--; NvertDeselect++;
01316      }
01317      vp=vp->last;
01318    }
01319    if(j == 0 || k == 0 || l == 0)goto EXIT;
01320    TOLL = MINUNIT/4;
01321    goto DOIT;
01322 #endif
01323  }
01324  if(NvertSelect < 4 || NvertDeselect < 4 || Nedge < 12)return;
01325  dmin=(double)TVsizeX*(double)TVsizeX; drange=dmin/1024;
01326  vx=-1;
01327  vp=0; Vp=MainVp;
01328  while(vp < Nvert){ /* find the first vertex of path closest to cursor */
01329    if(Vp->status == SELECTED && intriview(Vp)){
01330      d=(double)(Vp->xyz[0]-NpointerX)*(double)(Vp->xyz[0]-NpointerX)
01331       +(double)(Vp->xyz[1]-NpointerY)*(double)(Vp->xyz[1]-NpointerY)
01332       +(double)(Vp->xyz[2]-NpointerZ)*(double)(Vp->xyz[2]-NpointerZ);
01333      if(d < dmin && d < drange){
01334        dmin=d;
01335        vx=vp;
01336      }
01337    }
01338    Vp->id=0; /* clear ready to use for found flag   */
01339    vp++; Vp++;
01340  }
01341  if(vx < 0){
01342    SendPrgmQuery(IDQ_NOPATHSTART,0);
01343    return;
01344  }
01345  else if(SendPrgmQuery(IDQ_UNPLAN,2) != IDYES)return;
01346  if     (GetAsyncKeyState(VK_SHIFT)   & 0x8000)TOLL = MINUNIT/2;
01347  else if(GetAsyncKeyState(VK_CONTROL) & 0x8000)TOLL = MINUNIT/4;
01348  else if(GetAsyncKeyState(VK_MENU)    & 0x8000)TOLL = MINUNIT/8;
01349  else                                          TOLL = MINUNIT;
01350  hSave=SetCursor(ghcurWait);
01351  Save_Undo(0);
01352  (MainVp+vx)->id=1;
01353  vp=0; while(vp < Nvert){ /* flag the vertices in extruded curve */
01354    Vp=(MainVp+vp);
01355    if(Vp->status == SELECTED && Vp->id == 0 && connected(vx,vp)){
01356      vx=vp;
01357      Vp->id=1;
01358      vp=0;  /* go back and look for the next connected vertex */
01359    }
01360    else vp++;
01361  }
01362 // DOIT:
01363  vp=0; while(vp < Nvert){
01364    Vp=(MainVp+vp);
01365    if((Vp->status == SELECTED && Vp->id == 0) ||
01366        Vp->status == DESELECTED){
01367      if(Nsections == 0){
01368        if((sections=(long *)X__Malloc(sizeof(long))) == NULL)goto ABRT;
01369        *(sections) = Vp->xyz[1];
01370        Nsections=1;
01371      }
01372      else{
01373        for(i=0;i<Nsections;i++){
01374          if(abs(Vp->xyz[1] - *(sections+i)) < TOLL)goto BYPASS;
01375        }
01376        if((sections=(long *)X__Realloc(sections,(Nsections+1)*sizeof(long)))
01377                   == NULL)goto ABRT;
01378        *(sections+Nsections)=Vp->xyz[1];
01379        Nsections++;
01380        BYPASS:;
01381      }
01382    }
01383    vp++;
01384  }
01385  qsort(sections,Nsections,sizeof(long),(void *)sort_sections);
01386  ep=0; while(ep < Nedge){
01387    V0=(MainVp+(MainEp+ep)->V[0]); V1=(MainVp+(MainEp+ep)->V[1]);
01388    if(V0->status == DESELECTED &&
01389       V1->status == DESELECTED){ /* add to el1  vertical section */
01390      if(el1 == NULL){
01391        if( (el1=(long *)X__Malloc((long)sizeof(long)) ) == NULL)goto ABRT;
01392      }
01393      else{
01394        if( (el1=(long *)X__Realloc(el1,(Ne1+1)*(long)sizeof(long)) )
01395              == NULL)goto ABRT;
01396      }
01397      el1[Ne1]=ep;
01398      Ne1++;
01399    }
01400    else if(V0->status == SELECTED && V0->id == 0 &&
01401            V1->status == SELECTED && V1->id == 0){ /* horiz S */
01402      if(el2 == NULL){
01403        if( (el2=(long *)X__Malloc((long)sizeof(long)) ) == NULL)goto ABRT;
01404      }
01405      else {
01406        if( (el2=(long *)X__Realloc(el2,(Ne2+1)*(long)sizeof(long)) )
01407                == NULL)goto ABRT;
01408      }
01409      el2[Ne2]=ep;
01410      Ne2++;
01411    }
01412    ep++;
01413  }
01414  xmin = zmin =  MAXUNIT;
01415  xmax = zmax = -MAXUNIT;
01416  vp=0; Vp=MainVp; while(vp < Nvert){
01417    if(Vp->status == SELECTED){
01418      if(Vp->id == 0){
01419        Vp->status=DESELECTED; NvertSelect--; NvertDeselect++;
01420      }
01421      else{
01422        if(Vp->xyz[0] < xmin)xmin=Vp->xyz[0];
01423        if(Vp->xyz[0] > xmax)xmax=Vp->xyz[0];
01424        if(Vp->xyz[2] < zmin)zmin=Vp->xyz[2];
01425        if(Vp->xyz[2] > zmax)zmax=Vp->xyz[2];
01426        if(vo == NULL){
01427          if( (vo=(long *)X__Malloc((Nvo+1)*(long)sizeof(long)) )
01428                  == NULL)goto ABRT;
01429        }
01430        else {
01431          if( (vo=(long *)X__Realloc(vo,(Nvo+1)*(long)sizeof(long)) )
01432                  == NULL)goto ABRT;
01433        }
01434        vo[Nvo++]=vp;
01435      }
01436    }
01437    vp++; Vp++;
01438  }
01439  zcentre=(zmax+zmin)/2; xcentre=(xmax+xmin)/2;
01440  if(zmax == zmin || xmax == xmin)goto EXIT;
01441  zdif=(double)(zmax-zmin); xdif=(double)(xmax-xmin);
01442  ymax1 = -MAXUNIT;  ymin1 =  MAXUNIT;
01443  for(i=0;i<Ne1;i++){
01444    ep=el1[i];
01445    V0=(MainVp+(MainEp+ep)->V[0]); V1=(MainVp+(MainEp+ep)->V[1]);
01446    if(V0->xyz[1] < ymin1)ymin1=V0->xyz[1];
01447    if(V1->xyz[1] < ymin1)ymin1=V1->xyz[1];
01448    if(V0->xyz[1] > ymax1)ymax1=V0->xyz[1];
01449    if(V1->xyz[1] > ymax1)ymax1=V1->xyz[1];
01450  }
01451  ymax2 = -MAXUNIT;  ymin2 =  MAXUNIT;
01452  for(i=0;i<Ne2;i++){
01453    ep=el2[i];
01454    V0=(MainVp+(MainEp+ep)->V[0]); V1=(MainVp+(MainEp+ep)->V[1]);
01455    if(V0->xyz[1] < ymin2)ymin2=V0->xyz[1];
01456    if(V1->xyz[1] < ymin2)ymin2=V1->xyz[1];
01457    if(V0->xyz[1] > ymax2)ymax2=V0->xyz[1];
01458    if(V1->xyz[1] > ymax2)ymax2=V1->xyz[1];
01459  }
01460  ymin=max(ymin1,ymin2); ymax=min(ymax1,ymax2);
01461  for(i=0,p=0;i<Nsections;i++){
01462    y=sections[i];
01463    if(y >= ymin && y <= ymax){
01464      z1 = MAXUNIT; z2 = -MAXUNIT;
01465      for(j=0;j<Ne1;j++){
01466        ep=el1[j];  /* vertical yZ section  */
01467        V0=(MainVp+(MainEp+ep)->V[0]); V1=(MainVp+(MainEp+ep)->V[1]);
01468        if( (V0->xyz[1] <= y && V1->xyz[1] >= y ) ||
01469            (V1->xyz[1] <= y && V0->xyz[1] >= y ) ){/* spans */
01470          if(!(V0->xyz[1] == y && V1->xyz[1] == y)){/* not vert */
01471            m=section_intersect(y,V0->xyz[1],V1->xyz[1],
01472                                  V0->xyz[2],V1->xyz[2]);
01473            if(m <= z1)z1=m;
01474            if(m >= z2)z2=m;
01475          }
01476        }
01477      }
01478      x1 = MAXUNIT; x2 = -MAXUNIT;
01479      for(j=0;j<Ne2;j++){
01480        ep=el2[j];  /* horizontal section Xy */
01481        V0=(MainVp+(MainEp+ep)->V[0]); V1=(MainVp+(MainEp+ep)->V[1]);
01482        if( (V0->xyz[1] <= y && V1->xyz[1] >= y ) ||
01483            (V1->xyz[1] <= y && V0->xyz[1] >= y ) ){/* spans    */
01484          if(!(V0->xyz[1] == y && V1->xyz[1] == y)){/* not vert */
01485            m=section_intersect(y,V0->xyz[1],V1->xyz[1],
01486                                  V0->xyz[0],V1->xyz[0]);
01487            if(m <= x1)x1=m;
01488            if(m >= x2)x2=m;
01489          }
01490        }
01491      }
01492      if(z1 == MAXUNIT || x1 == MAXUNIT || z2 == -MAXUNIT || x2 == -MAXUNIT)
01493        goto OMIT;
01494      zc=(z1+z2)/2; xc=(x1+x2)/2;
01495      if    (p == 0)AddCopy(0);
01496      else  if(!CreateAttachedCopy(1))goto ABRT;
01497      if(zmax-zmin == 0)zscale=0.0;
01498      zscale=(double)(z2-z1)/zdif;
01499      xscale=(double)(x2-x1)/xdif;
01500      m=0;
01501      vp=0; Vp=MainVp; while(vp < Nvert){
01502        if(Vp->status == SELECTED){ /* move into position */
01503          Vp->xyz[1]=y;
01504          Vp->xyz[2]=(long)(zscale*(double)((MainVp+vo[m])->xyz[2]-zcentre)
01505                    +(double)zc);
01506          Vp->xyz[0]=(long)(xscale*(double)((MainVp+vo[m])->xyz[0]-xcentre)
01507                    +(double)xc);
01508          m++;
01509        }
01510        vp++; Vp++;
01511      }
01512      p++;
01513      OMIT:;
01514    }
01515  }
01516  goto EXIT;
01517  ABRT:;
01518  EXIT:;
01519  vp=0; Vp=MainVp; while(vp < Nvert){
01520    if(Vp->status == SELECTED){
01521      Vp->status=DESELECTED; NvertSelect--; NvertDeselect++;
01522    }
01523    vp++; Vp++;
01524  }
01525  if(vo != NULL)X__Free(vo);
01526  if(sections != NULL)X__Free(sections);
01527  if(el1 != NULL)X__Free(el1);
01528  if(el2 != NULL)X__Free(el2);
01529  if(special){
01530 #if 0
01531    vp=vend; while(vp != NULL){
01532      if(vp->status == INEDITOR)vp->status=DESELECTED;
01533      vp=vp->last;
01534    }
01535    vp=vend; while(vp != vlast){
01536      if(vp->status == DESELECTED){
01537        vp->status=SELECTED; NvertSelect++; NvertDeselect--;
01538      }
01539      vp=vp->last;
01540    }
01541    EraseVertex(0);
01542 #endif
01543  }
01544  SetCursor(hSave);
01545  reset_mod_maxview(1);
01546  DrawModel(); UpdateCounters();
01547 }

Generated on Sun Apr 27 14:20:12 2014 for OpenFX by  doxygen 1.5.6