TOOLS2.C

Go to the documentation of this file.
00001 /* --
00002 OpenFX - Modelling, Animation and Rendering Package
00003 -- */
00004 
00005 
00006 /* file TOOLS2.C  second designer tools file */
00007 
00008 #define MODULE_TOOLS2 1
00009 
00010 #include "design.h"
00011 
00012 //#define DIS2(a) ((double)(a[0]-NpointerX)*(double)(a[0]-NpointerX)+  \
00013 //                 (double)(a[1]-NpointerY)*(double)(a[1]-NpointerY)+  \
00014 //                 (double)(a[2]-NpointerZ)*(double)(a[2]-NpointerZ))
00015 
00016 typedef struct tagVERTEXVERTEX{
00017  long vl,vr;
00018 } VERTEXVERTEX;
00019 
00020 typedef struct tagFACEEXTRA{
00021  long extra,xxtra;
00022 } FACEEXTRA;
00023 
00024 static int squeeze(int how);
00025 static double dspacing(long Va1, long Va2);
00026 
00027 /* making list of vertices adjacent to new vertices improves effiency     */
00028 /* it uses the vertex ID to store index to array giving adjacent vertices */
00029 /* effient could be further improved by making a list of relevant faces   */
00030 
00031 int Subdivide(long down_to_f, long down_to_e, long draw){
00032  face *fp;
00033  edge *ep;
00034  vertex *V0,*V1,*V2;
00035  long i,j,vl,vr,id,nf=0,ne=0,n,Nedge1,Nface1,Nv1;
00036  VERTEXVERTEX *vlist=NULL;
00037  FACEEXTRA    *MainLp=NULL,*lp;
00038  HCURSOR hSave;
00039  if(NvertSelect > 32000){
00040    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00041    return FAIL;
00042  }
00043  /* get upper bound for number of faces selected */
00044  if(down_to_f < Nface){
00045    if((MainLp=(FACEEXTRA *)X__Malloc(Nface*sizeof(FACEEXTRA))) == NULL){
00046      SendPrgmQuery(IDQ_NOMEM1,0);
00047      return FAIL;
00048    }
00049    fp=(MainFp+down_to_f); lp=(MainLp+down_to_f); nf=0;
00050    for(i=down_to_f;i<Nface;i++){
00051      lp->extra = -1;
00052      lp->xxtra = -1;
00053      V0=(MainVp+fp->V[0]); V1=(MainVp+fp->V[1]); V2=(MainVp+fp->V[2]);
00054      if((V0->status == SELECTED && V1->status == SELECTED) ||
00055         (V1->status == SELECTED && V2->status == SELECTED) ||
00056         (V2->status == SELECTED && V0->status == SELECTED))nf++;
00057      fp++; lp++;
00058    }
00059  }
00060  for(ep=(MainEp+down_to_e),ne=0,i=down_to_e;i<Nedge;i++){
00061    if((MainVp+ep->V[0])->status == SELECTED &&
00062       (MainVp+ep->V[1])->status == SELECTED)ne++; // number of edges to be divided
00063    ep++;
00064  }
00065  if(ne == 0){
00066    if(MainLp != NULL)X__Free(MainLp);
00067    return FAIL;
00068  }
00069  /* extend the Vertices Edges and Faces arrays to their upper bounds */
00070  if((vlist=(VERTEXVERTEX *)X__Malloc(ne*sizeof(VERTEXVERTEX))) == NULL){
00071    if(MainLp != NULL)X__Free(MainLp);
00072    return FAIL;
00073  }
00074  if(!UpdateVertexHeap(Nvert+ne))goto EP1;
00075  if(!UpdateEdgeHeap(Nedge+ne+nf*3))goto EP1;
00076  if(!UpdateFaceHeap(Nface+nf*3))goto EP1;
00077  Nface1=Nface; Nedge1=Nedge;
00078  if(draw)hSave=SetCursor(ghcurWait);
00079  ep=(MainEp+down_to_e); n=0;
00080  for(i=down_to_e;i<Nedge1;i++){
00081    vl=ep->V[0]; V0=(MainVp+vl); vr=ep->V[1]; V1=(MainVp+vr);
00082    if(V0->status == SELECTED && V1->status == SELECTED){
00083      CreateVertex(); Nv1=Nvert-1;
00084      vlist[n].vl=vl; vlist[n].vr=vr; (MainVp+Nv1)->id=n; n++;
00085      (MainVp+Nv1)->xyz[0]=(V0->xyz[0] + V1->xyz[0])/2;
00086      (MainVp+Nv1)->xyz[1]=(V0->xyz[1] + V1->xyz[1])/2;
00087      (MainVp+Nv1)->xyz[2]=(V0->xyz[2] + V1->xyz[2])/2;
00088      CreateEdge(Nv1,ep->V[1]);
00089      ep->V[1]=Nv1;
00090      if(down_to_f < Nface1){
00091        fp=(MainFp+down_to_f); lp=(MainLp+down_to_f);
00092        for(j=down_to_f;j<Nface1;j++){
00093         id=0;
00094         if     ((fp->V[0] == vl && fp->V[1] == vr) ||
00095                 (fp->V[0] == vr && fp->V[1] == vl) )id=1;
00096         else if((fp->V[1] == vl && fp->V[2] == vr) ||
00097                 (fp->V[1] == vr && fp->V[2] == vl) )id=2;
00098         else if((fp->V[2] == vl && fp->V[0] == vr) ||
00099                 (fp->V[2] == vr && fp->V[0] == vl) )id=3;
00100         if(id != 0){
00101           if(lp->extra < 0)lp->extra=Nv1;
00102           else{
00103             if(lp->xxtra < 0)lp->xxtra=Nv1;
00104             else{
00105                CreateEdge(Nv1,lp->extra);
00106                CreateEdge(Nv1,lp->xxtra);
00107                CreateEdge(lp->extra,lp->xxtra);
00108                if     (id == 1){
00109                  if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00110                              fp->V[2],lp->xxtra,lp->extra))
00111                    CreateFace(fp->V[2],lp->xxtra,lp->extra);
00112                  else
00113                    CreateFace(fp->V[2],lp->extra,lp->xxtra);
00114                  CopyFaceProp(fp,(MainFp+Nface-1));
00115                  if(vlist[(MainVp+lp->extra)->id].vl == fp->V[0] ||
00116                     vlist[(MainVp+lp->extra)->id].vr == fp->V[0]){
00117                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00118                                fp->V[0],Nv1,lp->extra))
00119                      CreateFace(fp->V[0],Nv1,lp->extra);
00120                    else
00121                      CreateFace(fp->V[0],lp->extra,Nv1);
00122                    CopyFaceProp(fp,(MainFp+Nface-1));
00123                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00124                                fp->V[1],Nv1,lp->xxtra))
00125                      CreateFace(fp->V[1],Nv1,lp->xxtra);
00126                    else
00127                      CreateFace(fp->V[1],lp->xxtra,Nv1);
00128                    CopyFaceProp(fp,(MainFp+Nface-1));
00129                  }
00130                  else{
00131                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00132                                fp->V[1],Nv1,lp->extra))
00133                      CreateFace(fp->V[1],Nv1,lp->extra);
00134                    else
00135                      CreateFace(fp->V[1],lp->extra,Nv1);
00136                    CopyFaceProp(fp,(MainFp+Nface-1));
00137                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00138                                fp->V[0],Nv1,lp->xxtra))
00139                      CreateFace(fp->V[0],Nv1,lp->xxtra);
00140                    else
00141                      CreateFace(fp->V[0],lp->xxtra,Nv1);
00142                    CopyFaceProp(fp,(MainFp+Nface-1));
00143                  }
00144                }
00145                else if(id == 2){
00146                  if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00147                              fp->V[0],lp->xxtra,lp->extra))
00148                    CreateFace(fp->V[0],lp->xxtra,lp->extra);
00149                  else
00150                    CreateFace(fp->V[0],lp->extra,lp->xxtra);
00151                  CopyFaceProp(fp,(MainFp+Nface-1));
00152                  if(vlist[(MainVp+lp->extra)->id].vl == fp->V[1] ||
00153                     vlist[(MainVp+lp->extra)->id].vr == fp->V[1]){
00154                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00155                                fp->V[1],Nv1,lp->extra))
00156                      CreateFace(fp->V[1],Nv1,lp->extra);
00157                    else
00158                      CreateFace(fp->V[1],lp->extra,Nv1);
00159                    CopyFaceProp(fp,(MainFp+Nface-1));
00160                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00161                                fp->V[2],Nv1,lp->xxtra))
00162                      CreateFace(fp->V[2],Nv1,lp->xxtra);
00163                    else
00164                      CreateFace(fp->V[2],lp->xxtra,Nv1);
00165                    CopyFaceProp(fp,(MainFp+Nface-1));
00166                  }
00167                  else{
00168                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00169                                fp->V[2],Nv1,lp->extra))
00170                      CreateFace(fp->V[2],Nv1,lp->extra);
00171                    else
00172                      CreateFace(fp->V[2],lp->extra,Nv1);
00173                    CopyFaceProp(fp,(MainFp+Nface-1));
00174                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00175                                fp->V[1],Nv1,lp->xxtra))
00176                      CreateFace(fp->V[1],Nv1,lp->xxtra);
00177                    else
00178                      CreateFace(fp->V[1],lp->xxtra,Nv1);
00179                    CopyFaceProp(fp,(MainFp+Nface-1));
00180                  }
00181                }
00182                else if(id == 3){
00183                  if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00184                              fp->V[1],lp->xxtra,lp->extra))
00185                    CreateFace(fp->V[1],lp->xxtra,lp->extra);
00186                  else
00187                    CreateFace(fp->V[1],lp->extra,lp->xxtra);
00188                  CopyFaceProp(fp,(MainFp+Nface-1));
00189                  if(vlist[(MainVp+lp->extra)->id].vl == fp->V[2] ||
00190                     vlist[(MainVp+lp->extra)->id].vr == fp->V[2]){
00191                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00192                                fp->V[2],Nv1,lp->extra))
00193                      CreateFace(fp->V[2],Nv1,lp->extra);
00194                    else
00195                      CreateFace(fp->V[2],lp->extra,Nv1);
00196                    CopyFaceProp(fp,(MainFp+Nface-1));
00197                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00198                                fp->V[0],Nv1,lp->xxtra))
00199                      CreateFace(fp->V[0],Nv1,lp->xxtra);
00200                    else
00201                      CreateFace(fp->V[0],lp->xxtra,Nv1);
00202                    CopyFaceProp(fp,(MainFp+Nface-1));
00203                  }
00204                  else{
00205                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00206                                fp->V[0],Nv1,lp->extra))
00207                      CreateFace(fp->V[0],Nv1,lp->extra);
00208                    else
00209                     CreateFace(fp->V[0],lp->extra,Nv1);
00210                    CopyFaceProp(fp,(MainFp+Nface-1));
00211                    if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00212                                fp->V[2],Nv1,lp->xxtra))
00213                      CreateFace(fp->V[2],Nv1,lp->xxtra);
00214                    else
00215                      CreateFace(fp->V[2],lp->xxtra,Nv1);
00216                    CopyFaceProp(fp,(MainFp+Nface-1));
00217                  }
00218                }
00219                if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00220                           lp->xxtra,lp->extra,Nv1)){
00221                  fp->V[0]=lp->xxtra;
00222                  fp->V[1]=lp->extra;
00223                  fp->V[2]=Nv1;
00224                }
00225                else{
00226                  fp->V[0]=lp->xxtra;
00227                  fp->V[1]=Nv1;
00228                  fp->V[2]=lp->extra;
00229                }
00230                lp->extra = -1;
00231                lp->xxtra = -1;
00232             }
00233           }
00234         }
00235         fp++; lp++;
00236        }
00237      }
00238    }
00239    ep++;
00240  }
00241  if(down_to_f < Nface1){
00242    fp=(MainFp+down_to_f); lp=(MainLp+down_to_f);
00243    for(i=down_to_f;i<Nface1;i++){
00244      V0=(MainVp+fp->V[0]);
00245      V1=(MainVp+fp->V[1]);
00246      V2=(MainVp+fp->V[2]);
00247      if(lp->extra >= 0){
00248        if(V0->status == DESELECTED){
00249          if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00250                       fp->V[0],lp->extra,fp->V[2]))
00251            CreateFace(fp->V[0],lp->extra,fp->V[2]);
00252          else
00253            CreateFace(fp->V[0],fp->V[2],lp->extra);
00254          CopyFaceProp(fp,(MainFp+Nface-1));
00255          CreateEdge(fp->V[0],lp->extra);
00256          fp->V[2] = lp->extra;
00257        }
00258        else if(V1->status == DESELECTED){
00259          if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00260                       fp->V[1],lp->extra,fp->V[0]))
00261            CreateFace(fp->V[1],lp->extra,fp->V[0]);
00262          else
00263            CreateFace(fp->V[1],fp->V[0],lp->extra);
00264          CopyFaceProp(fp,(MainFp+Nface-1));
00265          CreateEdge(fp->V[1],lp->extra);
00266          fp->V[0] = lp->extra;
00267        }
00268        else if(V2->status == DESELECTED){
00269          if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00270                       fp->V[2],lp->extra,fp->V[1]))
00271            CreateFace(fp->V[2],lp->extra,fp->V[1]);
00272          else
00273            CreateFace(fp->V[2],fp->V[1],lp->extra);
00274          CopyFaceProp(fp,(MainFp+Nface-1));
00275          CreateEdge(fp->V[2],lp->extra);
00276          fp->V[1] = lp->extra;
00277        }
00278      }
00279      fp++; lp++;
00280    }
00281  }
00282  X__Free(vlist);
00283  if(MainLp != NULL)X__Free(MainLp);
00284  if(draw)SetCursor(hSave);
00285  return OK;
00286  EP1:
00287  if(MainLp != NULL)X__Free(MainLp);
00288  X__Free(vlist);
00289  return FAIL;
00290 }
00291 
00292 int connected(long v1, long v2){
00293  edge *ep;
00294  long i;
00295  ep=MainEp; for(i=0;i<Nedge;i++){
00296    if( ((ep->V[0] == v1 && ep->V[1] == v2))
00297      ||((ep->V[0] == v2 && ep->V[1] == v1))
00298      )return 1;
00299    ep++;
00300  }
00301  return 0;
00302 }
00303 
00304 int AutoFillFace(long down_to){
00305  long i,node,vp,NewVertex;
00306  long face_count,*face_list;
00307  if(down_to >= Nvert)return 0;
00308  if(NvertSelect > 32000){
00309    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00310    return 0;
00311  }
00312  face_list = (long *)X__Malloc((NvertSelect+1)*10*sizeof(long));
00313  if(face_list == NULL)return 0;
00314  if(!UpdateVertexHeap(Nvert+1))return 0;
00315  if(!UpdateEdgeHeap(Nedge+(NvertSelect+1)*10))return 0;
00316  if(!UpdateFaceHeap(Nface+(NvertSelect+1)*10))return 0;
00317  NewVertex=Nvert;
00318  CreateVertex();
00319  (MainVp+NewVertex)->status=DESELECTED;
00320  (MainVp+NewVertex)->xyz[0]=NpointerX;
00321  (MainVp+NewVertex)->xyz[1]=NpointerY;
00322  (MainVp+NewVertex)->xyz[2]=NpointerZ;
00323  NvertSelect--; NvertDeselect++;
00324  for(i=0;i<Nvert;i++)(MainVp+i)->id=0;
00325  face_count=0;
00326  for(node=down_to;node<NewVertex;node++){;
00327    if((MainVp+node)->status == SELECTED){
00328      (MainVp+node)->id=1;
00329      CreateEdge(node,NewVertex);
00330      if(node < NewVertex-1)for(vp=node+1;vp < NewVertex; vp++){
00331        if((MainVp+vp)->status == SELECTED && (MainVp+vp)->id != 1){
00332           if(connected(node,vp)){
00333             CreateFace(node,vp,NewVertex);
00334             face_list[face_count]=(Nface-1);
00335             face_count++;
00336           }
00337        }
00338      }
00339    }
00340  }
00341  UpdateFaceHeap(Nface);
00342  UpdateEdgeHeap(Nedge);
00343  OrientateFaceNormals(-1,face_count,face_list);
00344  X__Free(face_list);
00345  return 1;
00346 }
00347 
00348 static int squeeze(int how){
00349  long i,j,NewVertex;
00350  point p,TVp;
00351  vertex *V0,*V1;
00352  if(NvertSelect < 2)return 0;
00353  if(how == 1){p[0]=NpointerX; p[1]=NpointerY; p[2]=NpointerZ;}
00354  if(how == 2)get_centre(0,p,TVp,FALSE);  /* the centroid */
00355  for(i=0;i<Nvert;i++)(MainVp+i)->id=0;
00356  if(Nedge > 0)for(i=0;i<Nedge;i++){
00357    V0=(MainVp+(MainEp+i)->V[0]);
00358    V1=(MainVp+(MainEp+i)->V[1]);
00359    if(V0->status == SELECTED || V1->status == SELECTED){
00360      V0->id = -1;
00361      V1->id = -1;
00362    }
00363  }
00364  EraseVertex(1);
00365  NewVertex=0; if(Nvert > 0)for(i=0;i<Nvert;i++){
00366    if((MainVp+i)->id < 0)NewVertex++;
00367  }
00368  if(!UpdateVertexHeap(Nvert+1))return 0;
00369  if(!UpdateEdgeHeap(Nedge+NewVertex+1))return 0;
00370  if(!UpdateFaceHeap(Nface+NewVertex+1))return 0;
00371  NewVertex=Nvert;
00372  CreateVertex();
00373  (MainVp+NewVertex)->status=DESELECTED;
00374  (MainVp+NewVertex)->xyz[0]=p[0];
00375  (MainVp+NewVertex)->xyz[1]=p[1];
00376  (MainVp+NewVertex)->xyz[2]=p[2];
00377  NvertSelect--; NvertDeselect++;
00378  if(Nvert > 1)for(i=0;i<Nvert-1;i++){
00379    if((MainVp+i)->id < 0)CreateEdge(i,NewVertex);
00380  }
00381  /* put in the faces where there are triangles */
00382  if(Nvert > 1)for(i=0;i<Nvert-1;i++){
00383    if((MainVp+i)->id < 0){
00384      for(j=0;j<Nvert-1;j++){
00385        if((MainVp+j)->id < 0 && connected(i,j))CreateFace(i,j,NewVertex);
00386      }
00387      (MainVp+i)->id=0;
00388    }
00389  }
00390  return 1;
00391 }
00392 
00393 void Replace_Faces(int how, double threshold){   /* gather in */
00394  /* how=0 for Normal function  how=1/2/3 for flip+weld */
00395  int id;
00396  long count;
00397  long i,vf;
00398  double th,d;
00399  vertex *vp,*vff;
00400  char temp[10];
00401  if(NvertSelect < 2){
00402    if(how == 0)SendPrgmQuery(IDQ_TOOFEWVERTICES,0);
00403    return;
00404  }
00405  if(NvertSelect > 32000){
00406    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00407    return;
00408  }
00409  if(how == 0){
00410    d=(double)TVsizeX*(double)TVsizeY;
00411    for(i=0;i<Nvert;i++){
00412      vp=(MainVp+i);
00413      if(vp->status == SELECTED)d=min(d,DIS2(vp->xyz));
00414    }
00415    d=sqrt(fabs(d))/ruler; if(d < 0.001)d=0.0;
00416    if((id=DialogBoxParam(ghinst_main,MAKEINTRESOURCE(DLG_SQUEEZE),
00417      ghwnd_main,(DLGPROC)SqueezeDlgProc,(LPARAM)&d)) < 1)return;
00418    th=d;
00419    Save_Undo(2);
00420  }
00421  else {
00422    id=3;
00423    th=threshold*threshold;
00424  }
00425  if(id < 3)squeeze(id);
00426  else{   /* Weld */
00427    if(th >= 0.0){
00428      if(how == 0){th=th*ruler; th *= th;}
00429      for(i=0;i<Nvert;i++){
00430        vp=(MainVp+i);
00431        if(vp->status == SELECTED)vp->status = INEDITOR;
00432      }
00433      while(1){
00434        vf = -1;
00435        for(i=0;i<Nvert;i++){ /* find first vertex */
00436          vp=(MainVp+i);
00437          if(vp->status == INEDITOR){vf=i; break;}
00438        }
00439        if(vf < 0)break;
00440        vff=(MainVp+vf); vff->status = SELECTED; count=1;
00441        for(i=0;i<Nvert;i++){ /* find first vertex */
00442          vp=(MainVp+i);
00443          if(vp->status == INEDITOR){
00444            d=(double)(vff->xyz[0]-vp->xyz[0])*(double)(vff->xyz[0]-vp->xyz[0])
00445                     +(vff->xyz[1]-vp->xyz[1])*(double)(vff->xyz[1]-vp->xyz[1])
00446                     +(vff->xyz[2]-vp->xyz[2])*(double)(vff->xyz[2]-vp->xyz[2]);
00447            if(d < th){count++; vp->status=SELECTED;}
00448          }
00449        }
00450        if(count == 1){ /* if only one ignore */
00451          vff->status=DESELECTED; NvertSelect--; NvertDeselect++;
00452        }
00453        else squeeze(2);
00454      }
00455    }
00456  }
00457 }
00458 
00459 void ActionRotate(int axis, double angle, int draw){
00460  short shiftkey;
00461  double theta,ctheta,stheta
00462         ,dx,dy,dz;
00463  long i,tx,ty,tz;
00464  vertex *vp;
00465  struct np {int a; BOOL clock;} np;
00466  EDIT_ACTION=YES;
00467  theta = angle*PI/180.0;
00468  if(axis != 0 && WindowBox_view)theta *= -1.0;
00469  if(draw){
00470 //   if     (GetAsyncKeyState(VK_SHIFT  ) & 0x8000)theta *=  9.0;
00471 //   else if(GetAsyncKeyState(VK_MENU   ) & 0x8000)theta *= 18.0;
00472 //   else if(GetAsyncKeyState(VK_CONTROL) & 0x8000){
00473    np.a=(int)angle;
00474    if(angle < 0)np.clock=TRUE;
00475    else         np.clock=FALSE;
00476    if(!DialogBoxParam(ghinst_main,MAKEINTRESOURCE(DLG_ROTATE),ghwnd_main,
00477                       (DLGPROC)RotateDlgProc,(LPARAM)&np))return;
00478    shiftkey=np.a;
00479    if(np.clock)angle = -1.0;
00480    else        angle =  1.0;
00481    theta = (double)shiftkey*PI/180.0;
00482    if(angle < 0)theta *= -1.0;
00483    RotateNurbsAction(axis,theta);
00484  }
00485 // if(tool == SKANIMATE){
00486 //   SkRotate(axis,theta);
00487 //   return;
00488 // }
00489 // else if(sktool)return; /* do nothing if skeleton tool is active */
00490  if(theta == 0.0)return;
00491  if(Nnurbs == 0 && NvertSelect == 0)return;
00492  if(NvertSelect == 0)goto UPDATE;
00493  ctheta=cos(theta);
00494  stheta=sin(theta);
00495 
00496  vp=MainVp; for(i=0;i<Nvert;i++){
00497   if(vp->status == SELECTED){
00498    if     (axis == 0){
00499     dx=(double)(vp->xyz[0]-NpointerX);
00500     dy=(double)(vp->xyz[1]-NpointerY);
00501     tx=NpointerX+(long)(ctheta*dx-stheta*dy);
00502     ty=NpointerY+(long)(stheta*dx+ctheta*dy);
00503     vp->xyz[0]=tx;
00504     vp->xyz[1]=ty;
00505    }
00506    else if(axis == 1){
00507     dx=(double)(vp->xyz[0]-NpointerX);
00508     dz=(double)(vp->xyz[2]-NpointerZ);
00509     tx=NpointerX+(long)(ctheta*dx-stheta*dz);
00510     tz=NpointerZ+(long)(stheta*dx+ctheta*dz);
00511     vp->xyz[0]=tx;
00512     vp->xyz[2]=tz;
00513    }
00514    else if(axis == 2){
00515     dy=(double)(vp->xyz[1]-NpointerY);
00516     dz=(double)(vp->xyz[2]-NpointerZ);
00517     ty=NpointerY+(long)(ctheta*dy-stheta*dz);
00518     tz=NpointerZ+(long)(stheta*dy+ctheta*dz);
00519     vp->xyz[1]=ty;
00520     vp->xyz[2]=tz;
00521    }
00522   }
00523   vp++;
00524  }
00525  UPDATE:
00526  RecalibrateAllBezier(); RecalibrateMapLocks();
00527  if(draw)DrawModel();
00528 }
00529 
00530 void Explode(int type){
00531  struct TEMP {int id,id1; double dxx,dyy,dzz;} tc;
00532  double radius,distance,dmin,dmax;
00533  vertex *vp,*V0,*V1,*V2;
00534  int id,id1;
00535  face *fp;
00536  long i,g2;
00537  double medianX,medianY,medianZ,nmX,nmY,nmZ,dx,dy,dz,dxx,dyy,dzz;
00538  if(NvertSelect == 0){
00539    SendPrgmQuery(IDQ_OLD2,0);
00540  }
00541  else{
00542    if(type > 0){
00543      Save_Undo(1);
00544    }
00545    dmin=(double)MAXUNIT;
00546    dmax=0.0;
00547    if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++){
00548      if(vp->status == SELECTED){
00549        distance=sqrt(
00550          (double)(vp->xyz[0]-NpointerX)*(double)(vp->xyz[0]-NpointerX)
00551         +(double)(vp->xyz[1]-NpointerY)*(double)(vp->xyz[1]-NpointerY)
00552         +(double)(vp->xyz[2]-NpointerZ)*(double)(vp->xyz[2]-NpointerZ)
00553                   );
00554         if(distance < dmin)dmin=distance;
00555         if(distance > dmax)dmax=distance;
00556      }
00557      vp++;
00558    }
00559    if(dmin < MINUNIT)dmin=(double)MINUNIT;
00560    if(type > 0){
00561      dxx=1.5; dyy=1.5; dzz=1.5;
00562      tc.id=5; tc.id1=1;
00563      tc.dxx=dxx; tc.dyy=dyy; tc.dzz=dzz;
00564      DialogBoxParam(ghinst_main,MAKEINTRESOURCE(DLG_EXPLODE),
00565            ghwnd_main,(DLGPROC)ExplodeDlgProc,(LPARAM)&tc);
00566      id=tc.id; id1=tc.id1; dxx=tc.dxx; dyy=tc.dyy; dzz=tc.dzz;
00567    }
00568    else id=1;
00569    if(id <= 0)return;
00570    else if(id < 5){
00571      radius=(double)TVsizeX/2;
00572      if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++){
00573        if(vp->status == SELECTED){
00574          if(id == 1){
00575            distance=sqrt(
00576             (double)(vp->xyz[0]-NpointerX)*(double)(vp->xyz[0]-NpointerX)
00577            +(double)(vp->xyz[1]-NpointerY)*(double)(vp->xyz[1]-NpointerY)
00578            +(double)(vp->xyz[2]-NpointerZ)*(double)(vp->xyz[2]-NpointerZ)
00579                         );
00580            if(distance > 32){ /* any small number will do */
00581            distance = radius/distance;
00582              vp->xyz[0]=NpointerX+(vp->xyz[0]-NpointerX)*distance;
00583              vp->xyz[1]=NpointerY+(vp->xyz[1]-NpointerY)*distance;
00584              vp->xyz[2]=NpointerZ+(vp->xyz[2]-NpointerZ)*distance;
00585            }
00586          }
00587          else if(id == 2){
00588            vp->xyz[2]=NpointerZ;
00589          }
00590          else if(id == 3){
00591            vp->xyz[0]=NpointerX;
00592          }
00593          else if(id == 4){
00594            vp->xyz[1]=NpointerY;
00595          }
00596        }
00597        vp++;
00598      }
00599    }
00600    else if(id == 5){
00601      if((fp=MainFp) != NULL)for(i=0;i<Nface;i++){
00602        V0=(MainVp+fp->V[0]); V1=(MainVp+fp->V[1]); V2=(MainVp+fp->V[2]);
00603        if(V0->status == SELECTED ||
00604           V1->status == SELECTED ||
00605           V2->status == SELECTED){
00606          medianX=(V0->xyz[0] + V1->xyz[0] + V2->xyz[0])/3.0;
00607          medianY=(V0->xyz[1] + V1->xyz[1] + V2->xyz[1])/3.0;
00608          medianZ=(V0->xyz[2] + V1->xyz[2] + V2->xyz[2])/3.0;
00609          if(id1 < 1){dx=dxx; dy=dyy; dz=dzz;}
00610          else if(id1 == 1){
00611            dx=1.0+dxx*(double)(rand())/32767.0;
00612            dy=1.0+dyy*(double)(rand())/32767.0;
00613            dz=1.0+dzz*(double)(rand())/32767.0;
00614          }
00615          else{
00616            distance=sqrt((medianX-NpointerX)*(medianX-NpointerX) +
00617                          (medianY-NpointerY)*(medianY-NpointerY) +
00618                          (medianZ-NpointerZ)*(medianZ-NpointerZ));
00619            if(distance > dmax){dx=1.0; dy=1.0; dz=1.0;}
00620            else{
00621              dx = dxx*0.666667/(1.0+distance/dmax);
00622              dy = dyy*0.666667/(1.0+distance/dmax);
00623              dz = dzz*0.666667/(1.0+distance/dmax);
00624            }
00625          }
00626          nmX = NpointerX+(medianX-NpointerX)*dx;
00627          nmY = NpointerY+(medianY-NpointerY)*dy;
00628          nmZ = NpointerZ+(medianZ-NpointerZ)*dz;
00629          V0->xyz[0] = V0->xyz[0] - medianX + nmX;
00630          V0->xyz[1] = V0->xyz[1] - medianY + nmY;
00631          V0->xyz[2] = V0->xyz[2] - medianZ + nmZ;
00632          V1->xyz[0] = V1->xyz[0] - medianX + nmX;
00633          V1->xyz[1] = V1->xyz[1] - medianY + nmY;
00634          V1->xyz[2] = V1->xyz[2] - medianZ + nmZ;
00635          V2->xyz[0] = V2->xyz[0] - medianX + nmX;
00636          V2->xyz[1] = V2->xyz[1] - medianY + nmY;
00637          V2->xyz[2] = V2->xyz[2] - medianZ + nmZ;
00638        }
00639        fp++;
00640      }
00641    }
00642    else if(id == 6){ /* explode to grid */
00643      if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++){
00644        if(vp->status == SELECTED){
00645          g2=grid_size/2;
00646          vp->xyz[0] = lrulerx+((vp->xyz[0]+
00647            (vp->xyz[0] >= 0 ? g2 : -g2)-lrulerx)/grid_size)*grid_size;
00648          vp->xyz[1] = lrulery+((vp->xyz[1]+
00649            (vp->xyz[1] >= 0 ? g2 : -g2)-lrulery)/grid_size)*grid_size;
00650          vp->xyz[2] = lrulerz+((vp->xyz[2]+
00651            (vp->xyz[2] >= 0 ? g2 : -g2)-lrulerz)/grid_size)*grid_size;
00652        }
00653        vp++;
00654      }
00655    }
00656    if(type > 0)DrawModel();
00657  }
00658 }
00659 
00660 long get_closest_vertex(void){
00661  vertex *vp;
00662  long i,vf;
00663  double dmin,drange,d;
00664  dmin=(double)TVsizeX*(double)TVsizeX;
00665  drange=dmin/1024;
00666  vf = -1;
00667  if((vp=MainVp) != NULL)for(i=0;i<Nvert;i++){
00668    if(vp->status == SELECTED && intriview(vp)){
00669      d=(double)(vp->xyz[0]-NpointerX)*(double)(vp->xyz[0]-NpointerX)
00670       +(double)(vp->xyz[1]-NpointerY)*(double)(vp->xyz[1]-NpointerY)
00671       +(double)(vp->xyz[2]-NpointerZ)*(double)(vp->xyz[2]-NpointerZ);
00672      if(d < dmin && d < drange){
00673        dmin=d;
00674        vf=i;
00675      }
00676    }
00677    vp->id=0; /* use this bit for found flag */
00678    vp++;
00679  }
00680  if(vf < 0){
00681    SendPrgmQuery(IDQ_NOPATHSTART,0);
00682    return -1;
00683  }
00684  return vf;
00685 }
00686 
00687 void ExtrudeAlong(void){
00688  struct np {double expan,repeat_map;} data;
00689  long vp,vf,*va;
00690  double ndv1,mu,expan=1.0,l,ll,dmap,repeat_map=4.0;
00691  long Npath,i;
00692  vector v1,v2,v3,n,dv,vp1,vp2;
00693  int id,use_map_coord=0;
00694  vertex *Vp,*Va,*Va1;
00695  HCURSOR hSave;
00696  if(NvertSelect < 1)return;
00697  if(NvertSelect > 32000){
00698    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00699    return;
00700  }
00701  if((vf=get_closest_vertex()) < 0)return; /* set ID to 0 */
00702  data.expan=expan;
00703  data.repeat_map=repeat_map;
00704  if((id=DialogBoxParam(ghinst_main,MAKEINTRESOURCE(DLG_EXTRUDEALONG),
00705      ghwnd_main,(DLGPROC)ExtrudeAlongDlgProc,(LPARAM)&data)) == FAIL)return;
00706  expan=data.expan;
00707  repeat_map=data.repeat_map;
00708  /* found first vertex of path */
00709  /* find path connected to vf and store in array va[] */
00710  if((va=(long *)X__Malloc(NvertSelect*sizeof(long))) == NULL){
00711    SendPrgmQuery(IDQ_NOMEM2,0);
00712    return;
00713  }
00714  Npath=0; va[0]=vf; (MainVp+va[0])->id=1;
00715  (MainVp+vf)->status=DESELECTED; NvertSelect--; NvertDeselect++;
00716  vp=0; while(vp < Nvert){
00717    Vp=(MainVp+vp);
00718    if(Vp->status == SELECTED && Vp->id == 0 && connected(va[Npath],vp)){
00719      Npath++;    /* add the point to the path list */
00720      va[Npath]=vp;
00721      Vp->id=1;   /* flag so not used again also indicates in path */
00722      Vp->status=DESELECTED;
00723      NvertSelect--; NvertDeselect++; /* deselect the path points */
00724      vp=0;  /* go back and look for the next connected vertex */
00725    }
00726    else vp++;
00727  }
00728  Save_Undo(0);
00729  if(Npath > 0){ /* at least 2 points needed */
00730    if(id == 2){ /* calculate expansion factor for end of path*/
00731      expan = exp(log(expan)/(double)Npath);
00732    }
00733    use_map_coord=0;
00734    {
00735      vp=0; while(vp < Nvert){ /* find if some of curve is for extrude */
00736         Vp=(MainVp+vp);
00737         if(Vp->status == SELECTED && Vp->gp > 0){
00738           use_map_coord=1;
00739           break;
00740         }
00741         vp++;
00742      }
00743    }
00744    if(use_map_coord){
00745      l=0.0; ll=0.0; /* get length of path */
00746      for(i=1;i<=Npath;i++){
00747        Va=(MainVp+va[i]); Va1=(MainVp+va[i-1]);
00748        l += sqrt(
00749            (double)(Va->xyz[0] - Va1->xyz[0])*
00750            (double)(Va->xyz[0] - Va1->xyz[0])+
00751            (double)(Va->xyz[1] - Va1->xyz[1])*
00752            (double)(Va->xyz[1] - Va1->xyz[1])+
00753            (double)(Va->xyz[2] - Va1->xyz[2])*
00754            (double)(Va->xyz[2] - Va1->xyz[2]));
00755      }
00756    }
00757    hSave=SetCursor(ghcurWait);
00758    for(i=1;i<=Npath;i++){ /* extrude along each path segment */
00759      Va=(MainVp+va[i]); Va1=(MainVp+va[i-1]);
00760      if(use_map_coord){
00761        ll += sqrt(
00762          (double)(Va->xyz[0] - Va1->xyz[0])*
00763          (double)(Va->xyz[0] - Va1->xyz[0])+
00764          (double)(Va->xyz[1] - Va1->xyz[1])*
00765          (double)(Va->xyz[1] - Va1->xyz[1])+
00766          (double)(Va->xyz[2] - Va1->xyz[2])*
00767          (double)(Va->xyz[2] - Va1->xyz[2]));
00768        dmap=ll/l*repeat_map;
00769      }
00770      POINT2VECTOR(Va->xyz ,v2);
00771      POINT2VECTOR(Va1->xyz,v1);
00772      VECSUB(v2,v1,v1)
00773      if(O_normalize(v1) == FAIL){
00774        SendPrgmQuery(IDQ_POINTSTOOCLOSE,0);
00775        goto EXIT;
00776      }
00777      if(i<Npath){
00778        POINT2VECTOR((MainVp+va[i+1])->xyz,v3);
00779        VECSUB(v3,v2,v2)
00780        if(O_normalize(v2) == FAIL){
00781          SendPrgmQuery(IDQ_POINTSTOOCLOSE,0);
00782          goto EXIT;
00783        }
00784        VECSUM(v1,v2,n)   /* n is normal to plane at point  i */
00785      }
00786      else VECCOPY(v1,n)
00787      POINT2VECTOR((MainVp+va[i])->xyz,v2);
00788      ndv1=DOT(n,v1);       /* n.(vector point1 -> point2)  */
00789      if(fabs(ndv1) < 1.e-10){
00790         SendPrgmQuery(IDQ_NOLOOPBACK,0);
00791         goto EXIT;
00792      }
00793      if(!CreateAttachedCopy(1)){
00794        SendPrgmQuery(IDQ_NOMEM2,0);
00795        goto EXIT;
00796      }
00797      vp=0; while(vp < Nvert){ /* move new points into position */
00798        Vp=(MainVp+vp);
00799        if(Vp->status == SELECTED){
00800          if(use_map_coord && Vp->gp > 0){
00801            Vp->y = dmap;
00802          }
00803          POINT2VECTOR(Vp->xyz,v3);
00804          VECSUB(v2,v3,v3)         /* intersection of ray with plane */
00805          mu=DOT(n,v3)/ndv1;       /* at v2   */
00806          if(id < 2){
00807            Vp->xyz[0] += (long)(mu*v1[0]);
00808            Vp->xyz[1] += (long)(mu*v1[1]);
00809            Vp->xyz[2] += (long)(mu*v1[2]);
00810          }
00811          else{    /* expand while extruding along the curve */
00812            VECSCALE(mu,v1,dv)
00813            POINT2VECTOR(Vp->xyz,vp1);
00814            VECSUM(vp1,dv,vp2)
00815            POINT2VECTOR((MainVp+va[i])->xyz,vp1);
00816            VECSUB(vp2,vp1,dv)
00817            Vp->xyz[0] = (long)(vp1[0] + expan*dv[0]);
00818            Vp->xyz[1] = (long)(vp1[1] + expan*dv[1]);
00819            Vp->xyz[2] = (long)(vp1[2] + expan*dv[2]);
00820          }
00821        }
00822        vp++;
00823      }
00824    }
00825    /* set curve now as selected  everything else deselected*/
00826    vp=0; while(vp < Nvert){
00827      Vp=(MainVp+vp);
00828      if(Vp->status == SELECTED){
00829        Vp->status=DESELECTED; NvertSelect--; NvertDeselect++;
00830      }
00831      vp++;
00832    }
00833    for(i=0;i<=Npath;i++)if((MainVp+va[i])->status == DESELECTED){
00834      (MainVp+va[i])->status=SELECTED;
00835      NvertSelect++; NvertDeselect--;
00836    }
00837  }
00838  EXIT:
00839  SetCursor(hSave);
00840  X__Free(va);
00841  DrawModel(); UpdateCounters();
00842  return;
00843 }
00844 
00845 static double dspacing(long Va1, long Va2){
00846  vertex *va1,*va2;
00847  double d;
00848  va1=(MainVp+Va1); va2=(MainVp+Va2);
00849  d=(double)(va1->xyz[0] - va2->xyz[0]) *
00850    (double)(va1->xyz[0] - va2->xyz[0]) +
00851    (double)(va1->xyz[1] - va2->xyz[1]) *
00852    (double)(va1->xyz[1] - va2->xyz[1]) +
00853    (double)(va1->xyz[2] - va2->xyz[2]) *
00854    (double)(va1->xyz[2] - va2->xyz[2]);
00855  d=sqrt(d);
00856  return d;
00857 }
00858 
00859 void JoinTwoCurves(void){
00860  HCURSOR hSave;
00861  vertex *Vp;
00862  long vp,vf1,vf2,*va1,*va2,*tempva,tempv,vactive,vnext,vcurrent;
00863  double d,dmin=1e32;
00864  long Npath1,Npath2,i,j,k0,k1,k2,flag;
00865  if(NvertSelect<6){
00866    SendPrgmQuery(IDQ_TOOFEWVERTICES,0);
00867    return;
00868  }
00869  if(NvertSelect > 32000){
00870    SendPrgmQuery(IDQ_WIRETOOBIG,0);
00871    return;
00872  }
00873  EDIT_ACTION=YES;
00874  hSave=SetCursor(ghcurWait);
00875  vp=0; vf1=vf2=-1;
00876  while(vp < Nvert){
00877    Vp=(MainVp+vp);
00878    if(Vp->status == SELECTED)vf1=vp;
00879    Vp->id=0; /* use this bit for found flag */
00880    vp++;
00881  }
00882  if(vf1 < 0){
00883    SendPrgmQuery(IDQ_NOCURVE1,0);
00884    goto FINISH;
00885  }
00886  /* find path connected to vf1 and store in array va1[] */
00887  if((va1=(long *)X__Malloc(NvertSelect*sizeof(long))) == NULL){
00888    SendPrgmQuery(IDQ_NOMEM2,0);
00889    goto FINISH;
00890  }
00891  Npath1=0; va1[0]=vf1; (MainVp+va1[0])->id=1;
00892  (MainVp+vf1)->status=DESELECTED; NvertSelect--; NvertDeselect++;
00893  vp=0; while(vp < Nvert){
00894    Vp=(MainVp+vp);
00895    if(Vp->status == SELECTED && Vp->id == 0 && connected(va1[Npath1],vp)){
00896      Npath1++;    /* add the point to the path list */
00897      va1[Npath1]=vp;
00898      Vp->id=1;   /* flag so not used again also indicates in path */
00899      Vp->status=DESELECTED;
00900      NvertSelect--; NvertDeselect++; /* deselect the path points */
00901      vp=0;  /* go back and look for the next connected vertex */
00902    }
00903    else vp++;
00904  }
00905  /* now we've curve 1 get curve 2 */
00906  vp=0;
00907  while(vp < Nvert){
00908    if((MainVp+vp)->status == SELECTED){
00909      vf2=vp; break; /* first one found will be enough */
00910    }
00911    vp++;
00912  }
00913  if(vf2 < 0){
00914    SendPrgmQuery(IDQ_NOCURVE2,0);
00915    X__Free(va1);
00916    goto GETOUT;
00917  }
00918  /* find path connected to vf1 and store in array va1[] */
00919  if((va2=(long *)X__Malloc(NvertSelect*sizeof(long))) == NULL){
00920    SendPrgmQuery(IDQ_NOMEM2,0);
00921    X__Free(va1);
00922    goto GETOUT;
00923  }
00924  Npath2=0; va2[0]=vf2; (MainVp+va2[0])->id=2;
00925  (MainVp+vf2)->status=DESELECTED; NvertSelect--; NvertDeselect++;
00926  vp=0; while(vp < Nvert){
00927    Vp=(MainVp+vp);
00928    if(Vp->status == SELECTED && Vp->id == 0 && connected(va2[Npath2],vp)){
00929      Npath2++;    /* add the point to the path list */
00930      va2[Npath2]=vp;
00931      Vp->id=2;   /* flag so not used again also indicates in path */
00932      Vp->status=DESELECTED;
00933      NvertSelect--; NvertDeselect++; /* deselect the path points */
00934      vp=0;  /* go back and look for the next connected vertex */
00935    }
00936    else vp++;
00937  }
00938  Npath1++; Npath2++;   /* correct number of vertices */
00939  if(Npath1 < 3 || Npath2 < 3 || NvertSelect > 0){
00940    SendPrgmQuery(IDQ_NOTSUITABLECURVE,0);
00941    X__Free(va1);
00942    X__Free(va2);
00943    goto GETOUT;
00944  }
00945  Save_Undo(0);
00946  /* find the smallest distance between the two paths*/
00947  for(i=0;i<Npath1;i++)
00948    for(j=0;j<Npath2;j++){
00949      if((d=dspacing(va1[i],va2[j])) < dmin){
00950        dmin=d; vf1=va1[i]; vf2=va2[j];
00951      }
00952  }
00953  /* for the paths re-make with first vertex the closest */
00954  Npath1=0; va1[0]=vf1; (MainVp+va1[0])->id=0;
00955  vp=0; while(vp < Nvert){
00956    Vp=(MainVp+vp);
00957    if(Vp->id == 1 && connected(va1[Npath1],vp)){
00958      Npath1++;
00959      va1[Npath1]=vp;
00960      Vp->id=0;
00961      vp=0;
00962    }
00963    else vp++;
00964  }
00965  Npath2=0; va2[0]=vf2; (MainVp+va2[0])->id=0;
00966  vp=0; while(vp < Nvert){
00967    Vp=(MainVp+vp);
00968    if(Vp->id == 2 && connected(va2[Npath2],vp)){
00969      Npath2++;
00970      va2[Npath2]=vp;
00971      Vp->id=0;
00972      vp=0;
00973    }
00974    else vp++;
00975  }
00976  if(Npath1 == 0 || Npath2 == 0){
00977    SendPrgmQuery(IDQ_NOJOIN,0);
00978    goto GETOUT;
00979  }
00980  Npath1++; Npath2++;
00981 //fprintf(debug,"1 %ld    2 %ld\n",Npath1,Npath2);
00982  /* make Npath1 the main path with the fewest vertices */
00983  if(Npath2 < Npath1){
00984 //fprintf(debug,"swapping curves\n");
00985    tempv=vf1; vf1=vf2; vf2=tempv;
00986    tempva=va1; va1=va2; va2=tempva;
00987    i=Npath1; Npath1=Npath2; Npath2=i;
00988  }
00989  /* which way round the second loop */
00990 
00991  /* make a start */
00992  if(dspacing(va1[1],va2[1]) > dspacing(va1[1],va2[Npath2-1])){
00993    /* curve 2 must be reversed */
00994 //fprintf(debug,"changing direction\n");
00995    for(i=1;i<=(Npath2-1)/2;i++){
00996      tempv=va2[i];
00997      va2[i]=va2[Npath2-i];
00998      va2[Npath2-i]=tempv;
00999    }
01000  }
01001  /* extend the arrays                 */
01002  if(!UpdateEdgeHeap(Nedge+2*(Npath1+Npath2+1)))goto UPDATE_HEAP;
01003  if(!UpdateFaceHeap(Nface+2*(Npath1+Npath2+4)))goto UPDATE_HEAP;
01004  /* vcurrent is on the larger curve   */
01005  k0=1;
01006  CreateEdge(va1[0],va2[0]);
01007  (MainVp+va1[0])->id=0;                    /* first has been found closest ! */
01008  for(i=1;i<Npath1;i++){
01009    dmin=1e32; k1= -1;
01010    if(k0 < Npath2)for(j=k0;j<Npath2;j++){
01011      if((d=dspacing(va1[i],va2[j])) < dmin){dmin=d; k1=j;}
01012    }
01013    if(k1 >= 0){
01014      k0=k1;
01015      (MainVp+va1[i])->id=k0;
01016      CreateEdge(va1[i],va2[k0]);
01017    }
01018  }
01019  /* we now have a list of best connections from smaller to larger - go to it*/
01020  for(i=0;i<Npath1;i++){
01021    flag=0;     /* flagged when moving closer to vertex i+1 */
01022    vactive=va1[i];
01023    flag=0;
01024    k0=(long)((MainVp+va1[i])->id);
01025    vcurrent=va2[k0];
01026    if(i < Npath1-1){
01027      vnext=va1[i+1];
01028      k1=(long)((MainVp+va1[i+1])->id);
01029      k2=k1;
01030    }
01031    else{  /* fizing up the last bit */
01032      vnext=va1[0]; k1=Npath2; k2=0;
01033    }
01034    if(k1 > k0){ /* at least one edge between i and i+1 */
01035      if(k1 > k0+1){ /* at least one vertex between i and i+1 */
01036        for(j=k0+1;j<k1;j++){
01037          vcurrent=va2[j];
01038          if(flag == 0){ /* check which end is closest */
01039            CreateEdge(vcurrent,vactive);
01040            CreateFace(vactive,vcurrent,va2[j-1]);
01041            if(dspacing(vcurrent,va2[k0]) > dspacing(vcurrent,va2[k2])){
01042              /* switch to connecting to i+1 */
01043              CreateEdge(vcurrent,vnext);
01044              CreateFace(vactive,vcurrent,vnext);
01045              flag=1;
01046            }
01047          }
01048          else{ /* no option must be vnext */
01049            CreateEdge(vcurrent,vnext);
01050            CreateFace(va2[j-1],vnext,vcurrent);
01051          }
01052        }
01053      }
01054      /* put in last bit */
01055      if(flag == 0){
01056        CreateEdge(vcurrent,vnext);  /* check closest ??? */
01057        CreateFace(vactive,vnext,vcurrent);
01058      }
01059      CreateFace(vcurrent,vnext,va2[k2]);
01060    }
01061    else{ /* both i and i+1 are attached to same point */
01062          /* edges in place just put in face           */
01063      CreateFace(vactive,vcurrent,vnext);
01064    }
01065  }
01066  UPDATE_HEAP:
01067  UpdateFaceHeap(Nface);    /* release any storage that was given as  */
01068  UpdateEdgeHeap(Nedge);    /* an over estimate when it was allocated */
01069  X__Free(va1);
01070  X__Free(va2);
01071  GETOUT:
01072  DrawModel();
01073  UpdateCounters();
01074  FINISH:
01075  SetCursor(hSave);
01076 }
01077 
01078 void Spin(int connect, int nsections, BOOL quiet, int Iaxis){
01079  HCURSOR hSave;
01080  int n=12,angle,i,axis,j,np1,np2;
01081  double theta=360.0,dmap=1.0;
01082  long *p1,*p2,vp,vps,vsave;
01083  vertex *Vp;
01084  if(NvertSelect < 1)return;
01085  if(NvertSelect > 32000){
01086    SendPrgmQuery(IDQ_WIRETOOBIG,0);
01087    return;
01088  }
01089  if(!quiet){
01090    if(Read1Int1Real("Lathe","# Sections","Angle",&n,3,100,&theta,
01091                     -355.0,360.0,ghwnd_main) != OK)return;
01092    axis=ActiveView;
01093  }
01094  else{
01095    axis=Iaxis;
01096    n=nsections;
01097    theta=360.0;
01098  }
01099  angle=(int)theta;
01100 
01101  dmap=4.0/(double)n*(double)angle/360.0;
01102  if(abs(angle) < 2)return;
01103  p1=NULL; p2=NULL;
01104  if(angle == 360){
01105    if(n < 3)return;             /* insist on at least 3 points in full rot */
01106    theta =(double)angle/(double)n; n--;
01107    if(connect == 1){
01108      p1=(long *)X__Malloc(sizeof(long)*NvertSelect);
01109      if(p1 == NULL){
01110        SendPrgmQuery(IDQ_NOMEM2,0);
01111        return;
01112      }
01113      p2=(long *)X__Malloc(sizeof(long)*NvertSelect);
01114      if(p2 == NULL){
01115        SendPrgmQuery(IDQ_NOMEM2,0);
01116        X__Free(p1);
01117        return;
01118      }
01119      np1=0; vps=Nvert;
01120      vp=0; while(vp < Nvert){
01121        if((MainVp+vp)->status==SELECTED){*(p1+np1)=vp; np1++;}
01122        vp++;
01123      }
01124    }
01125  }
01126  else {
01127    n--;
01128    theta=(double)angle/(double)n;
01129  }
01130  if(!quiet){
01131    hSave=SetCursor(ghcurWait);
01132    Save_Undo(0);
01133  }
01134  for(i=0;i<n;i++){
01135    vsave=Nvert;
01136    if(connect==0 && !AddCopy(0))goto FINISHED;
01137    if(connect==1 && !CreateAttachedCopy(1)){
01138      if(p1 != NULL)X__Free(p1);
01139      if(p1 != NULL)X__Free(p2);
01140      goto FINISHED;
01141    }
01142    ActionRotate(axis,theta,0);
01143    {
01144      vp=vsave; while(vp < Nvert){
01145        Vp=(MainVp+vp);
01146        if(Vp->status == SELECTED && Vp->gp > 0)Vp->y += dmap;
01147        vp++;
01148      }
01149    }
01150  }
01151 /* tidy up for 360  rotation  fill in the missing links */
01152  if(angle==360 && connect == 1){
01153    /* extend the Edge/Face heaps */
01154    if(!UpdateEdgeHeap(Nedge+2*np1))goto EXIT;
01155    if(!UpdateFaceHeap(Nface+2*np1))goto EXIT;
01156    np2=0;
01157    vp=vps; while(vp < Nvert){
01158      if((MainVp+vp)->status==SELECTED){
01159        *(p2+np2)=vp; np2++;
01160      }
01161      vp++;
01162    }
01163    if(np1 != np2){MessageBeep(MB_OK); goto EXIT;}
01164    for(i=0;i<np1;i++)CreateEdge(*(p1+i),*(p2+i));
01165    if(np1 > 1){
01166      for(i=0;i<np1-1;i++) for(j=i+1;j<np1;j++){
01167        if(connected(*(p1+i),*(p1+j))){
01168          CreateEdge(*(p1+i),*(p2+j));
01169          CreateFace(*(p1+i),*(p2+j),*(p2+i));
01170          CreateFace(*(p1+i),*(p1+j),*(p2+j));
01171        }
01172      }
01173    }
01174    EXIT:
01175    X__Free(p1);
01176    X__Free(p2);
01177    UpdateEdgeHeap(Nedge);
01178    UpdateFaceHeap(Nface);
01179  }
01180  FINISHED:
01181  if(!quiet){
01182    SetCursor(hSave);
01183    DrawModel(); UpdateCounters();
01184  }
01185 }
01186 
01187 void CopyConnected(void){
01188 #define PATH 11
01189  int flag1=0,flag2=0;
01190  HCURSOR hSave;
01191  long vp,vp2,Nv;
01192  point centre,TVp;
01193  vector x;
01194  vertex *Vp;
01195  int i=0;
01196  if(NvertSelect < 1) return;
01197  if(NvertSelect > 32000){
01198    SendPrgmQuery(IDQ_WIRETOOBIG,0);
01199    return;
01200  }
01201  Save_Undo(0);
01202  SelectConnected(PATH);                // Set all path points to PATH status.
01203  vp=0; vp2=-1;
01204  while(vp < Nvert){
01205   if((MainVp+vp)->status==PATH){
01206     flag1=1; vp2=vp;
01207   }
01208   else if((MainVp+vp)->status==SELECTED)flag2=1;
01209   vp++;
01210  }
01211  if(flag1 == 0){
01212    SendPrgmQuery(IDQ_NONEARVERTEX,0);
01213    return;
01214  }
01215  if(flag2 == 0){
01216    vp=0; while(vp < Nvert){
01217      if((MainVp+vp)->status==PATH)(MainVp+vp)->status=DESELECTED;
01218      vp++;
01219    }
01220    DrawModel(); UpdateCounters();
01221    SendPrgmQuery(IDQ_BADCURVE,0);
01222    return;
01223  }
01224  Nv=Nvert;
01225  hSave=SetCursor(ghcurWait);
01226  vp=0; while(vp < Nv){
01227    if((MainVp+vp)->status==PATH){
01228      if(i > 0){
01229        if(!AddCopy(0))goto FINISHED;
01230      }
01231      get_centre(1,centre,TVp,FALSE);
01232      Vp=(MainVp+vp);
01233      x[0]=Vp->xyz[0]-centre[0];          // Calculate distance to move.
01234      x[1]=Vp->xyz[1]-centre[1];
01235      x[2]=Vp->xyz[2]-centre[2];
01236      vp2=0; while(vp2 < Nvert){
01237        Vp=(MainVp+vp2);
01238        if(Vp->status==SELECTED){
01239          Vp->xyz[0]+=x[0];                // Move selected to new position.
01240          Vp->xyz[1]+=x[1];
01241          Vp->xyz[2]+=x[2];
01242        }
01243        vp2++;
01244      }
01245      ++i;
01246    }
01247    vp++;
01248  }
01249  FINISHED:
01250  vp=0; while(vp < Nvert){
01251    if(Vp->status==SELECTED) {
01252      Vp->status=DESELECTED; NvertSelect--; NvertDeselect++;
01253    }
01254    vp++;
01255  }
01256  vp=0; while(vp < Nvert){
01257    Vp=(MainVp+vp);
01258    if(Vp->status==PATH) {             // Select path on exit.
01259      Vp->status=SELECTED;  ++NvertSelect; --NvertDeselect;
01260    }
01261    vp++;
01262  }
01263  SetCursor(hSave);
01264  DrawModel(); UpdateCounters();
01265 }
01266 
01267 void Flip(void){ /* 0 = H 1= V */
01268  HCURSOR hSave;
01269  struct np {int plane,weld;} data;
01270  vertex *Vp;
01271  long vp,vps;
01272  long NpX2,NpY2,NpZ2,toll,x,y,z;
01273  int sx,sy,swi,kid = -1;
01274  int id,plane,weld;
01275  data.plane=0;
01276  data.weld=0;
01277  if((id=DialogBoxParam(ghinst_main,MAKEINTRESOURCE(DLG_FLIP),
01278      ghwnd_main,(DLGPROC)FlipDlgProc,(LPARAM)&data)) == FAIL)return;
01279  plane=data.plane;
01280  weld=data.weld;
01281  if     (ActiveView == TRITOP){
01282    if(plane == 0)kid=2; else kid=1;
01283  }
01284  else if(ActiveView == TRIFRONT){
01285    if(plane == 0)kid=3; else kid=1;
01286  }
01287  else if(ActiveView == TRIRIGHT){
01288    if(plane == 0)kid=3; else kid=2;
01289  }
01290  if(NvertSelect == 0 || kid < 0)return;
01291  if(weld){
01292 // below may not be a good idea for getting toll - might work now  ???
01293    GetWindowCoords(ActiveView,NpointerX,NpointerY,NpointerZ,&sx,&sy);
01294    if(plane == 0){if(sy < 4)sy += 3; else sy -= 3;}
01295    if(plane == 1){if(sx < 4)sx += 3; else sx -= 3;}
01296    GetWorldCoords(ActiveView,&x,&y,&z,sx,sy);
01297    if     (kid == 1)toll=labs(NpointerX-x);
01298    else if(kid == 2)toll=labs(NpointerY-y);
01299    else if(kid == 3)toll=labs(NpointerZ-z);
01300 // otherwise
01301 //   toll=MINUNIT/2;
01302    Save_Undo(2);
01303    hSave=SetCursor(ghcurWait);
01304    vps=Nvert;
01305    AddCopy(0);
01306  }
01307  else Save_Undo(1);
01308  NpX2=NpointerX*2;
01309  NpY2=NpointerY*2;
01310  NpZ2=NpointerZ*2;
01311  vp=0; while(vp < Nvert){
01312    Vp=(MainVp+vp);
01313    if(Vp->status == SELECTED){
01314      switch(kid){
01315        case 1: Vp->xyz[0] = NpX2-Vp->xyz[0]; break;
01316        case 2: Vp->xyz[1] = NpY2-Vp->xyz[1]; break;
01317        case 3: Vp->xyz[2] = NpZ2-Vp->xyz[2]; break;
01318      }
01319    }
01320    vp++;
01321  }
01322  if(weld){
01323    vp=0; while(vp < vps){ /* get vertices on edge in old */
01324      Vp=(MainVp+vp);
01325      if(Vp->id >= 0 && Vp->status == DESELECTED){
01326        swi=0;
01327        switch(kid){
01328          case 1: if(labs(Vp->xyz[0] - NpointerX) < toll)swi=1; break;
01329          case 2: if(labs(Vp->xyz[1] - NpointerY) < toll)swi=1; break;
01330          case 3: if(labs(Vp->xyz[2] - NpointerZ) < toll)swi=1; break;
01331        }
01332        if(swi){Vp->status=SELECTED; NvertSelect++; NvertDeselect--;}
01333      }
01334      vp++;
01335    }
01336    vp=vps; while(vp < Nvert){ /* get vertices on edge in new */
01337      Vp=(MainVp+vp);
01338      if(Vp->status == SELECTED){
01339        swi=0;
01340        switch(kid){
01341          case 1: if(labs(Vp->xyz[0] - NpointerX) > toll)swi=1; break;
01342          case 2: if(labs(Vp->xyz[1] - NpointerY) > toll)swi=1; break;
01343          case 3: if(labs(Vp->xyz[2] - NpointerZ) > toll)swi=1; break;
01344        }
01345        if(swi){Vp->status=DESELECTED; NvertSelect--; NvertDeselect++;}
01346      }
01347      vp++;
01348    }
01349    Replace_Faces(kid,(double)toll);
01350    SetCursor(hSave);
01351  }
01352  DrawModel(); UpdateCounters();
01353 }
01354 
01355 #include "splines.c"
01356 
01357 void SmoothCurve(void){
01358  vertex *Vp;
01359  long vp,vf,*va;
01360  double d,dmin,drange,dist,gds,gde,gs,ge,kx[4],ky[4],kz[4];
01361  long Npath,i;
01362  int id;
01363  char response[20];
01364  if(NvertSelect < 1)return;
01365  if(NvertSelect > 100){
01366    SendPrgmQuery(IDQ_WIRETOOBIG,0);
01367    return;
01368  }
01369  dmin=(double)TVsizeX*(double)TVsizeX;
01370  drange=dmin/1024;
01371  vp=0; vf= -1;
01372  while(vp < Nvert){
01373    Vp=(MainVp+vp);
01374    if(Vp->status == SELECTED && intriview(Vp)){
01375      d=(double)(Vp->xyz[0]-NpointerX)*(double)(Vp->xyz[0]-NpointerX)
01376       +(double)(Vp->xyz[1]-NpointerY)*(double)(Vp->xyz[1]-NpointerY)
01377       +(double)(Vp->xyz[2]-NpointerZ)*(double)(Vp->xyz[2]-NpointerZ);
01378      if(d < dmin && d < drange){
01379        dmin=d;
01380        vf=vp;
01381      }
01382    }
01383    Vp->id=0; /* use this bit for found flag */
01384    vp++;
01385  }
01386  if(vf < 0){
01387    SendPrgmQuery(IDQ_NOPATHSTART,0);
01388    return;
01389  }
01390  if((va=(long *)X__Malloc(NvertSelect*sizeof(long))) == NULL){
01391    SendPrgmQuery(IDQ_NOMEM2,0);
01392    return;
01393  }
01394  Save_Undo(1);
01395  Npath=0; va[0]=vf; (MainVp+va[0])->id=1;
01396  vp=0; while(vp < Nvert){
01397    Vp=(MainVp+vp);
01398    if(Vp->status == SELECTED && Vp->id == 0 && connected(va[Npath],vp)){
01399      Npath++;
01400      va[Npath]=vp;
01401      Vp->id=1;
01402      vp=0;
01403    }
01404    else vp++;
01405  }
01406  Npath++;
01407  if(Npath > 4){ /* at least 5 points needed */
01408    dist=dspacing(va[Npath-2],va[1]);
01409    gds=dist/dspacing(va[1],va[0]); gde=dist/dspacing(va[Npath-1],va[Npath-2]);
01410    if(GetAsyncKeyState(VK_CONTROL) & 0x8000){
01411      sprintf(response,"1.0,1.0");
01412      RequestCharString(10,response,"Flexibility",ghwnd_main);
01413      if(sscanf(response,"%lf,%lf",&gs,&ge) == 2){
01414        if(gs < 0.01 || gs > 20)gs=1.0;
01415        if(ge < 0.01 || ge > 20)ge=1.0;
01416        gds *= gs; gde *= ge;
01417      }
01418    }
01419    else if(GetAsyncKeyState(VK_SHIFT) & 0x8000){
01420      gds *= 2; gde *= 2;
01421    }
01422    else if(GetAsyncKeyState(VK_MENU) & 0x8000){
01423      gds *= 4; gde *= 4;
01424    }
01425    gs = (double)((MainVp+va[1])->xyz[0] - (MainVp+va[0])->xyz[0])*gds;
01426    ge = (double)((MainVp+va[Npath-1])->xyz[0] - (MainVp+va[Npath-2])->xyz[0])*gde;
01427    SplinesG(kx,(double)(MainVp+va[1])->xyz[0],
01428                (double)(MainVp+va[Npath-2])->xyz[0],gs,ge);
01429    gs = (double)((MainVp+va[1])->xyz[1] - (MainVp+va[0])->xyz[1])*gds;
01430    ge = (double)((MainVp+va[Npath-1])->xyz[1] - (MainVp+va[Npath-2])->xyz[1])*gde;
01431    SplinesG(ky,(double)(MainVp+va[1])->xyz[1],
01432                (double)(MainVp+va[Npath-2])->xyz[1],gs,ge);
01433    gs = (double)((MainVp+va[1])->xyz[2] - (MainVp+va[0])->xyz[2])*gds;
01434    ge = (double)((MainVp+va[Npath-1])->xyz[2] - (MainVp+va[Npath-2])->xyz[2])*gde;
01435    SplinesG(kz,(double)(MainVp+va[1])->xyz[2],
01436                (double)(MainVp+va[Npath-2])->xyz[2],gs,ge);
01437    for(i=2;i<Npath-2;i++){
01438      gds=(double)(i-1)/(double)(Npath-3);
01439      (MainVp+va[i])->xyz[0] = (long)SplinesR(kx,gds);
01440      (MainVp+va[i])->xyz[1] = (long)SplinesR(ky,gds);
01441      (MainVp+va[i])->xyz[2] = (long)SplinesR(kz,gds);
01442    }
01443  }
01444  else{
01445    SendPrgmQuery(IDQ_TOOFEWVERTICES,0);
01446  }
01447  X__Free(va);
01448  DrawModel();
01449 }
01450 

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