IK3D.C

Go to the documentation of this file.
00001 /* --
00002 OpenFX version 2.0 - Modelling, Animation and Rendering Package
00003 Copyright (C) 2000 - OpenFX Development Team
00004 
00005 This program is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU General Public License
00007 as published by the Free Software Foundation; either version 2
00008 of the License, or (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 
00019 You may contact the OpenFX development team via elecronic mail
00020 at core@openfx.org, or visit our website at http://openfx.org for
00021 further information and support details.
00022 -- */
00023 
00024 /*  IK3D.C                                                            */
00025 
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <math.h>
00029 #include <windows.h>
00030 
00031 #include "struct.h"
00032 #include "dstruct.h"
00033 
00034 
00035 #include "ik3d.h"
00036 
00037 #define VECCOPY(a,b)    { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; }
00038 #define VECSUB(a,b,c)   { c[0]=a[0]-b[0]; c[1]=a[1]-b[1]; c[2]=a[2]-b[2];}
00039 #define VECSUM(a,b,c)   { c[0]=a[0]+b[0]; c[1]=a[1]+b[1]; c[2]=a[2]+b[2];}
00040 #define VECSCALE(a,b,c) { c[0]=(a)*b[0]; c[1]=(a)*b[1]; c[2]=(a)*b[2];}
00041 #define DOT(a,b)        ( (a[0]*b[0]) + (a[1]*b[1]) + (a[2]*b[2]) )
00042 #define CROSS(v1,v2,r)  { \
00043                           r[0] = (v1[1]*v2[2]) - (v2[1]*v1[2]);  \
00044                           r[1] = (v1[2]*v2[0]) - (v1[0]*v2[2]);  \
00045                           r[2] = (v1[0]*v2[1]) - (v2[0]*v1[1]);  \
00046                          }
00047 
00048 #ifndef PI
00049 #define PI 3.1415926
00050 #endif
00051 
00052 #ifndef PI2
00053 #define PI2 PI/2
00054 #endif
00055 
00056 static HWND      hParent;
00057 static HINSTANCE hThisInstance;
00058 static char *szViewClass="OFX:IKtestClass";
00059 static SYSTEM_INFO sys_info;
00060 static int    xScreen,yScreen;
00061 static DWORD fdwStyle = WS_POPUP | WS_CAPTION | ! WS_SYSMENU |
00062                         WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
00063 static HCURSOR hcurSave,hcurPen1=NULL;
00064 static char filename[256];
00065 
00066 static int pen=0,tracetool=0,version=0;
00067 static long Lv= -1,Fv= -1,Nv=0,Ne=0;
00068 static struct TVLIST {BOOL inc; int x,y,z; long id;
00069                       vector p;
00070                       vector ax,ay,az;}     *TVlist=NULL;
00071 static struct TELIST {BOOL inc; int v1,v2;} *TElist=NULL;
00072 static FILE *debug=NULL;
00073 
00074 static LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
00075 static BOOL MenuCommand(HWND, WORD);
00076 static BOOL Tester(void);
00077 static void DrawRubberLine(HWND, int, int);
00078 static void DrawList(HWND, HDC);
00079 static void AddTraceVertex(int, int);
00080 static int GetVertexAtCursor(int, int);
00081 static void IterateTowardsGoal(HWND, int, int);
00082 static void SetupStart(void);
00083 static void RotateVectorRound(vector, vector, vector, double);
00084 static BOOL normalize(vector v);
00085 static void rotz(double [4][4], double);
00086 static void roty(double [4][4], double);
00087 static void rotx(double [4][4], double);
00088 static void mv4by1(double [4][4], vector, vector);
00089 static void m4by4(double [4][4], double [4][4], double [4][4]);
00090 static void rotate_round_vector(double, vector, double [4][4]);
00091 static void CalculateTranspose(double *, double *, long, long);
00092 static void MultiplyMatrix(double *, long, long,
00093                            double *, long, long,
00094                            double *);
00095 static BOOL InvertMatrix(double *, long, double *);
00096 static BOOL StepOK(double *, double *, double *, long, long, double, double);
00097 static void UpdateTheLinkage(long, double *);
00098 static void CalculateJacobian(double *, long);
00099 static double Length(double *, long);
00100 static double Dist(double *, double *, long);
00101 
00102 static BOOL Tester(void){
00103  MSG msg;
00104  HWND hDesktopWnd,hWnd;
00105  HDC hDCcaps;
00106  WNDCLASS wndclass;
00107  TVlist=NULL; TElist=NULL; Nv=0; Ne=0;
00108  hDesktopWnd = GetDesktopWindow();
00109  hDCcaps     = GetDC(hDesktopWnd);
00110  ReleaseDC(hDesktopWnd,hDCcaps);
00111  GetSystemInfo(&sys_info);
00112  wndclass.style         = 0;
00113  wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
00114  wndclass.cbClsExtra    = 0 ;
00115  wndclass.cbWndExtra    = 0 ;
00116  wndclass.hInstance     = hThisInstance ;
00117  wndclass.hIcon         = NULL;
00118  wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
00119  wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
00120  wndclass.lpszMenuName  = "tracemenu" ;
00121  wndclass.lpszClassName = szViewClass;
00122  if (!RegisterClass (&wndclass))  return FALSE ;
00123  xScreen = GetSystemMetrics(SM_CXSCREEN) ;
00124  yScreen = GetSystemMetrics(SM_CYSCREEN) ;
00125  hWnd = CreateWindow(
00126         szViewClass,
00127         "Pseudo 3D Inverse Kinematics (IK) Test Engine",
00128         fdwStyle,
00129         25,
00130         25,
00131         xScreen-50,
00132         yScreen-50,
00133         hParent,
00134         NULL,
00135         hThisInstance,
00136         NULL) ;
00137  if(hWnd == NULL)return FALSE;
00138  hcurPen1=LoadCursor(hThisInstance,MAKEINTRESOURCE(IDC_PEN1));
00139  ShowWindow (hWnd,SW_SHOWNA);
00140  PostMessage(hWnd,WM_COMMAND,(WPARAM)IDM_DRAWIT,0);
00141  while(GetMessage (&msg,NULL,0,0)){
00142    TranslateMessage (&msg);
00143    DispatchMessage (&msg);
00144  }
00145  DestroyWindow(hWnd);
00146  if(hcurPen1 != NULL)DeleteObject(hcurPen1);
00147  UnregisterClass(wndclass.lpszClassName,wndclass.hInstance);
00148  if(TVlist != NULL)X__Free(TVlist); TVlist=NULL; Nv=0;
00149  if(TElist != NULL)X__Free(TElist); TElist=NULL; Ne=0;
00150  return TRUE;
00151 }
00152 
00153 LRESULT CALLBACK MainWndProc(HWND hWnd,UINT iMessage,WPARAM wParam,
00154                              LPARAM lParam){
00155  static BOOL bToolCaptured=FALSE;
00156  static HCURSOR hCursorSave;
00157  static POINT LastPt;
00158  PAINTSTRUCT ps;
00159  HDC hDC;
00160  int i;
00161  RECT rc;
00162  POINT pt;
00163  switch (iMessage) {
00164    case WM_DESTROY:
00165     break;
00166   case WM_COMMAND:
00167     return MenuCommand(hWnd,LOWORD(wParam));
00168     break;
00169   case WM_RBUTTONUP:
00170     if(!bToolCaptured)break;
00171     if(tracetool == 1){
00172       DrawRubberLine(hWnd,LOWORD(lParam),HIWORD(lParam));
00173       SetCursor(hCursorSave);
00174       ClipCursor(NULL);
00175       ReleaseCapture();
00176       bToolCaptured=FALSE;
00177       Lv= -1;
00178     }
00179     break;
00180   case WM_LBUTTONDOWN:
00181     if(bToolCaptured)break;
00182     if(tracetool == 1){
00183       bToolCaptured=TRUE;
00184       SetCapture(hWnd);
00185       hCursorSave=SetCursor(hcurPen1);
00186       GetClientRect(hWnd,&rc);
00187       pt.x=rc.left; pt.y=rc.top;
00188       ClientToScreen(hWnd,&pt);
00189       rc.left=pt.x; rc.top=pt.y;
00190       pt.x=rc.right; pt.y=rc.bottom;
00191       ClientToScreen(hWnd,&pt);
00192       rc.right=pt.x; rc.bottom=pt.y;
00193       ClipCursor(&rc);
00194     }
00195     else if(tracetool == 2){
00196       bToolCaptured=TRUE;
00197       SetCapture(hWnd);
00198       LastPt.x=LOWORD(lParam); LastPt.y=HIWORD(lParam);
00199       SetupStart();
00200       Lv=GetVertexAtCursor(LOWORD(lParam),HIWORD(lParam));
00201     }
00202     break;
00203   case WM_MOUSEMOVE:
00204     if(!bToolCaptured)break;
00205     if(tracetool == 1){
00206       DrawRubberLine(hWnd,(int)LastPt.x,(int)LastPt.y);
00207       LastPt.x=LOWORD(lParam); LastPt.y=HIWORD(lParam);
00208       DrawRubberLine(hWnd,(int)LastPt.x,(int)LastPt.y);
00209     }
00210     if(tracetool == 2){
00211       IterateTowardsGoal(hWnd,(int)LOWORD(lParam)-(int)LastPt.x,
00212                         (int)HIWORD(lParam)-(int)LastPt.y);
00213       LastPt.x=LOWORD(lParam); LastPt.y=HIWORD(lParam);
00214     }
00215     break;
00216   case WM_LBUTTONUP:
00217     if(!bToolCaptured)break;
00218     if(tracetool == 1){ /* add */
00219       LastPt.x=LOWORD(lParam); LastPt.y=HIWORD(lParam);
00220       if(Lv >= 0)DrawRubberLine(hWnd,(int)LastPt.x,(int)LastPt.y);
00221       AddTraceVertex((int)LOWORD(lParam),(int)HIWORD(lParam));
00222       DrawList(hWnd,NULL);
00223       DrawRubberLine(hWnd,(int)LastPt.x,(int)LastPt.y);
00224     }
00225     else if(tracetool == 2){ /* move */
00226       ReleaseCapture();
00227       bToolCaptured=FALSE;
00228     }
00229     break;
00230   case WM_PAINT:
00231     hDC = BeginPaint(hWnd, &ps);
00232     GetClientRect(hWnd,&rc);
00233     PatBlt(hDC,0,0,rc.right,rc.bottom,PATCOPY);
00234     DrawList(hWnd,hDC);
00235     EndPaint(hWnd,&ps);
00236     break ;
00237   case WM_SIZE:
00238     InvalidateRect(hWnd,NULL,FALSE);
00239     return 0;
00240   default:
00241       return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
00242  }
00243  return 0L ;
00244 }
00245 
00246 BOOL MenuCommand(HWND hWnd, WORD id){
00247  int i;
00248  switch (id) {
00249    case IDM_PEN_RED  : pen=0; goto PENID;
00250    case IDM_PEN_WHITE: pen=1; goto PENID;
00251    case IDM_PEN_BLACK: pen=2; goto PENID;
00252    case IDM_PEN_CYAN : pen=3; goto PENID;
00253      PENID:
00254      CheckMenuItem(GetMenu(hWnd),IDM_PEN_RED,MF_UNCHECKED);
00255      CheckMenuItem(GetMenu(hWnd),IDM_PEN_WHITE,MF_UNCHECKED);
00256      CheckMenuItem(GetMenu(hWnd),IDM_PEN_BLACK,MF_UNCHECKED);
00257      CheckMenuItem(GetMenu(hWnd),IDM_PEN_CYAN,MF_UNCHECKED);
00258      if(pen == 0)CheckMenuItem(GetMenu(hWnd),IDM_PEN_RED,MF_CHECKED);
00259      if(pen == 1)CheckMenuItem(GetMenu(hWnd),IDM_PEN_WHITE,MF_CHECKED);
00260      if(pen == 2)CheckMenuItem(GetMenu(hWnd),IDM_PEN_BLACK,MF_CHECKED);
00261      if(pen == 3)CheckMenuItem(GetMenu(hWnd),IDM_PEN_CYAN,MF_CHECKED);
00262      DrawList(hWnd,NULL);
00263      break;
00264    case IDM_ADD:
00265      Lv= -1;
00266      EnableMenuItem(GetMenu(hWnd),IDM_ADD,MF_GRAYED);
00267      EnableMenuItem(GetMenu(hWnd),IDM_MOVE,MF_ENABLED);
00268      DrawMenuBar(hWnd);
00269      tracetool=1;
00270      break;
00271    case IDM_MOVE:
00272      Lv= -1;
00273      EnableMenuItem(GetMenu(hWnd),IDM_ADD,MF_ENABLED);
00274      EnableMenuItem(GetMenu(hWnd),IDM_MOVE,MF_GRAYED);
00275      DrawMenuBar(hWnd);
00276      tracetool=2;
00277      break;
00278    case IDM_EXIT:
00279      PostQuitMessage(0);
00280      break;
00281    default:
00282      break;
00283  }
00284  return TRUE;
00285 }
00286 
00287 static void DrawRubberLine(HWND hwnd, int x, int y){
00288  HPEN hOldPen,MyPen;
00289  int oldROP;
00290  HDC hDClocal;
00291  if(Lv < 0)return;
00292  hDClocal=GetDC(hwnd);
00293  if(pen == 0)MyPen=CreatePen(PS_SOLID,0,RGB(255,0,0));
00294  if(pen == 1)MyPen=CreatePen(PS_SOLID,0,RGB(0,0,255));
00295  if(pen == 2)MyPen=CreatePen(PS_SOLID,0,RGB(0,0,0));
00296  if(pen == 3)MyPen=CreatePen(PS_SOLID,0,RGB(0,255,0));
00297  hOldPen=SelectObject(hDClocal,MyPen);
00298  oldROP=SetROP2(hDClocal,R2_NOT);
00299  MoveToEx(hDClocal,x,y,NULL);
00300  LineTo(hDClocal,TVlist[Lv].x,TVlist[Lv].y);
00301  SetROP2(hDClocal,oldROP);
00302  SelectObject(hDClocal,hOldPen);
00303  DeleteObject(MyPen);
00304  ReleaseDC(hwnd,hDClocal);
00305 }
00306 
00307 static void DrawList(HWND hwnd, HDC hDC){
00308  int i,x,y;
00309  HPEN hOldPen,MyPen;
00310  HBRUSH hOldBrush;
00311  HDC hDClocal;
00312  if(hDC == NULL){
00313    hDClocal=GetDC(hwnd);
00314  }
00315  else hDClocal=hDC;
00316  if(pen == 0)MyPen=CreatePen(PS_SOLID,0,RGB(255,0,0));
00317  if(pen == 1)MyPen=CreatePen(PS_SOLID,0,RGB(0,0,255));
00318  if(pen == 2)MyPen=CreatePen(PS_SOLID,0,RGB(0,0,0));
00319  if(pen == 3)MyPen=CreatePen(PS_SOLID,0,RGB(0,255,0));
00320  hOldPen=SelectObject(hDClocal,MyPen);
00321  hOldBrush=SelectObject(hDClocal,GetStockObject(BLACK_BRUSH));
00322  if(Ne > 0 && TElist != NULL){
00323    for(i=0;i<Ne;i++){
00324      if(!TElist[i].inc)continue;
00325      x=TVlist[TElist[i].v1].x; y=TVlist[TElist[i].v1].y;
00326      MoveToEx(hDClocal,x,y,NULL);
00327      x=TVlist[TElist[i].v2].x; y=TVlist[TElist[i].v2].y;
00328      LineTo(hDClocal,x,y);
00329    }
00330  }
00331  if(Nv > 0 && TVlist != NULL){
00332    for(i=0;i<Nv;i++)if(TVlist[i].inc){
00333      x=TVlist[i].x; y=TVlist[i].y;
00334      MoveToEx(hDClocal,x,y,NULL);
00335      LineTo(hDClocal,x+(int)(TVlist[i].ax[0]*40),y+(int)(TVlist[i].ax[1]*40));
00336      MoveToEx(hDClocal,x,y,NULL);
00337      LineTo(hDClocal,x+(int)(TVlist[i].ay[0]*30),y+(int)(TVlist[i].ay[1]*30));
00338      Rectangle(hDClocal,
00339                TVlist[i].x-2,TVlist[i].y-2,
00340                TVlist[i].x+2,TVlist[i].y+2);
00341    }
00342  }
00343  SelectObject(hDClocal,hOldPen);
00344  SelectObject(hDClocal,hOldBrush);
00345  DeleteObject(MyPen);
00346  if(hDC == NULL){
00347    ReleaseDC(hwnd,hDClocal);
00348  }
00349 }
00350 
00351 static void AddTraceVertex(int x,int y){
00352  int i,id,found=0,flag=0;
00353  vector x0={1.0,0.0,0.0},y0={0.0,1.0,0.0},z0={0.0,0.0,1.0};
00354  struct TVLIST *v;
00355  struct TELIST *e;
00356  if(Nv > 0){
00357    for(i=0;i<Nv;i++){
00358      if(TVlist[i].inc && abs(x-TVlist[i].x) < 4 && abs(y-TVlist[i].y) < 4){
00359        found=1;
00360        if(Lv >= 0)flag=1;
00361        id=i;
00362      }
00363    }
00364  }
00365  if(!found){
00366    if(TVlist == NULL){
00367      if((v=(struct TVLIST *)X__Malloc(sizeof(struct TVLIST))) == NULL)return;
00368    }
00369    else{
00370      if((v=(struct TVLIST *)X__Realloc(TVlist,(Nv+1)*sizeof(struct TVLIST))) == NULL)return;
00371    }
00372    TVlist=v;
00373    v[Nv].x=x; v[Nv].y=y; v[Nv].z=0; v[Nv].inc=TRUE;
00374    v[Nv].p[0]=(double)x;
00375    v[Nv].p[1]=(double)y;
00376    v[Nv].p[2]=0.0;
00377    VECCOPY(x0,v[Nv].ax)
00378    VECCOPY(y0,v[Nv].ay)
00379    VECCOPY(z0,v[Nv].az)
00380    id=Nv;
00381    Nv++;
00382  }
00383  if(Lv < 0){
00384    Lv=id;
00385  }
00386  else{
00387    if(TElist == NULL){
00388      if((e=(struct TELIST *)X__Malloc(sizeof(struct TELIST))) == NULL)return;
00389    }
00390    else{
00391      if((e=(struct TELIST *)X__Realloc(TElist,(Ne+1)*sizeof(struct TELIST))) == NULL)return;
00392    }
00393    TElist=e;
00394    e[Ne].v1=id; e[Ne].v2=Lv; e[Ne].inc=TRUE;
00395    Lv=id;
00396    Ne++;
00397  }
00398  if(flag)Lv= -1;
00399 }
00400 
00401 static int GetVertexAtCursor(int x, int y){
00402  int i,id=Nv-1;
00403  if(Nv > 0)for(i=0;i<Nv;i++){
00404    if(TVlist[i].inc && abs(x-TVlist[i].x) < 4 && abs(y-TVlist[i].y) < 4)id=i;
00405  }
00406  return id;
00407 }
00408 
00409 static void IterateTowardsGoal(HWND hWnd,int xi, int yi){
00410  double *J,*Jt,*dTheta,*I,*dI,*Ji;
00411  double l,dl,x[3],dx[3],dx_sum[3];
00412  double;
00413  long Nv1,i,j,k,n=0;
00414  if(Lv < 0)return;
00415  Nv1=Nv-1;
00416  Nv1=Lv; 
00417 // dx_sum[0]=dx_sum[1]=dx_sum[2]=0.0;
00418 // x[0]=dx[0]=(double)xi;
00419 // x[1]=dx[1]=(double)yi;
00420 // x[2]=dx[2]=(double)0.0;
00421  x[0]=TVlist[Nv1].p[0]+(double)xi;  //
00422  x[1]=TVlist[Nv1].p[1]+(double)yi;  //
00423  x[2]=TVlist[Nv1].p[2]+(double)0.0; //
00424  VECSUB(x,TVlist[Nv1].p,dx) //
00425  if((dTheta=(double *)malloc((3*Nv1)*sizeof(double))) == NULL)return;
00426  if((J=(double *)malloc(3*(3*Nv1)*sizeof(double))) == NULL)return;
00427  if((Jt=(double *)malloc((3*Nv1)*3*sizeof(double))) == NULL)return;
00428  if((Ji=(double *)malloc((3*Nv1)*3*sizeof(double))) == NULL)return;
00429  if((dI=(double *)malloc(3*3*sizeof(double))) == NULL)return;
00430  if((I=(double *)malloc(3*3*sizeof(double))) == NULL)return;
00431 
00432  sprintf(filename,"f:\\ik3d%ld.dat",version); version++;
00433  //debug=fopen(filename,"w");
00434  while(1){
00435    VECSUB(x,TVlist[Nv1].p,dx) //
00436    if(++n > 200){MessageBox(NULL,"Out of iteration",NULL,MB_OK); break;}
00437    if(debug != NULL)fprintf(debug,"Iteration %ld\n",n);
00438    CalculateJacobian(J,Nv1);
00439    CalculateTranspose(J,Jt,3,3*Nv1);
00440    MultiplyMatrix(J,3,3*Nv1,Jt,3*Nv1,3,I);
00441    if(InvertMatrix(I,3,dI)){
00442      // calculate the generalised inverse of the jacobian J (i.e. Ji)
00443      MultiplyMatrix(Jt,3*Nv1,3,dI,3,3,Ji);
00444      // StepOK returns a reduced dx so that the product [J][Ji] is
00445      // close to the identity matrix [I] and therefore can be used to
00446      // determine incremental angular rotations.
00447      if(!StepOK(J,Ji,dx,3,3*Nv1,1.e-2,1.e-6)){
00448        MessageBox(NULL,"Dx too small",NULL,MB_OK);
00449        break;    // can't reach desired point
00450      }
00451      else{
00452        // calculate the incremental rotations
00453        MultiplyMatrix(Ji,3*Nv1,3,dx,3,1,dTheta);
00454        // determine the new position of the linkage
00455        UpdateTheLinkage(Nv1,dTheta);
00456 //       dx_sum[0] += dx[0];  // how close to the goal the selected
00457 //       dx_sum[1] += dx[1];  // end point of the linkage has got
00458 //       dx_sum[2] += dx[2];
00459 //       if(Dist(dx_sum,x,3) < 1.0){
00460        if(Dist(TVlist[Nv1].p,x,3) < 3.0){ //
00461          break;   // converged to solution
00462        }
00463      }
00464    }
00465    else{
00466      MessageBeep(MB_OK);
00467    }
00468  }
00469 
00470  if(debug != NULL)fclose(debug);
00471  free(dTheta);
00472  free(Ji);
00473  free(I);
00474  free(dI);
00475  free(Jt);
00476  free(J);
00477  InvalidateRect(hWnd,NULL,FALSE);
00478  return;
00479 }
00480 
00481 static void CalculateJacobian(double *J, // dimension 3 by n
00482                               long n     // number of entries
00483                                          // i.e. 1 less than points
00484                              ){
00485  long k,l;
00486  vector ax,ay,az,dp,Jx,Jy,Jz;
00487  for(l=0,k=0;k<n;k++){
00488    VECCOPY(TVlist[k].ax,ax)
00489    VECCOPY(TVlist[k].ay,ay)
00490    VECCOPY(TVlist[k].az,az)
00491    VECSUB(TVlist[n].p,TVlist[k].p,dp)
00492    CROSS(ax,dp,Jx)
00493    CROSS(ay,dp,Jy)
00494    CROSS(az,dp,Jz)
00495    J[l]       = Jx[0];
00496    J[l+n*3]   = Jx[1];
00497    J[l+n*3*2] = Jx[2];
00498    l++;
00499    J[l]       = Jy[0];
00500    J[l+n*3]   = Jy[1];
00501    J[l+n*3*2] = Jy[2];
00502    l++;
00503    J[l]       = Jz[0];
00504    J[l+n*3]   = Jz[1];
00505    J[l+n*3*2] = Jz[2];
00506    l++;
00507  }
00508  return;
00509 }
00510 
00511 static void SetupStart(void){
00512  int i;
00513  vector x0={1.0,0.0,0.0},y0={0.0,1.0,0.0},z0={0.0,0.0,1.0};
00514  if(Nv < 2)return;
00515  for(i=0;i<Nv;i++){
00516    TVlist[i].p[0]=(double)TVlist[i].x;
00517    TVlist[i].p[1]=(double)TVlist[i].y;
00518    TVlist[i].p[2]=0.0;
00519    VECCOPY(x0,TVlist[i].ax)
00520    VECCOPY(y0,TVlist[i].ay)
00521    VECCOPY(z0,TVlist[i].az)
00522  }
00523 }
00524 
00525 static void UpdateTheLinkage(long Nv1, double *dTheta){
00526  long i,j,l;
00527  double thetaX,thetaY,thetaZ;
00528  vector ax,ay,az,baseZero={0.0,0.0,0.0};
00529  for(i=0,l=0;i<Nv1;i++,l+=3){
00530    // extract the incremental rotations and axis vectors around which
00531    // they are to be applied.
00532    thetaX = *(dTheta+l);
00533    thetaY = *(dTheta+l+1);
00534    thetaZ = *(dTheta+l+2);
00535    VECCOPY(TVlist[i].ax,ax)
00536    VECCOPY(TVlist[i].ay,ay)
00537    VECCOPY(TVlist[i].az,az)
00538    // apply the rotation to all the vertex locations and base vectors
00539    // further down the linkage (including the end point)
00540    for(j=i+1;j<=Nv1;j++){
00541      RotateVectorRound(TVlist[j].p,TVlist[i].p,ax,thetaX);
00542      RotateVectorRound(TVlist[j].p,TVlist[i].p,ay,thetaY);
00543      RotateVectorRound(TVlist[j].p,TVlist[i].p,az,thetaZ);
00544      RotateVectorRound(TVlist[j].ax,baseZero,ax,thetaX);
00545      RotateVectorRound(TVlist[j].ax,baseZero,ay,thetaY);
00546      RotateVectorRound(TVlist[j].ax,baseZero,az,thetaZ);
00547 //if(debug != NULL)fprintf(debug,"i=%ld j=%ld ax=(%lf,%lf,%lf)\n",i,j,
00548 //TVlist[j].ax[0],TVlist[j].ax[1],TVlist[j].ax[2]);
00549      RotateVectorRound(TVlist[j].ay,baseZero,ax,thetaX);
00550      RotateVectorRound(TVlist[j].ay,baseZero,ay,thetaY);
00551      RotateVectorRound(TVlist[j].ay,baseZero,az,thetaZ);
00552      RotateVectorRound(TVlist[j].az,baseZero,ax,thetaX);
00553      RotateVectorRound(TVlist[j].az,baseZero,ay,thetaY);
00554      RotateVectorRound(TVlist[j].az,baseZero,az,thetaZ);
00555      TVlist[j].x=(int)TVlist[j].p[0];
00556      TVlist[j].y=(int)TVlist[j].p[1];
00557      TVlist[j].z=(int)TVlist[j].p[2]; // should be 0 for pseudo 2D
00558    }
00559  }
00560  return;
00561 }
00562 
00563 static BOOL StepOK(double *J, double *Ji, double *dx,
00564                    long n, long m,
00565                    double e, double dmin){
00566  BOOL result=TRUE;
00567  long i;
00568  double *I,*N,norm=0.0;
00569  if((I=(double *)malloc(n*n*sizeof(double))) == NULL)return FALSE;
00570  if((N=(double *)malloc(n*sizeof(double))) == NULL)return FALSE;
00571  MultiplyMatrix(J,n,m,Ji,m,n,I);
00572  for(i=0;i<n;i++){
00573    I[i*n+i] -= 1.0;
00574  }
00575  while(1){
00576    MultiplyMatrix(I,n,n,dx,n,1,N);
00577    norm=0.0;
00578    for(i=0;i<n;i++){
00579      norm += N[i] * N[i];
00580    }
00581    if(norm < e)break;
00582    for(i=0;i<n;i++)dx[i] *= 0.5;
00583    if(Length(dx,n) < dmin){
00584       result=FALSE;
00585       break;
00586    }
00587  }
00588  free(N);
00589  free(I);
00590  return result;
00591 }
00592 
00593 static void RotateVectorRound(vector v,
00594                               vector BaseOfRotation,
00595                               vector AxisOfRotation,
00596                               double theta){
00597  // modify the input vector to apply the rotational transformation
00598  double t[4][4];
00599  vector lv,lvv;
00600  VECSUB(v,BaseOfRotation,lv) // remove
00601  rotate_round_vector(theta,AxisOfRotation,t);  // get rotational transform
00602  mv4by1(t,lv,lvv);  // apply it
00603  VECSUM(lvv,BaseOfRotation,v)
00604  return;
00605 }
00606 
00607 static BOOL normalize(vector v){
00608  double n,nn;
00609  n= (double)((v[0]*v[0]) + (v[1]*v[1]) + (v[2]*v[2]));
00610  if(n < 1.e-10)return FALSE;
00611  nn=sqrt(n);
00612  n = 1.0 / nn;
00613  VECSCALE(n,v,v)
00614  return TRUE;
00615 }
00616 
00617 
00618 static void rotz(double tr[4][4], double ang){
00619  short i,j;
00620  for(i=0;i<4;i++)
00621  for(j=0;j<4;j++){
00622   tr[i][j]=0.0;
00623   if(i == j)tr[i][j]=1.0;
00624  }
00625   tr[0][0]= cos(ang);
00626   tr[0][1]=-sin(ang);
00627   tr[1][0]= sin(ang);
00628   tr[1][1]= cos(ang);
00629   return;
00630 }
00631 
00632 static void roty(double tr[4][4], double ang){
00633  short i,j;
00634  for(i=0;i<4;i++)
00635  for(j=0;j<4;j++){
00636   tr[i][j]=0.0;
00637   if(i == j)tr[i][j]=1.0;
00638  }
00639   tr[0][0]= cos(ang);
00640   tr[0][2]=-sin(ang);
00641   tr[2][0]= sin(ang);
00642   tr[2][2]= cos(ang);
00643   return;
00644 }
00645 
00646 static void rotx(double tr[4][4], double ang){
00647  long i,j;
00648  for(i=0;i<4;i++)
00649  for(j=0;j<4;j++){
00650   tr[i][j]=0.0;
00651   if(i == j)tr[i][j]=1.0;
00652  }
00653   tr[1][1]= cos(ang);
00654   tr[1][2]=-sin(ang);
00655   tr[2][1]= sin(ang);
00656   tr[2][2]= cos(ang);
00657   return;
00658 }
00659 
00660 static void mv4by1(double t4[4][4], vector v1, vector v2){
00661  double xx,yy,zz;
00662  xx=t4[0][0]*v1[0]+t4[0][1]*v1[1]+t4[0][2]*v1[2]+t4[0][3];
00663  yy=t4[1][0]*v1[0]+t4[1][1]*v1[1]+t4[1][2]*v1[2]+t4[1][3];
00664  zz=t4[2][0]*v1[0]+t4[2][1]*v1[1]+t4[2][2]*v1[2]+t4[2][3];
00665  v2[0]=xx; v2[1]=yy; v2[2]=zz;
00666  return;
00667 }
00668 
00669 static void m4by4(double t1[4][4], double t2[4][4], double tr[4][4]){
00670  short n=4,i,j,k;
00671  for(i=0;i<4;i++)
00672  for(j=0;j<4;j++){
00673   tr[i][j]=0.0;
00674   for(k=0;k<4;k++)tr[i][j]=tr[i][j]+t1[i][k]*t2[k][j];
00675  }
00676  return;
00677 }
00678 
00679 static void rotate_round_vector(double angle, vector v, double t[4][4]){
00680   double dx,dy,dz,phi,theta,dxy;
00681   double t1[4][4],t2[4][4],t3[4][4];
00682   dx=v[0]; dy=v[1]; dz=v[2];
00683   dxy=dx*dx+dy*dy;
00684   if(dxy < 0.00001){ /* vertical so just rotate about z  and return */
00685     if(dz > 0.0)rotz(t, angle);
00686     else        rotz(t,-angle);
00687     return;
00688   }
00689   dxy=sqrt(dxy);
00690   if     (dx == 0.0 && dy > 0.0)phi =  PI2;
00691   else if(dx == 0.0 && dy < 0.0)phi = -PI2;
00692   else phi = atan2(dy,dx);
00693   theta = atan2(dz,dxy);
00694   rotz(t3, -phi);
00695   roty(t2, -theta);
00696   m4by4(t2,t3,t1);
00697   rotx(t2, angle);
00698   m4by4(t2,t1,t3);
00699   roty(t2,theta);
00700   m4by4(t2,t3,t1);
00701   rotz(t2,phi);
00702   m4by4(t2,t1,t);
00703 }
00704 
00705 static double Length(double *dx, long n){
00706  long i;
00707  double l=0.0;
00708  for(i=0;i<n;i++)l += dx[i]*dx[i];
00709  return sqrt(l);
00710 }
00711 
00712 static double Dist(double *x, double *y, long n){
00713  long i;
00714  double d=0.0;
00715  for(i=0;i<n;i++)d += (x[i]-y[i])*(x[i]-y[i]);
00716  return sqrt(d);
00717 }
00718 
00719 static void CalculateTranspose(double *M, double *Mt, long n, long m){
00720  long i,j;                       // M  is "n" rows "m" columns  [n x m]
00721  for(i=0;i<n;i++){
00722    for(j=0;j<m;j++){
00723      *(Mt+j*n+i) = *(M+i*m+j);   // Mt[j*n+i] = M[i*m+j];
00724    }
00725  }
00726  return;
00727 }
00728 
00729 static void MultiplyMatrix(double *M1, long n1, long m1,
00730                            double *M2, long n2, long m2,
00731                            double *I){
00732  long   i,j,k,c;           // [n1 x m2][n2 x m2] result is [n1 x m2]
00733  double s;
00734  if(m1 != n2){MessageBox(NULL,"Bad Multiply",NULL,MB_OK); return;}
00735  c=n2;
00736  for(i=0;i<n1;i++){
00737    for(j=0;j<m2;j++){
00738      for(s=0.0,k=0;k<c;k++){
00739        s += (*(M1+i*m1+k)) * (*(M2+k*m2+j));
00740        //  s += M1[i*m1+k]*M2[k*m2+j];  //  M1[i][k] * M2[k][j]
00741      }
00742      *(I+i*m2+j) = s;                   //  I[i*m2+j]=s;   // I[i][j]
00743    }
00744  }
00745  return;
00746 }
00747 
00748 static BOOL InvertMatrix(double *A, long n, double *B){
00749  int i,j,k,imax,kp1;
00750  double del,amax,atmp,btmp,div,amult,eps=1.e-6;
00751  for(i=0;i<n;i++)for(j=0;j<n;j++){
00752    if(i == j)B[i*n+j]=1.0;
00753    else      B[i*n+j]=0.0;
00754  }
00755  del=1.0;
00756  for(k=0;k<n;k++){
00757    if(k < n-1){
00758      imax=k;
00759      amax=fabs(A[k*n+k]);
00760      kp1=k+1;
00761      for(i=kp1;i<n;i++){
00762        if(amax-fabs(A[i*n+k]) < 0.0){
00763          imax=i;
00764          amax=fabs(A[i*n+k]);
00765        }
00766      }
00767      if(imax != k){
00768        for(j=0;j<n;j++){
00769          atmp=A[imax*n+j];
00770          A[imax*n+j]=A[k*n+j];
00771          A[k*n+j]=atmp;
00772          btmp=B[imax*n+j];
00773          B[imax*n+j]=B[k*n+j];
00774          B[k*n+j]=btmp;
00775        }
00776        del = -del;
00777      }
00778    }
00779    if(fabs(A[k*n+k]) < eps)return FALSE;
00780    del=A[k*n+k]*del;
00781    div=1.0/A[k*n+k];
00782    for(j=0;j<n;j++){
00783      A[k*n+j]=A[k*n+j]*div;
00784      B[k*n+j]=B[k*n+j]*div;
00785    }
00786    for(i=0;i<n;i++){
00787      amult=A[i*n+k];
00788      if(i != k){
00789        for(j=0;j<n;j++){
00790          A[i*n+j]=A[i*n+j]-amult*A[k*n+j];
00791          B[i*n+j]=B[i*n+j]-amult*B[k*n+j];
00792        }
00793      }
00794    }
00795  }
00796  return TRUE;
00797 }
00798 
00799 #if __WATCOMC__
00800 int APIENTRY LibMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00801 #else
00802 BOOL WINAPI DllMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00803 #endif
00804   switch (dwReason) {
00805     case DLL_PROCESS_ATTACH: {
00806       hThisInstance=hDLL;
00807       break;
00808     }
00809     case DLL_PROCESS_DETACH:
00810       break;
00811   }
00812   return TRUE;
00813 }
00814 
00815 BOOL _Xmodeler
00816  (HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){
00817  lpEVI=lpevi;
00818  tracetool=0;
00819  hParent=parent_window;
00820  return Tester();
00821 }

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