pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* 00002 * (c) Copyright 1993, 1994, Silicon Graphics, Inc. 00003 * ALL RIGHTS RESERVED 00004 * Permission to use, copy, modify, and distribute this software for 00005 * any purpose and without fee is hereby granted, provided that the above 00006 * copyright notice appear in all copies and that both the copyright notice 00007 * and this permission notice appear in supporting documentation, and that 00008 * the name of Silicon Graphics, Inc. not be used in advertising 00009 * or publicity pertaining to distribution of the software without specific, 00010 * written prior permission. 00011 * 00012 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" 00013 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, 00014 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR 00015 * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 00016 * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, 00017 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY 00018 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, 00019 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF 00020 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN 00021 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON 00022 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN PAD_CONNECTION WITH THE 00023 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. 00024 * 00025 * US Government Users Restricted Rights 00026 * Use, duplication, or disclosure by the Government is subject to 00027 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph 00028 * (c)(1)(ii) of the Rights in Technical Data and Computer Software 00029 * clause at DFARS 252.227-7013 and/or in similar or successor 00030 * clauses in the FAR or the DOD or NASA FAR Supplement. 00031 * Unpublished-- rights reserved under the copyright laws of the 00032 * United States. Contractor/manufacturer is Silicon Graphics, 00033 * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. 00034 * 00035 * OpenGL(TM) is a trademark of Silicon Graphics, Inc. 00036 */ 00037 /* 00038 * Trackball code: 00039 * 00040 * Implementation of a virtual trackball. 00041 * Implemented by Gavin Bell, lots of ideas from Thant Tessman and 00042 * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. 00043 * 00044 * Vector manip code: 00045 * 00046 * Original code from: 00047 * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli 00048 * 00049 * Much mucking with by: 00050 * Gavin Bell 00051 */ 00052 #include <math.h> 00053 #include "trackball.h" 00054 00055 /* 00056 * This size should really be based on the distance from the center of 00057 * rotation to the point on the object underneath the mouse. That 00058 * point would then track the mouse as closely as possible. This is a 00059 * simple example, though, so that is left as an Exercise for the 00060 * Programmer. 00061 */ 00062 #define TRACKBALLSIZE (0.8f) 00063 00064 /* 00065 * Local function prototypes (not defined in trackball.h) 00066 */ 00067 static float tb_project_to_sphere(float, float, float); 00068 static void normalize_quat(float [4]); 00069 00070 void 00071 vzero(float *v) 00072 { 00073 v[0] = 0.0; 00074 v[1] = 0.0; 00075 v[2] = 0.0; 00076 } 00077 00078 void 00079 vset(float *v, float x, float y, float z) 00080 { 00081 v[0] = x; 00082 v[1] = y; 00083 v[2] = z; 00084 } 00085 00086 void 00087 vsub(const float *src1, const float *src2, float *dst) 00088 { 00089 dst[0] = src1[0] - src2[0]; 00090 dst[1] = src1[1] - src2[1]; 00091 dst[2] = src1[2] - src2[2]; 00092 } 00093 00094 void 00095 vcopy(const float *v1, float *v2) 00096 { 00097 register int i; 00098 for (i = 0 ; i < 3 ; i++) 00099 v2[i] = v1[i]; 00100 } 00101 00102 void 00103 vcross(const float *v1, const float *v2, float *cross) 00104 { 00105 float temp[3]; 00106 00107 temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); 00108 temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); 00109 temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); 00110 vcopy(temp, cross); 00111 } 00112 00113 float 00114 vlength(const float *v) 00115 { 00116 return (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 00117 } 00118 00119 void 00120 vscale(float *v, float div) 00121 { 00122 v[0] *= div; 00123 v[1] *= div; 00124 v[2] *= div; 00125 } 00126 00127 void 00128 vnormal(float *v) 00129 { 00130 vscale(v, 1.0f/vlength(v)); 00131 } 00132 00133 float 00134 vdot(const float *v1, const float *v2) 00135 { 00136 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; 00137 } 00138 00139 void 00140 vadd(const float *src1, const float *src2, float *dst) 00141 { 00142 dst[0] = src1[0] + src2[0]; 00143 dst[1] = src1[1] + src2[1]; 00144 dst[2] = src1[2] + src2[2]; 00145 } 00146 00147 /* 00148 * Ok, simulate a track-ball. Project the points onto the virtual 00149 * trackball, then figure out the axis of rotation, which is the cross 00150 * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) 00151 * Note: This is a deformed trackball-- is a trackball in the center, 00152 * but is deformed into a hyperbolic sheet of rotation away from the 00153 * center. This particular function was chosen after trying out 00154 * several variations. 00155 * 00156 * It is assumed that the arguments to this routine are in the range 00157 * (-1.0 ... 1.0) 00158 */ 00159 void 00160 trackball(float q[4], float p1x, float p1y, float p2x, float p2y) 00161 { 00162 float a[3]; /* Axis of rotation */ 00163 float phi; /* how much to rotate about axis */ 00164 float p1[3], p2[3], d[3]; 00165 float t; 00166 00167 if (p1x == p2x && p1y == p2y) { 00168 /* Zero rotation */ 00169 vzero(q); 00170 q[3] = 1.0; 00171 return; 00172 } 00173 00174 /* 00175 * First, figure out z-coordinates for projection of P1 and P2 to 00176 * deformed sphere 00177 */ 00178 vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y)); 00179 vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y)); 00180 00181 /* 00182 * Now, we want the cross product of P1 and P2 00183 */ 00184 vcross(p2,p1,a); 00185 00186 /* 00187 * Figure out how much to rotate around that axis. 00188 */ 00189 vsub(p1, p2, d); 00190 t = vlength(d) / (2.0f*TRACKBALLSIZE); 00191 00192 /* 00193 * Avoid problems with out-of-control values... 00194 */ 00195 if (t > 1.0) t = 1.0; 00196 if (t < -1.0) t = -1.0; 00197 phi = 2.0f * (float) asin(t); 00198 00199 axis_to_quat(a,phi,q); 00200 } 00201 00202 /* 00203 * Given an axis and angle, compute quaternion. 00204 */ 00205 void 00206 axis_to_quat(float a[3], float phi, float q[4]) 00207 { 00208 vnormal(a); 00209 vcopy(a, q); 00210 vscale(q, (float) sin(phi/2.0)); 00211 q[3] = (float) cos(phi/2.0); 00212 } 00213 00214 /* 00215 * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet 00216 * if we are away from the center of the sphere. 00217 */ 00218 static float 00219 tb_project_to_sphere(float r, float x, float y) 00220 { 00221 float d, t, z; 00222 00223 d = hypotf(x, y); 00224 if (d < r * 0.70710678118654752440) { /* Inside sphere */ 00225 z = (float) sqrt(r*r - d*d); 00226 } else { /* On hyperbola */ 00227 t = r / 1.41421356237309504880f; 00228 z = t*t / d; 00229 } 00230 return z; 00231 } 00232 00233 /* 00234 * Given two rotations, e1 and e2, expressed as quaternion rotations, 00235 * figure out the equivalent single rotation and stuff it into dest. 00236 * 00237 * This routine also normalizes the result every RENORMCOUNT times it is 00238 * called, to keep error from creeping in. 00239 * 00240 * NOTE: This routine is written so that q1 or q2 may be the same 00241 * as dest (or each other). 00242 */ 00243 00244 #define RENORMCOUNT 97 00245 00246 void 00247 add_quats(float q1[4], float q2[4], float dest[4]) 00248 { 00249 static int count=0; 00250 float t1[4], t2[4], t3[4]; 00251 float tf[4]; 00252 00253 vcopy(q1,t1); 00254 vscale(t1,q2[3]); 00255 00256 vcopy(q2,t2); 00257 vscale(t2,q1[3]); 00258 00259 vcross(q2,q1,t3); 00260 vadd(t1,t2,tf); 00261 vadd(t3,tf,tf); 00262 tf[3] = q1[3] * q2[3] - vdot(q1,q2); 00263 00264 dest[0] = tf[0]; 00265 dest[1] = tf[1]; 00266 dest[2] = tf[2]; 00267 dest[3] = tf[3]; 00268 00269 if (++count > RENORMCOUNT) { 00270 count = 0; 00271 normalize_quat(dest); 00272 } 00273 } 00274 00275 /* 00276 * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 00277 * If they don't add up to 1.0, dividing by their magnitued will 00278 * renormalize them. 00279 * 00280 * Note: See the following for more information on quaternions: 00281 * 00282 * - Shoemake, K., Animating rotation with quaternion curves, Computer 00283 * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. 00284 * - Pletinckx, D., Quaternion calculus as a basic tool in computer 00285 * graphics, The Visual Computer 5, 2-13, 1989. 00286 */ 00287 static void 00288 normalize_quat(float q[4]) 00289 { 00290 int i; 00291 float mag; 00292 00293 mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); 00294 for (i = 0; i < 4; i++) q[i] /= mag; 00295 } 00296 00297 /* 00298 * Build a rotation matrix, given a quaternion rotation. 00299 * 00300 */ 00301 void 00302 build_rotmatrix(float m[4][4], float q[4]) 00303 { 00304 m[0][0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]); 00305 m[0][1] = 2.0f * (q[0] * q[1] - q[2] * q[3]); 00306 m[0][2] = 2.0f * (q[2] * q[0] + q[1] * q[3]); 00307 m[0][3] = 0.0f; 00308 00309 m[1][0] = 2.0f * (q[0] * q[1] + q[2] * q[3]); 00310 m[1][1]= 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]); 00311 m[1][2] = 2.0f * (q[1] * q[2] - q[0] * q[3]); 00312 m[1][3] = 0.0f; 00313 00314 m[2][0] = 2.0f * (q[2] * q[0] - q[1] * q[3]); 00315 m[2][1] = 2.0f * (q[1] * q[2] + q[0] * q[3]); 00316 m[2][2] = 1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]); 00317 m[2][3] = 0.0f; 00318 00319 m[3][0] = 0.0f; 00320 m[3][1] = 0.0f; 00321 m[3][2] = 0.0f; 00322 m[3][3] = 1.0f; 00323 } 00324