|
Blender
V2.59
|
00001 /* 00002 * $Id: math_geom.c 38078 2011-07-04 08:13:27Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 00023 * The Original Code is: some of this file. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * */ 00027 00034 #include "MEM_guardedalloc.h" 00035 00036 #include "BLI_math.h" 00037 #include "BLI_memarena.h" 00038 #include "BLI_utildefines.h" 00039 00040 /********************************** Polygons *********************************/ 00041 00042 void cent_tri_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3]) 00043 { 00044 cent[0]= 0.33333f*(v1[0]+v2[0]+v3[0]); 00045 cent[1]= 0.33333f*(v1[1]+v2[1]+v3[1]); 00046 cent[2]= 0.33333f*(v1[2]+v2[2]+v3[2]); 00047 } 00048 00049 void cent_quad_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]) 00050 { 00051 cent[0]= 0.25f*(v1[0]+v2[0]+v3[0]+v4[0]); 00052 cent[1]= 0.25f*(v1[1]+v2[1]+v3[1]+v4[1]); 00053 cent[2]= 0.25f*(v1[2]+v2[2]+v3[2]+v4[2]); 00054 } 00055 00056 float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]) 00057 { 00058 float n1[3],n2[3]; 00059 00060 n1[0]= v1[0]-v2[0]; 00061 n2[0]= v2[0]-v3[0]; 00062 n1[1]= v1[1]-v2[1]; 00063 n2[1]= v2[1]-v3[1]; 00064 n1[2]= v1[2]-v2[2]; 00065 n2[2]= v2[2]-v3[2]; 00066 n[0]= n1[1]*n2[2]-n1[2]*n2[1]; 00067 n[1]= n1[2]*n2[0]-n1[0]*n2[2]; 00068 n[2]= n1[0]*n2[1]-n1[1]*n2[0]; 00069 00070 return normalize_v3(n); 00071 } 00072 00073 float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]) 00074 { 00075 /* real cross! */ 00076 float n1[3],n2[3]; 00077 00078 n1[0]= v1[0]-v3[0]; 00079 n1[1]= v1[1]-v3[1]; 00080 n1[2]= v1[2]-v3[2]; 00081 00082 n2[0]= v2[0]-v4[0]; 00083 n2[1]= v2[1]-v4[1]; 00084 n2[2]= v2[2]-v4[2]; 00085 00086 n[0]= n1[1]*n2[2]-n1[2]*n2[1]; 00087 n[1]= n1[2]*n2[0]-n1[0]*n2[2]; 00088 n[2]= n1[0]*n2[1]-n1[1]*n2[0]; 00089 00090 return normalize_v3(n); 00091 } 00092 00093 float area_tri_v2(const float v1[2], const float v2[2], const float v3[2]) 00094 { 00095 return 0.5f * fabsf((v1[0]-v2[0])*(v2[1]-v3[1]) + (v1[1]-v2[1])*(v3[0]-v2[0])); 00096 } 00097 00098 float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2]) 00099 { 00100 return 0.5f * ((v1[0]-v2[0])*(v2[1]-v3[1]) + (v1[1]-v2[1])*(v3[0]-v2[0])); 00101 } 00102 00103 float area_quad_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) /* only convex Quadrilaterals */ 00104 { 00105 float len, vec1[3], vec2[3], n[3]; 00106 00107 sub_v3_v3v3(vec1, v2, v1); 00108 sub_v3_v3v3(vec2, v4, v1); 00109 cross_v3_v3v3(n, vec1, vec2); 00110 len= normalize_v3(n); 00111 00112 sub_v3_v3v3(vec1, v4, v3); 00113 sub_v3_v3v3(vec2, v2, v3); 00114 cross_v3_v3v3(n, vec1, vec2); 00115 len+= normalize_v3(n); 00116 00117 return (len/2.0f); 00118 } 00119 00120 float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]) /* Triangles */ 00121 { 00122 float len, vec1[3], vec2[3], n[3]; 00123 00124 sub_v3_v3v3(vec1, v3, v2); 00125 sub_v3_v3v3(vec2, v1, v2); 00126 cross_v3_v3v3(n, vec1, vec2); 00127 len= normalize_v3(n); 00128 00129 return (len/2.0f); 00130 } 00131 00132 float area_poly_v3(int nr, float verts[][3], const float normal[3]) 00133 { 00134 float x, y, z, area, max; 00135 float *cur, *prev; 00136 int a, px=0, py=1; 00137 00138 /* first: find dominant axis: 0==X, 1==Y, 2==Z */ 00139 x= (float)fabs(normal[0]); 00140 y= (float)fabs(normal[1]); 00141 z= (float)fabs(normal[2]); 00142 max = MAX3(x, y, z); 00143 if(max==y) py=2; 00144 else if(max==x) { 00145 px=1; 00146 py= 2; 00147 } 00148 00149 /* The Trapezium Area Rule */ 00150 prev= verts[nr-1]; 00151 cur= verts[0]; 00152 area= 0; 00153 for(a=0; a<nr; a++) { 00154 area+= (cur[px]-prev[px])*(cur[py]+prev[py]); 00155 prev= verts[a]; 00156 cur= verts[a+1]; 00157 } 00158 00159 return fabsf(0.5f * area / max); 00160 } 00161 00162 /********************************* Distance **********************************/ 00163 00164 /* distance v1 to line v2-v3 */ 00165 /* using Hesse formula, NO LINE PIECE! */ 00166 float dist_to_line_v2(const float v1[2], const float v2[2], const float v3[2]) 00167 { 00168 float a[2],deler; 00169 00170 a[0]= v2[1]-v3[1]; 00171 a[1]= v3[0]-v2[0]; 00172 deler= (float)sqrt(a[0]*a[0]+a[1]*a[1]); 00173 if(deler== 0.0f) return 0; 00174 00175 return fabsf((v1[0]-v2[0])*a[0]+(v1[1]-v2[1])*a[1])/deler; 00176 00177 } 00178 00179 /* distance v1 to line-piece v2-v3 */ 00180 float dist_to_line_segment_v2(const float v1[2], const float v2[2], const float v3[2]) 00181 { 00182 float labda, rc[2], pt[2], len; 00183 00184 rc[0]= v3[0]-v2[0]; 00185 rc[1]= v3[1]-v2[1]; 00186 len= rc[0]*rc[0]+ rc[1]*rc[1]; 00187 if(len==0.0f) { 00188 rc[0]= v1[0]-v2[0]; 00189 rc[1]= v1[1]-v2[1]; 00190 return (float)(sqrt(rc[0]*rc[0]+ rc[1]*rc[1])); 00191 } 00192 00193 labda= (rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]))/len; 00194 if(labda <= 0.0f) { 00195 pt[0]= v2[0]; 00196 pt[1]= v2[1]; 00197 } 00198 else if(labda >= 1.0f) { 00199 pt[0]= v3[0]; 00200 pt[1]= v3[1]; 00201 } 00202 else { 00203 pt[0]= labda*rc[0]+v2[0]; 00204 pt[1]= labda*rc[1]+v2[1]; 00205 } 00206 00207 rc[0]= pt[0]-v1[0]; 00208 rc[1]= pt[1]-v1[1]; 00209 return sqrtf(rc[0]*rc[0]+ rc[1]*rc[1]); 00210 } 00211 00212 /* point closest to v1 on line v2-v3 in 3D */ 00213 void closest_to_line_segment_v3(float closest[3], const float v1[3], const float v2[3], const float v3[3]) 00214 { 00215 float lambda, cp[3]; 00216 00217 lambda= closest_to_line_v3(cp,v1, v2, v3); 00218 00219 if(lambda <= 0.0f) 00220 copy_v3_v3(closest, v2); 00221 else if(lambda >= 1.0f) 00222 copy_v3_v3(closest, v3); 00223 else 00224 copy_v3_v3(closest, cp); 00225 } 00226 00227 /* distance v1 to line-piece v2-v3 in 3D */ 00228 float dist_to_line_segment_v3(const float v1[3], const float v2[3], const float v3[3]) 00229 { 00230 float closest[3]; 00231 00232 closest_to_line_segment_v3(closest, v1, v2, v3); 00233 00234 return len_v3v3(closest, v1); 00235 } 00236 00237 /******************************* Intersection ********************************/ 00238 00239 /* intersect Line-Line, shorts */ 00240 int isect_line_line_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]) 00241 { 00242 float div, labda, mu; 00243 00244 div= (float)((v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0])); 00245 if(div==0.0f) return ISECT_LINE_LINE_COLINEAR; 00246 00247 labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div; 00248 00249 mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div; 00250 00251 if(labda>=0.0f && labda<=1.0f && mu>=0.0f && mu<=1.0f) { 00252 if(labda==0.0f || labda==1.0f || mu==0.0f || mu==1.0f) return ISECT_LINE_LINE_EXACT; 00253 return ISECT_LINE_LINE_CROSS; 00254 } 00255 return ISECT_LINE_LINE_NONE; 00256 } 00257 00258 /* intersect Line-Line, floats */ 00259 int isect_line_line_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) 00260 { 00261 float div, labda, mu; 00262 00263 div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]); 00264 if(div==0.0f) return ISECT_LINE_LINE_COLINEAR; 00265 00266 labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div; 00267 00268 mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div; 00269 00270 if(labda>=0.0f && labda<=1.0f && mu>=0.0f && mu<=1.0f) { 00271 if(labda==0.0f || labda==1.0f || mu==0.0f || mu==1.0f) return ISECT_LINE_LINE_EXACT; 00272 return ISECT_LINE_LINE_CROSS; 00273 } 00274 return ISECT_LINE_LINE_NONE; 00275 } 00276 00277 /* get intersection point of two 2D segments and return intersection type: 00278 -1: colliniar 00279 1: intersection */ 00280 int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], float vi[2]) 00281 { 00282 float a1, a2, b1, b2, c1, c2, d; 00283 float u, v; 00284 const float eps= 0.000001f; 00285 00286 a1= v2[0]-v1[0]; 00287 b1= v4[0]-v3[0]; 00288 c1= v1[0]-v4[0]; 00289 00290 a2= v2[1]-v1[1]; 00291 b2= v4[1]-v3[1]; 00292 c2= v1[1]-v4[1]; 00293 00294 d= a1*b2-a2*b1; 00295 00296 if(d==0) { 00297 if(a1*c2-a2*c1==0.0f && b1*c2-b2*c1==0.0f) { /* equal lines */ 00298 float a[2], b[2], c[2]; 00299 float u2; 00300 00301 if(len_v2v2(v1, v2)==0.0f) { 00302 if(len_v2v2(v3, v4)>eps) { 00303 /* use non-point segment as basis */ 00304 SWAP(const float *, v1, v3); 00305 SWAP(const float *, v2, v4); 00306 } else { /* both of segments are points */ 00307 if(equals_v2v2(v1, v3)) { /* points are equal */ 00308 copy_v2_v2(vi, v1); 00309 return 1; 00310 } 00311 00312 /* two different points */ 00313 return -1; 00314 } 00315 } 00316 00317 sub_v2_v2v2(a, v3, v1); 00318 sub_v2_v2v2(b, v2, v1); 00319 sub_v2_v2v2(c, v2, v1); 00320 u= dot_v2v2(a, b) / dot_v2v2(c, c); 00321 00322 sub_v2_v2v2(a, v4, v1); 00323 u2= dot_v2v2(a, b) / dot_v2v2(c, c); 00324 00325 if(u>u2) SWAP(float, u, u2); 00326 00327 if(u>1.0f+eps || u2<-eps) return -1; /* non-ovlerlapping segments */ 00328 else if(maxf(0.0f, u) == minf(1.0f, u2)){ /* one common point: can return result */ 00329 interp_v2_v2v2(vi, v1, v2, maxf(0, u)); 00330 return 1; 00331 } 00332 } 00333 00334 /* lines are colliniar */ 00335 return -1; 00336 } 00337 00338 u= (c2*b1-b2*c1)/d; 00339 v= (c1*a2-a1*c2)/d; 00340 00341 if(u>=-eps && u<=1.0f+eps && v>=-eps && v<=1.0f+eps) { /* intersection */ 00342 interp_v2_v2v2(vi, v1, v2, u); 00343 return 1; 00344 } 00345 00346 /* out of segment intersection */ 00347 return -1; 00348 } 00349 00350 int isect_line_sphere_v3(const float l1[3], const float l2[3], 00351 const float sp[3], const float r, 00352 float r_p1[3], float r_p2[3]) 00353 { 00354 /* l1: coordinates (point of line) 00355 * l2: coordinates (point of line) 00356 * sp, r: coordinates and radius (sphere) 00357 * r_p1, r_p2: return intersection coordinates 00358 */ 00359 00360 00361 /* adapted for use in blender by Campbell Barton - 2011 00362 * 00363 * atelier iebele abel - 2001 00364 * atelier@iebele.nl 00365 * http://www.iebele.nl 00366 * 00367 * sphere_line_intersection function adapted from: 00368 * http://astronomy.swin.edu.au/pbourke/geometry/sphereline 00369 * Paul Bourke pbourke@swin.edu.au 00370 */ 00371 00372 const float ldir[3]= { 00373 l2[0] - l1[0], 00374 l2[1] - l1[1], 00375 l2[2] - l1[2] 00376 }; 00377 00378 const float a= dot_v3v3(ldir, ldir); 00379 00380 const float b= 2.0f * 00381 (ldir[0] * (l1[0] - sp[0]) + 00382 ldir[1] * (l1[1] - sp[1]) + 00383 ldir[2] * (l1[2] - sp[2])); 00384 00385 const float c= 00386 dot_v3v3(sp, sp) + 00387 dot_v3v3(l1, l1) - 00388 (2.0f * dot_v3v3(sp, l1)) - 00389 (r * r); 00390 00391 const float i = b * b - 4.0f * a * c; 00392 00393 float mu; 00394 00395 if (i < 0.0f) { 00396 /* no intersections */ 00397 return 0; 00398 } 00399 else if (i == 0.0f) { 00400 /* one intersection */ 00401 mu = -b / (2.0f * a); 00402 madd_v3_v3v3fl(r_p1, l1, ldir, mu); 00403 return 1; 00404 } 00405 else if (i > 0.0) { 00406 const float i_sqrt= sqrt(i); /* avoid calc twice */ 00407 00408 /* first intersection */ 00409 mu = (-b + i_sqrt) / (2.0f * a); 00410 madd_v3_v3v3fl(r_p1, l1, ldir, mu); 00411 00412 /* second intersection */ 00413 mu = (-b - i_sqrt) / (2.0f * a); 00414 madd_v3_v3v3fl(r_p2, l1, ldir, mu); 00415 return 2; 00416 } 00417 else { 00418 /* math domain error - nan */ 00419 return -1; 00420 } 00421 } 00422 00423 /* keep in sync with isect_line_sphere_v3 */ 00424 int isect_line_sphere_v2(const float l1[2], const float l2[2], 00425 const float sp[2], const float r, 00426 float r_p1[2], float r_p2[2]) 00427 { 00428 const float ldir[2]= { 00429 l2[0] - l1[0], 00430 l2[1] - l1[1] 00431 }; 00432 00433 const float a= dot_v2v2(ldir, ldir); 00434 00435 const float b= 2.0f * 00436 (ldir[0] * (l1[0] - sp[0]) + 00437 ldir[1] * (l1[1] - sp[1])); 00438 00439 const float c= 00440 dot_v2v2(sp, sp) + 00441 dot_v2v2(l1, l1) - 00442 (2.0f * dot_v2v2(sp, l1)) - 00443 (r * r); 00444 00445 const float i = b * b - 4.0f * a * c; 00446 00447 float mu; 00448 00449 if (i < 0.0f) { 00450 /* no intersections */ 00451 return 0; 00452 } 00453 else if (i == 0.0f) { 00454 /* one intersection */ 00455 mu = -b / (2.0f * a); 00456 madd_v2_v2v2fl(r_p1, l1, ldir, mu); 00457 return 1; 00458 } 00459 else if (i > 0.0) { 00460 const float i_sqrt= sqrt(i); /* avoid calc twice */ 00461 00462 /* first intersection */ 00463 mu = (-b + i_sqrt) / (2.0f * a); 00464 madd_v2_v2v2fl(r_p1, l1, ldir, mu); 00465 00466 /* second intersection */ 00467 mu = (-b - i_sqrt) / (2.0f * a); 00468 madd_v2_v2v2fl(r_p2, l1, ldir, mu); 00469 return 2; 00470 } 00471 else { 00472 /* math domain error - nan */ 00473 return -1; 00474 } 00475 } 00476 00477 /* 00478 -1: colliniar 00479 1: intersection 00480 00481 */ 00482 static short IsectLLPt2Df(const float x0, const float y0, const float x1, const float y1, 00483 const float x2, const float y2, const float x3, const float y3, float *xi,float *yi) 00484 00485 { 00486 /* 00487 this function computes the intersection of the sent lines 00488 and returns the intersection point, note that the function assumes 00489 the lines intersect. the function can handle vertical as well 00490 as horizontal lines. note the function isn't very clever, it simply 00491 applies the math, but we don't need speed since this is a 00492 pre-processing step 00493 */ 00494 float c1,c2, // constants of linear equations 00495 det_inv, // the inverse of the determinant of the coefficient 00496 m1,m2; // the slopes of each line 00497 /* 00498 compute slopes, note the cludge for infinity, however, this will 00499 be close enough 00500 */ 00501 if (fabs(x1-x0) > 0.000001) 00502 m1 = (y1-y0) / (x1-x0); 00503 else 00504 return -1; /*m1 = (float) 1e+10;*/ // close enough to infinity 00505 00506 if (fabs(x3-x2) > 0.000001) 00507 m2 = (y3-y2) / (x3-x2); 00508 else 00509 return -1; /*m2 = (float) 1e+10;*/ // close enough to infinity 00510 00511 if (fabs(m1-m2) < 0.000001) 00512 return -1; /* parallel lines */ 00513 00514 // compute constants 00515 00516 c1 = (y0-m1*x0); 00517 c2 = (y2-m2*x2); 00518 00519 // compute the inverse of the determinate 00520 00521 det_inv = 1.0f / (-m1 + m2); 00522 00523 // use Kramers rule to compute xi and yi 00524 00525 *xi= ((-c2 + c1) *det_inv); 00526 *yi= ((m2*c1 - m1*c2) *det_inv); 00527 00528 return 1; 00529 } // end Intersect_Lines 00530 00531 /* point in tri */ 00532 00533 int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2]) 00534 { 00535 if (line_point_side_v2(v1,v2,pt)>=0.0f) { 00536 if (line_point_side_v2(v2,v3,pt)>=0.0f) { 00537 if (line_point_side_v2(v3,v1,pt)>=0.0f) { 00538 return 1; 00539 } 00540 } 00541 } else { 00542 if (! (line_point_side_v2(v2,v3,pt)>=0.0f)) { 00543 if (! (line_point_side_v2(v3,v1,pt)>=0.0f)) { 00544 return -1; 00545 } 00546 } 00547 } 00548 00549 return 0; 00550 } 00551 /* point in quad - only convex quads */ 00552 int isect_point_quad_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2]) 00553 { 00554 if (line_point_side_v2(v1,v2,pt)>=0.0f) { 00555 if (line_point_side_v2(v2,v3,pt)>=0.0f) { 00556 if (line_point_side_v2(v3,v4,pt)>=0.0f) { 00557 if (line_point_side_v2(v4,v1,pt)>=0.0f) { 00558 return 1; 00559 } 00560 } 00561 } 00562 } else { 00563 if (! (line_point_side_v2(v2,v3,pt)>=0.0f)) { 00564 if (! (line_point_side_v2(v3,v4,pt)>=0.0f)) { 00565 if (! (line_point_side_v2(v4,v1,pt)>=0.0f)) { 00566 return -1; 00567 } 00568 } 00569 } 00570 } 00571 00572 return 0; 00573 } 00574 00575 /* moved from effect.c 00576 test if the line starting at p1 ending at p2 intersects the triangle v0..v2 00577 return non zero if it does 00578 */ 00579 int isect_line_tri_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float uv[2]) 00580 { 00581 00582 float p[3], s[3], d[3], e1[3], e2[3], q[3]; 00583 float a, f, u, v; 00584 00585 sub_v3_v3v3(e1, v1, v0); 00586 sub_v3_v3v3(e2, v2, v0); 00587 sub_v3_v3v3(d, p2, p1); 00588 00589 cross_v3_v3v3(p, d, e2); 00590 a = dot_v3v3(e1, p); 00591 if ((a > -0.000001f) && (a < 0.000001f)) return 0; 00592 f = 1.0f/a; 00593 00594 sub_v3_v3v3(s, p1, v0); 00595 00596 u = f * dot_v3v3(s, p); 00597 if ((u < 0.0f)||(u > 1.0f)) return 0; 00598 00599 cross_v3_v3v3(q, s, e1); 00600 00601 v = f * dot_v3v3(d, q); 00602 if ((v < 0.0f)||((u + v) > 1.0f)) return 0; 00603 00604 *lambda = f * dot_v3v3(e2, q); 00605 if ((*lambda < 0.0f)||(*lambda > 1.0f)) return 0; 00606 00607 if(uv) { 00608 uv[0]= u; 00609 uv[1]= v; 00610 } 00611 00612 return 1; 00613 } 00614 /* moved from effect.c 00615 test if the ray starting at p1 going in d direction intersects the triangle v0..v2 00616 return non zero if it does 00617 */ 00618 int isect_ray_tri_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float uv[2]) 00619 { 00620 float p[3], s[3], e1[3], e2[3], q[3]; 00621 float a, f, u, v; 00622 00623 sub_v3_v3v3(e1, v1, v0); 00624 sub_v3_v3v3(e2, v2, v0); 00625 00626 cross_v3_v3v3(p, d, e2); 00627 a = dot_v3v3(e1, p); 00628 /* note: these values were 0.000001 in 2.4x but for projection snapping on 00629 * a human head (1BU==1m), subsurf level 2, this gave many errors - campbell */ 00630 if ((a > -0.00000001f) && (a < 0.00000001f)) return 0; 00631 f = 1.0f/a; 00632 00633 sub_v3_v3v3(s, p1, v0); 00634 00635 u = f * dot_v3v3(s, p); 00636 if ((u < 0.0f)||(u > 1.0f)) return 0; 00637 00638 cross_v3_v3v3(q, s, e1); 00639 00640 v = f * dot_v3v3(d, q); 00641 if ((v < 0.0f)||((u + v) > 1.0f)) return 0; 00642 00643 *lambda = f * dot_v3v3(e2, q); 00644 if ((*lambda < 0.0f)) return 0; 00645 00646 if(uv) { 00647 uv[0]= u; 00648 uv[1]= v; 00649 } 00650 00651 return 1; 00652 } 00653 00654 int isect_ray_plane_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, int clip) 00655 { 00656 float p[3], s[3], e1[3], e2[3], q[3]; 00657 float a, f; 00658 /* float u, v; */ /*UNUSED*/ 00659 00660 sub_v3_v3v3(e1, v1, v0); 00661 sub_v3_v3v3(e2, v2, v0); 00662 00663 cross_v3_v3v3(p, d, e2); 00664 a = dot_v3v3(e1, p); 00665 /* note: these values were 0.000001 in 2.4x but for projection snapping on 00666 * a human head (1BU==1m), subsurf level 2, this gave many errors - campbell */ 00667 if ((a > -0.00000001f) && (a < 0.00000001f)) return 0; 00668 f = 1.0f/a; 00669 00670 sub_v3_v3v3(s, p1, v0); 00671 00672 /* u = f * dot_v3v3(s, p); */ /*UNUSED*/ 00673 00674 cross_v3_v3v3(q, s, e1); 00675 00676 /* v = f * dot_v3v3(d, q); */ /*UNUSED*/ 00677 00678 *lambda = f * dot_v3v3(e2, q); 00679 if (clip && (*lambda < 0.0f)) return 0; 00680 00681 return 1; 00682 } 00683 00684 int isect_ray_tri_epsilon_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float uv[2], const float epsilon) 00685 { 00686 float p[3], s[3], e1[3], e2[3], q[3]; 00687 float a, f, u, v; 00688 00689 sub_v3_v3v3(e1, v1, v0); 00690 sub_v3_v3v3(e2, v2, v0); 00691 00692 cross_v3_v3v3(p, d, e2); 00693 a = dot_v3v3(e1, p); 00694 if (a == 0.0f) return 0; 00695 f = 1.0f/a; 00696 00697 sub_v3_v3v3(s, p1, v0); 00698 00699 u = f * dot_v3v3(s, p); 00700 if ((u < -epsilon)||(u > 1.0f+epsilon)) return 0; 00701 00702 cross_v3_v3v3(q, s, e1); 00703 00704 v = f * dot_v3v3(d, q); 00705 if ((v < -epsilon)||((u + v) > 1.0f+epsilon)) return 0; 00706 00707 *lambda = f * dot_v3v3(e2, q); 00708 if ((*lambda < 0.0f)) return 0; 00709 00710 if(uv) { 00711 uv[0]= u; 00712 uv[1]= v; 00713 } 00714 00715 return 1; 00716 } 00717 00718 int isect_ray_tri_threshold_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *lambda, float *uv, const float threshold) 00719 { 00720 float p[3], s[3], e1[3], e2[3], q[3]; 00721 float a, f, u, v; 00722 float du = 0, dv = 0; 00723 00724 sub_v3_v3v3(e1, v1, v0); 00725 sub_v3_v3v3(e2, v2, v0); 00726 00727 cross_v3_v3v3(p, d, e2); 00728 a = dot_v3v3(e1, p); 00729 if ((a > -0.000001f) && (a < 0.000001f)) return 0; 00730 f = 1.0f/a; 00731 00732 sub_v3_v3v3(s, p1, v0); 00733 00734 cross_v3_v3v3(q, s, e1); 00735 *lambda = f * dot_v3v3(e2, q); 00736 if ((*lambda < 0.0f)) return 0; 00737 00738 u = f * dot_v3v3(s, p); 00739 v = f * dot_v3v3(d, q); 00740 00741 if (u < 0) du = u; 00742 if (u > 1) du = u - 1; 00743 if (v < 0) dv = v; 00744 if (v > 1) dv = v - 1; 00745 if (u > 0 && v > 0 && u + v > 1) 00746 { 00747 float t = u + v - 1; 00748 du = u - t/2; 00749 dv = v - t/2; 00750 } 00751 00752 mul_v3_fl(e1, du); 00753 mul_v3_fl(e2, dv); 00754 00755 if (dot_v3v3(e1, e1) + dot_v3v3(e2, e2) > threshold * threshold) 00756 { 00757 return 0; 00758 } 00759 00760 if(uv) { 00761 uv[0]= u; 00762 uv[1]= v; 00763 } 00764 00765 return 1; 00766 } 00767 00768 int isect_line_plane_v3(float out[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3], const short no_flip) 00769 { 00770 float l_vec[3]; /* l1 -> l2 normalized vector */ 00771 float p_no[3]; /* 'plane_no' normalized */ 00772 float dot; 00773 00774 sub_v3_v3v3(l_vec, l2, l1); 00775 00776 normalize_v3(l_vec); 00777 normalize_v3_v3(p_no, plane_no); 00778 00779 dot= dot_v3v3(l_vec, p_no); 00780 if(dot == 0.0f) { 00781 return 0; 00782 } 00783 else { 00784 float l1_plane[3]; /* line point aligned with the plane */ 00785 float dist; /* 'plane_no' aligned distance to the 'plane_co' */ 00786 00787 /* for pradictable flipping since the plane is only used to 00788 * define a direction, ignore its flipping and aligned with 'l_vec' */ 00789 if(dot < 0.0f) { 00790 dot= -dot; 00791 negate_v3(p_no); 00792 } 00793 00794 add_v3_v3v3(l1_plane, l1, p_no); 00795 00796 dist = line_point_factor_v3(plane_co, l1, l1_plane); 00797 00798 /* treat line like a ray, when 'no_flip' is set */ 00799 if(no_flip && dist < 0.0f) { 00800 dist= -dist; 00801 } 00802 00803 mul_v3_fl(l_vec, dist / dot); 00804 00805 add_v3_v3v3(out, l1, l_vec); 00806 00807 return 1; 00808 } 00809 } 00810 00811 /* Adapted from the paper by Kasper Fauerby */ 00812 /* "Improved Collision detection and Response" */ 00813 static int getLowestRoot(const float a, const float b, const float c, const float maxR, float *root) 00814 { 00815 // Check if a solution exists 00816 float determinant = b*b - 4.0f*a*c; 00817 00818 // If determinant is negative it means no solutions. 00819 if (determinant >= 0.0f) 00820 { 00821 // calculate the two roots: (if determinant == 0 then 00822 // x1==x2 but lets disregard that slight optimization) 00823 float sqrtD = (float)sqrt(determinant); 00824 float r1 = (-b - sqrtD) / (2.0f*a); 00825 float r2 = (-b + sqrtD) / (2.0f*a); 00826 00827 // Sort so x1 <= x2 00828 if (r1 > r2) 00829 SWAP(float, r1, r2); 00830 00831 // Get lowest root: 00832 if (r1 > 0.0f && r1 < maxR) 00833 { 00834 *root = r1; 00835 return 1; 00836 } 00837 00838 // It is possible that we want x2 - this can happen 00839 // if x1 < 0 00840 if (r2 > 0.0f && r2 < maxR) 00841 { 00842 *root = r2; 00843 return 1; 00844 } 00845 } 00846 // No (valid) solutions 00847 return 0; 00848 } 00849 00850 int isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius, const float v0[3], const float v1[3], const float v2[3], float *lambda, float ipoint[3]) 00851 { 00852 float e1[3], e2[3], e3[3], point[3], vel[3], /*dist[3],*/ nor[3], temp[3], bv[3]; 00853 float a, b, c, d, e, x, y, z, radius2=radius*radius; 00854 float elen2,edotv,edotbv,nordotv; 00855 float newLambda; 00856 int found_by_sweep=0; 00857 00858 sub_v3_v3v3(e1,v1,v0); 00859 sub_v3_v3v3(e2,v2,v0); 00860 sub_v3_v3v3(vel,p2,p1); 00861 00862 /*---test plane of tri---*/ 00863 cross_v3_v3v3(nor,e1,e2); 00864 normalize_v3(nor); 00865 00866 /* flip normal */ 00867 if(dot_v3v3(nor,vel)>0.0f) negate_v3(nor); 00868 00869 a=dot_v3v3(p1,nor)-dot_v3v3(v0,nor); 00870 nordotv=dot_v3v3(nor,vel); 00871 00872 if (fabsf(nordotv) < 0.000001f) 00873 { 00874 if(fabsf(a) >= radius) { 00875 return 0; 00876 } 00877 } 00878 else 00879 { 00880 float t0=(-a+radius)/nordotv; 00881 float t1=(-a-radius)/nordotv; 00882 00883 if(t0>t1) 00884 SWAP(float, t0, t1); 00885 00886 if(t0>1.0f || t1<0.0f) return 0; 00887 00888 /* clamp to [0,1] */ 00889 CLAMP(t0, 0.0f, 1.0f); 00890 CLAMP(t1, 0.0f, 1.0f); 00891 00892 /*---test inside of tri---*/ 00893 /* plane intersection point */ 00894 00895 point[0] = p1[0] + vel[0]*t0 - nor[0]*radius; 00896 point[1] = p1[1] + vel[1]*t0 - nor[1]*radius; 00897 point[2] = p1[2] + vel[2]*t0 - nor[2]*radius; 00898 00899 00900 /* is the point in the tri? */ 00901 a=dot_v3v3(e1,e1); 00902 b=dot_v3v3(e1,e2); 00903 c=dot_v3v3(e2,e2); 00904 00905 sub_v3_v3v3(temp,point,v0); 00906 d=dot_v3v3(temp,e1); 00907 e=dot_v3v3(temp,e2); 00908 00909 x=d*c-e*b; 00910 y=e*a-d*b; 00911 z=x+y-(a*c-b*b); 00912 00913 00914 if(z <= 0.0f && (x >= 0.0f && y >= 0.0f)) 00915 { 00916 //(((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y))) & 0x80000000){ 00917 *lambda=t0; 00918 copy_v3_v3(ipoint,point); 00919 return 1; 00920 } 00921 } 00922 00923 00924 *lambda=1.0f; 00925 00926 /*---test points---*/ 00927 a=dot_v3v3(vel,vel); 00928 00929 /*v0*/ 00930 sub_v3_v3v3(temp,p1,v0); 00931 b=2.0f*dot_v3v3(vel,temp); 00932 c=dot_v3v3(temp,temp)-radius2; 00933 00934 if(getLowestRoot(a, b, c, *lambda, lambda)) 00935 { 00936 copy_v3_v3(ipoint,v0); 00937 found_by_sweep=1; 00938 } 00939 00940 /*v1*/ 00941 sub_v3_v3v3(temp,p1,v1); 00942 b=2.0f*dot_v3v3(vel,temp); 00943 c=dot_v3v3(temp,temp)-radius2; 00944 00945 if(getLowestRoot(a, b, c, *lambda, lambda)) 00946 { 00947 copy_v3_v3(ipoint,v1); 00948 found_by_sweep=1; 00949 } 00950 00951 /*v2*/ 00952 sub_v3_v3v3(temp,p1,v2); 00953 b=2.0f*dot_v3v3(vel,temp); 00954 c=dot_v3v3(temp,temp)-radius2; 00955 00956 if(getLowestRoot(a, b, c, *lambda, lambda)) 00957 { 00958 copy_v3_v3(ipoint,v2); 00959 found_by_sweep=1; 00960 } 00961 00962 /*---test edges---*/ 00963 sub_v3_v3v3(e3,v2,v1); //wasnt yet calculated 00964 00965 00966 /*e1*/ 00967 sub_v3_v3v3(bv,v0,p1); 00968 00969 elen2 = dot_v3v3(e1,e1); 00970 edotv = dot_v3v3(e1,vel); 00971 edotbv = dot_v3v3(e1,bv); 00972 00973 a=elen2*(-dot_v3v3(vel,vel))+edotv*edotv; 00974 b=2.0f*(elen2*dot_v3v3(vel,bv)-edotv*edotbv); 00975 c=elen2*(radius2-dot_v3v3(bv,bv))+edotbv*edotbv; 00976 00977 if(getLowestRoot(a, b, c, *lambda, &newLambda)) 00978 { 00979 e=(edotv*newLambda-edotbv)/elen2; 00980 00981 if(e >= 0.0f && e <= 1.0f) 00982 { 00983 *lambda = newLambda; 00984 copy_v3_v3(ipoint,e1); 00985 mul_v3_fl(ipoint,e); 00986 add_v3_v3(ipoint, v0); 00987 found_by_sweep=1; 00988 } 00989 } 00990 00991 /*e2*/ 00992 /*bv is same*/ 00993 elen2 = dot_v3v3(e2,e2); 00994 edotv = dot_v3v3(e2,vel); 00995 edotbv = dot_v3v3(e2,bv); 00996 00997 a=elen2*(-dot_v3v3(vel,vel))+edotv*edotv; 00998 b=2.0f*(elen2*dot_v3v3(vel,bv)-edotv*edotbv); 00999 c=elen2*(radius2-dot_v3v3(bv,bv))+edotbv*edotbv; 01000 01001 if(getLowestRoot(a, b, c, *lambda, &newLambda)) 01002 { 01003 e=(edotv*newLambda-edotbv)/elen2; 01004 01005 if(e >= 0.0f && e <= 1.0f) 01006 { 01007 *lambda = newLambda; 01008 copy_v3_v3(ipoint,e2); 01009 mul_v3_fl(ipoint,e); 01010 add_v3_v3(ipoint, v0); 01011 found_by_sweep=1; 01012 } 01013 } 01014 01015 /*e3*/ 01016 /* sub_v3_v3v3(bv,v0,p1); */ /* UNUSED */ 01017 /* elen2 = dot_v3v3(e1,e1); */ /* UNUSED */ 01018 /* edotv = dot_v3v3(e1,vel); */ /* UNUSED */ 01019 /* edotbv = dot_v3v3(e1,bv); */ /* UNUSED */ 01020 01021 sub_v3_v3v3(bv,v1,p1); 01022 elen2 = dot_v3v3(e3,e3); 01023 edotv = dot_v3v3(e3,vel); 01024 edotbv = dot_v3v3(e3,bv); 01025 01026 a=elen2*(-dot_v3v3(vel,vel))+edotv*edotv; 01027 b=2.0f*(elen2*dot_v3v3(vel,bv)-edotv*edotbv); 01028 c=elen2*(radius2-dot_v3v3(bv,bv))+edotbv*edotbv; 01029 01030 if(getLowestRoot(a, b, c, *lambda, &newLambda)) 01031 { 01032 e=(edotv*newLambda-edotbv)/elen2; 01033 01034 if(e >= 0.0f && e <= 1.0f) 01035 { 01036 *lambda = newLambda; 01037 copy_v3_v3(ipoint,e3); 01038 mul_v3_fl(ipoint,e); 01039 add_v3_v3(ipoint, v1); 01040 found_by_sweep=1; 01041 } 01042 } 01043 01044 01045 return found_by_sweep; 01046 } 01047 int isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *lambda) 01048 { 01049 float p[3], e1[3], e2[3]; 01050 float u, v, f; 01051 int a0=axis, a1=(axis+1)%3, a2=(axis+2)%3; 01052 01053 //return isect_line_tri_v3(p1,p2,v0,v1,v2,lambda); 01054 01056 //if(MIN3(v0[a1],v1[a1],v2[a1]) > p1[a1]) return 0; 01057 //if(MIN3(v0[a2],v1[a2],v2[a2]) > p1[a2]) return 0; 01058 //if(MAX3(v0[a1],v1[a1],v2[a1]) < p1[a1]) return 0; 01059 //if(MAX3(v0[a2],v1[a2],v2[a2]) < p1[a2]) return 0; 01060 01062 01063 sub_v3_v3v3(e1,v1,v0); 01064 sub_v3_v3v3(e2,v2,v0); 01065 sub_v3_v3v3(p,v0,p1); 01066 01067 f= (e2[a1]*e1[a2]-e2[a2]*e1[a1]); 01068 if ((f > -0.000001f) && (f < 0.000001f)) return 0; 01069 01070 v= (p[a2]*e1[a1]-p[a1]*e1[a2])/f; 01071 if ((v < 0.0f)||(v > 1.0f)) return 0; 01072 01073 f= e1[a1]; 01074 if((f > -0.000001f) && (f < 0.000001f)){ 01075 f= e1[a2]; 01076 if((f > -0.000001f) && (f < 0.000001f)) return 0; 01077 u= (-p[a2]-v*e2[a2])/f; 01078 } 01079 else 01080 u= (-p[a1]-v*e2[a1])/f; 01081 01082 if ((u < 0.0f) || ((u + v) > 1.0f)) return 0; 01083 01084 *lambda = (p[a0]+u*e1[a0]+v*e2[a0])/(p2[a0]-p1[a0]); 01085 01086 if ((*lambda < 0.0f) || (*lambda > 1.0f)) return 0; 01087 01088 return 1; 01089 } 01090 01091 /* Returns the number of point of interests 01092 * 0 - lines are colinear 01093 * 1 - lines are coplanar, i1 is set to intersection 01094 * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively 01095 * */ 01096 int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float i1[3], float i2[3]) 01097 { 01098 float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3]; 01099 float d; 01100 01101 sub_v3_v3v3(c, v3, v1); 01102 sub_v3_v3v3(a, v2, v1); 01103 sub_v3_v3v3(b, v4, v3); 01104 01105 normalize_v3_v3(dir1, a); 01106 normalize_v3_v3(dir2, b); 01107 d = dot_v3v3(dir1, dir2); 01108 if (d == 1.0f || d == -1.0f) { 01109 /* colinear */ 01110 return 0; 01111 } 01112 01113 cross_v3_v3v3(ab, a, b); 01114 d = dot_v3v3(c, ab); 01115 01116 /* test if the two lines are coplanar */ 01117 if (d > -0.000001f && d < 0.000001f) { 01118 cross_v3_v3v3(cb, c, b); 01119 01120 mul_v3_fl(a, dot_v3v3(cb, ab) / dot_v3v3(ab, ab)); 01121 add_v3_v3v3(i1, v1, a); 01122 copy_v3_v3(i2, i1); 01123 01124 return 1; /* one intersection only */ 01125 } 01126 /* if not */ 01127 else { 01128 float n[3], t[3]; 01129 float v3t[3], v4t[3]; 01130 sub_v3_v3v3(t, v1, v3); 01131 01132 /* offset between both plane where the lines lies */ 01133 cross_v3_v3v3(n, a, b); 01134 project_v3_v3v3(t, t, n); 01135 01136 /* for the first line, offset the second line until it is coplanar */ 01137 add_v3_v3v3(v3t, v3, t); 01138 add_v3_v3v3(v4t, v4, t); 01139 01140 sub_v3_v3v3(c, v3t, v1); 01141 sub_v3_v3v3(a, v2, v1); 01142 sub_v3_v3v3(b, v4t, v3t); 01143 01144 cross_v3_v3v3(ab, a, b); 01145 cross_v3_v3v3(cb, c, b); 01146 01147 mul_v3_fl(a, dot_v3v3(cb, ab) / dot_v3v3(ab, ab)); 01148 add_v3_v3v3(i1, v1, a); 01149 01150 /* for the second line, just substract the offset from the first intersection point */ 01151 sub_v3_v3v3(i2, i1, t); 01152 01153 return 2; /* two nearest points */ 01154 } 01155 } 01156 01157 /* Intersection point strictly between the two lines 01158 * 0 when no intersection is found 01159 * */ 01160 int isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *lambda) 01161 { 01162 float a[3], b[3], c[3], ab[3], cb[3], ca[3], dir1[3], dir2[3]; 01163 float d; 01164 01165 sub_v3_v3v3(c, v3, v1); 01166 sub_v3_v3v3(a, v2, v1); 01167 sub_v3_v3v3(b, v4, v3); 01168 01169 normalize_v3_v3(dir1, a); 01170 normalize_v3_v3(dir2, b); 01171 d = dot_v3v3(dir1, dir2); 01172 if (d == 1.0f || d == -1.0f || d == 0) { 01173 /* colinear or one vector is zero-length*/ 01174 return 0; 01175 } 01176 01177 cross_v3_v3v3(ab, a, b); 01178 d = dot_v3v3(c, ab); 01179 01180 /* test if the two lines are coplanar */ 01181 if (d > -0.000001f && d < 0.000001f) { 01182 float f1, f2; 01183 cross_v3_v3v3(cb, c, b); 01184 cross_v3_v3v3(ca, c, a); 01185 01186 f1 = dot_v3v3(cb, ab) / dot_v3v3(ab, ab); 01187 f2 = dot_v3v3(ca, ab) / dot_v3v3(ab, ab); 01188 01189 if (f1 >= 0 && f1 <= 1 && 01190 f2 >= 0 && f2 <= 1) 01191 { 01192 mul_v3_fl(a, f1); 01193 add_v3_v3v3(vi, v1, a); 01194 01195 if (lambda != NULL) 01196 { 01197 *lambda = f1; 01198 } 01199 01200 return 1; /* intersection found */ 01201 } 01202 else 01203 { 01204 return 0; 01205 } 01206 } 01207 else 01208 { 01209 return 0; 01210 } 01211 } 01212 01213 int isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3]) 01214 { 01215 return (min1[0]<max2[0] && min1[1]<max2[1] && min1[2]<max2[2] && 01216 min2[0]<max1[0] && min2[1]<max1[1] && min2[2]<max1[2]); 01217 } 01218 01219 /* find closest point to p on line through l1,l2 and return lambda, 01220 * where (0 <= lambda <= 1) when cp is in the line segement l1,l2 01221 */ 01222 float closest_to_line_v3(float cp[3], const float p[3], const float l1[3], const float l2[3]) 01223 { 01224 float h[3],u[3],lambda; 01225 sub_v3_v3v3(u, l2, l1); 01226 sub_v3_v3v3(h, p, l1); 01227 lambda =dot_v3v3(u,h)/dot_v3v3(u,u); 01228 cp[0] = l1[0] + u[0] * lambda; 01229 cp[1] = l1[1] + u[1] * lambda; 01230 cp[2] = l1[2] + u[2] * lambda; 01231 return lambda; 01232 } 01233 01234 float closest_to_line_v2(float cp[2],const float p[2], const float l1[2], const float l2[2]) 01235 { 01236 float h[2],u[2],lambda; 01237 sub_v2_v2v2(u, l2, l1); 01238 sub_v2_v2v2(h, p, l1); 01239 lambda =dot_v2v2(u,h)/dot_v2v2(u,u); 01240 cp[0] = l1[0] + u[0] * lambda; 01241 cp[1] = l1[1] + u[1] * lambda; 01242 return lambda; 01243 } 01244 01245 /* little sister we only need to know lambda */ 01246 float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]) 01247 { 01248 float h[3],u[3]; 01249 sub_v3_v3v3(u, l2, l1); 01250 sub_v3_v3v3(h, p, l1); 01251 return(dot_v3v3(u,h)/dot_v3v3(u,u)); 01252 } 01253 01254 float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]) 01255 { 01256 float h[2], u[2]; 01257 sub_v2_v2v2(u, l2, l1); 01258 sub_v2_v2v2(h, p, l1); 01259 return(dot_v2v2(u, h)/dot_v2v2(u, u)); 01260 } 01261 01262 /* Similar to LineIntersectsTriangleUV, except it operates on a quad and in 2d, assumes point is in quad */ 01263 void isect_point_quad_uv_v2(const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float pt[2], float *uv) 01264 { 01265 float x0,y0, x1,y1, wtot, v2d[2], w1, w2; 01266 01267 /* used for parallel lines */ 01268 float pt3d[3], l1[3], l2[3], pt_on_line[3]; 01269 01270 /* compute 2 edges of the quad intersection point */ 01271 if (IsectLLPt2Df(v0[0],v0[1],v1[0],v1[1], v2[0],v2[1],v3[0],v3[1], &x0,&y0) == 1) { 01272 /* the intersection point between the quad-edge intersection and the point in the quad we want the uv's for */ 01273 /* should never be paralle !! */ 01274 /*printf("\tnot parallel 1\n");*/ 01275 IsectLLPt2Df(pt[0],pt[1],x0,y0, v0[0],v0[1],v3[0],v3[1], &x1,&y1); 01276 01277 /* Get the weights from the new intersection point, to each edge */ 01278 v2d[0] = x1-v0[0]; 01279 v2d[1] = y1-v0[1]; 01280 w1 = len_v2(v2d); 01281 01282 v2d[0] = x1-v3[0]; /* some but for the other vert */ 01283 v2d[1] = y1-v3[1]; 01284 w2 = len_v2(v2d); 01285 wtot = w1+w2; 01286 /*w1 = w1/wtot;*/ 01287 /*w2 = w2/wtot;*/ 01288 uv[0] = w1/wtot; 01289 } else { 01290 /* lines are parallel, lambda_cp_line_ex is 3d grrr */ 01291 /*printf("\tparallel1\n");*/ 01292 pt3d[0] = pt[0]; 01293 pt3d[1] = pt[1]; 01294 pt3d[2] = l1[2] = l2[2] = 0.0f; 01295 01296 l1[0] = v0[0]; l1[1] = v0[1]; 01297 l2[0] = v1[0]; l2[1] = v1[1]; 01298 closest_to_line_v3(pt_on_line,pt3d, l1, l2); 01299 v2d[0] = pt[0]-pt_on_line[0]; /* same, for the other vert */ 01300 v2d[1] = pt[1]-pt_on_line[1]; 01301 w1 = len_v2(v2d); 01302 01303 l1[0] = v2[0]; l1[1] = v2[1]; 01304 l2[0] = v3[0]; l2[1] = v3[1]; 01305 closest_to_line_v3(pt_on_line,pt3d, l1, l2); 01306 v2d[0] = pt[0]-pt_on_line[0]; /* same, for the other vert */ 01307 v2d[1] = pt[1]-pt_on_line[1]; 01308 w2 = len_v2(v2d); 01309 wtot = w1+w2; 01310 uv[0] = w1/wtot; 01311 } 01312 01313 /* Same as above to calc the uv[1] value, alternate calculation */ 01314 01315 if (IsectLLPt2Df(v0[0],v0[1],v3[0],v3[1], v1[0],v1[1],v2[0],v2[1], &x0,&y0) == 1) { /* was v0,v1 v2,v3 now v0,v3 v1,v2*/ 01316 /* never paralle if above was not */ 01317 /*printf("\tnot parallel2\n");*/ 01318 IsectLLPt2Df(pt[0],pt[1],x0,y0, v0[0],v0[1],v1[0],v1[1], &x1,&y1);/* was v0,v3 now v0,v1*/ 01319 01320 v2d[0] = x1-v0[0]; 01321 v2d[1] = y1-v0[1]; 01322 w1 = len_v2(v2d); 01323 01324 v2d[0] = x1-v1[0]; 01325 v2d[1] = y1-v1[1]; 01326 w2 = len_v2(v2d); 01327 wtot = w1+w2; 01328 uv[1] = w1/wtot; 01329 } else { 01330 /* lines are parallel, lambda_cp_line_ex is 3d grrr */ 01331 /*printf("\tparallel2\n");*/ 01332 pt3d[0] = pt[0]; 01333 pt3d[1] = pt[1]; 01334 pt3d[2] = l1[2] = l2[2] = 0.0f; 01335 01336 01337 l1[0] = v0[0]; l1[1] = v0[1]; 01338 l2[0] = v3[0]; l2[1] = v3[1]; 01339 closest_to_line_v3(pt_on_line,pt3d, l1, l2); 01340 v2d[0] = pt[0]-pt_on_line[0]; /* some but for the other vert */ 01341 v2d[1] = pt[1]-pt_on_line[1]; 01342 w1 = len_v2(v2d); 01343 01344 l1[0] = v1[0]; l1[1] = v1[1]; 01345 l2[0] = v2[0]; l2[1] = v2[1]; 01346 closest_to_line_v3(pt_on_line,pt3d, l1, l2); 01347 v2d[0] = pt[0]-pt_on_line[0]; /* some but for the other vert */ 01348 v2d[1] = pt[1]-pt_on_line[1]; 01349 w2 = len_v2(v2d); 01350 wtot = w1+w2; 01351 uv[1] = w1/wtot; 01352 } 01353 /* may need to flip UV's here */ 01354 } 01355 01356 /* same as above but does tri's and quads, tri's are a bit of a hack */ 01357 void isect_point_face_uv_v2(const int isquad, const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float pt[2], float *uv) 01358 { 01359 if (isquad) { 01360 isect_point_quad_uv_v2(v0, v1, v2, v3, pt, uv); 01361 } 01362 else { 01363 /* not for quads, use for our abuse of LineIntersectsTriangleUV */ 01364 float p1_3d[3], p2_3d[3], v0_3d[3], v1_3d[3], v2_3d[3], lambda; 01365 01366 p1_3d[0] = p2_3d[0] = uv[0]; 01367 p1_3d[1] = p2_3d[1] = uv[1]; 01368 p1_3d[2] = 1.0f; 01369 p2_3d[2] = -1.0f; 01370 v0_3d[2] = v1_3d[2] = v2_3d[2] = 0.0; 01371 01372 /* generate a new fuv, (this is possibly a non optimal solution, 01373 * since we only need 2d calculation but use 3d func's) 01374 * 01375 * this method makes an imaginary triangle in 2d space using the UV's from the derived mesh face 01376 * Then find new uv coords using the fuv and this face with LineIntersectsTriangleUV. 01377 * This means the new values will be correct in relation to the derived meshes face. 01378 */ 01379 copy_v2_v2(v0_3d, v0); 01380 copy_v2_v2(v1_3d, v1); 01381 copy_v2_v2(v2_3d, v2); 01382 01383 /* Doing this in 3D is not nice */ 01384 isect_line_tri_v3(p1_3d, p2_3d, v0_3d, v1_3d, v2_3d, &lambda, uv); 01385 } 01386 } 01387 01388 #if 0 // XXX this version used to be used in isect_point_tri_v2_int() and was called IsPointInTri2D 01389 int isect_point_tri_v2(float pt[2], float v1[2], float v2[2], float v3[2]) 01390 { 01391 float inp1, inp2, inp3; 01392 01393 inp1= (v2[0]-v1[0])*(v1[1]-pt[1]) + (v1[1]-v2[1])*(v1[0]-pt[0]); 01394 inp2= (v3[0]-v2[0])*(v2[1]-pt[1]) + (v2[1]-v3[1])*(v2[0]-pt[0]); 01395 inp3= (v1[0]-v3[0])*(v3[1]-pt[1]) + (v3[1]-v1[1])*(v3[0]-pt[0]); 01396 01397 if(inp1<=0.0f && inp2<=0.0f && inp3<=0.0f) return 1; 01398 if(inp1>=0.0f && inp2>=0.0f && inp3>=0.0f) return 1; 01399 01400 return 0; 01401 } 01402 #endif 01403 01404 #if 0 01405 int isect_point_tri_v2(float v0[2], float v1[2], float v2[2], float pt[2]) 01406 { 01407 /* not for quads, use for our abuse of LineIntersectsTriangleUV */ 01408 float p1_3d[3], p2_3d[3], v0_3d[3], v1_3d[3], v2_3d[3]; 01409 /* not used */ 01410 float lambda, uv[3]; 01411 01412 p1_3d[0] = p2_3d[0] = uv[0]= pt[0]; 01413 p1_3d[1] = p2_3d[1] = uv[1]= uv[2]= pt[1]; 01414 p1_3d[2] = 1.0f; 01415 p2_3d[2] = -1.0f; 01416 v0_3d[2] = v1_3d[2] = v2_3d[2] = 0.0; 01417 01418 /* generate a new fuv, (this is possibly a non optimal solution, 01419 * since we only need 2d calculation but use 3d func's) 01420 * 01421 * this method makes an imaginary triangle in 2d space using the UV's from the derived mesh face 01422 * Then find new uv coords using the fuv and this face with LineIntersectsTriangleUV. 01423 * This means the new values will be correct in relation to the derived meshes face. 01424 */ 01425 copy_v2_v2(v0_3d, v0); 01426 copy_v2_v2(v1_3d, v1); 01427 copy_v2_v2(v2_3d, v2); 01428 01429 /* Doing this in 3D is not nice */ 01430 return isect_line_tri_v3(p1_3d, p2_3d, v0_3d, v1_3d, v2_3d, &lambda, uv); 01431 } 01432 #endif 01433 01434 /* 01435 01436 x1,y2 01437 | \ 01438 | \ .(a,b) 01439 | \ 01440 x1,y1-- x2,y1 01441 01442 */ 01443 int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b) 01444 { 01445 float v1[2], v2[2], v3[2], p[2]; 01446 01447 v1[0]= (float)x1; 01448 v1[1]= (float)y1; 01449 01450 v2[0]= (float)x1; 01451 v2[1]= (float)y2; 01452 01453 v3[0]= (float)x2; 01454 v3[1]= (float)y1; 01455 01456 p[0]= (float)a; 01457 p[1]= (float)b; 01458 01459 return isect_point_tri_v2(p, v1, v2, v3); 01460 } 01461 01462 static int point_in_slice(const float p[3], const float v1[3], const float l1[3], const float l2[3]) 01463 { 01464 /* 01465 what is a slice ? 01466 some maths: 01467 a line including l1,l2 and a point not on the line 01468 define a subset of R3 delimeted by planes parallel to the line and orthogonal 01469 to the (point --> line) distance vector,one plane on the line one on the point, 01470 the room inside usually is rather small compared to R3 though still infinte 01471 useful for restricting (speeding up) searches 01472 e.g. all points of triangular prism are within the intersection of 3 'slices' 01473 onother trivial case : cube 01474 but see a 'spat' which is a deformed cube with paired parallel planes needs only 3 slices too 01475 */ 01476 float h,rp[3],cp[3],q[3]; 01477 01478 closest_to_line_v3(cp,v1,l1,l2); 01479 sub_v3_v3v3(q,cp,v1); 01480 01481 sub_v3_v3v3(rp,p,v1); 01482 h=dot_v3v3(q,rp)/dot_v3v3(q,q); 01483 if (h < 0.0f || h > 1.0f) return 0; 01484 return 1; 01485 } 01486 01487 #if 0 01488 /*adult sister defining the slice planes by the origin and the normal 01489 NOTE |normal| may not be 1 but defining the thickness of the slice*/ 01490 static int point_in_slice_as(float p[3],float origin[3],float normal[3]) 01491 { 01492 float h,rp[3]; 01493 sub_v3_v3v3(rp,p,origin); 01494 h=dot_v3v3(normal,rp)/dot_v3v3(normal,normal); 01495 if (h < 0.0f || h > 1.0f) return 0; 01496 return 1; 01497 } 01498 01499 /*mama (knowing the squared length of the normal)*/ 01500 static int point_in_slice_m(float p[3],float origin[3],float normal[3],float lns) 01501 { 01502 float h,rp[3]; 01503 sub_v3_v3v3(rp,p,origin); 01504 h=dot_v3v3(normal,rp)/lns; 01505 if (h < 0.0f || h > 1.0f) return 0; 01506 return 1; 01507 } 01508 #endif 01509 01510 int isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]) 01511 { 01512 if(!point_in_slice(p,v1,v2,v3)) return 0; 01513 if(!point_in_slice(p,v2,v3,v1)) return 0; 01514 if(!point_in_slice(p,v3,v1,v2)) return 0; 01515 return 1; 01516 } 01517 01518 int clip_line_plane(float p1[3], float p2[3], const float plane[4]) 01519 { 01520 float dp[3], n[3], div, t, pc[3]; 01521 01522 copy_v3_v3(n, plane); 01523 sub_v3_v3v3(dp, p2, p1); 01524 div= dot_v3v3(dp, n); 01525 01526 if(div == 0.0f) /* parallel */ 01527 return 1; 01528 01529 t= -(dot_v3v3(p1, n) + plane[3])/div; 01530 01531 if(div > 0.0f) { 01532 /* behind plane, completely clipped */ 01533 if(t >= 1.0f) { 01534 zero_v3(p1); 01535 zero_v3(p2); 01536 return 0; 01537 } 01538 01539 /* intersect plane */ 01540 if(t > 0.0f) { 01541 madd_v3_v3v3fl(pc, p1, dp, t); 01542 copy_v3_v3(p1, pc); 01543 return 1; 01544 } 01545 01546 return 1; 01547 } 01548 else { 01549 /* behind plane, completely clipped */ 01550 if(t <= 0.0f) { 01551 zero_v3(p1); 01552 zero_v3(p2); 01553 return 0; 01554 } 01555 01556 /* intersect plane */ 01557 if(t < 1.0f) { 01558 madd_v3_v3v3fl(pc, p1, dp, t); 01559 copy_v3_v3(p2, pc); 01560 return 1; 01561 } 01562 01563 return 1; 01564 } 01565 } 01566 01567 01568 void plot_line_v2v2i(const int p1[2], const int p2[2], int (*callback)(int, int, void *), void *userData) 01569 { 01570 int x1= p1[0]; 01571 int y1= p1[1]; 01572 int x2= p2[0]; 01573 int y2= p2[1]; 01574 01575 signed char ix; 01576 signed char iy; 01577 01578 // if x1 == x2 or y1 == y2, then it does not matter what we set here 01579 int delta_x = (x2 > x1?(ix = 1, x2 - x1):(ix = -1, x1 - x2)) << 1; 01580 int delta_y = (y2 > y1?(iy = 1, y2 - y1):(iy = -1, y1 - y2)) << 1; 01581 01582 if(callback(x1, y1, userData) == 0) { 01583 return; 01584 } 01585 01586 if (delta_x >= delta_y) { 01587 // error may go below zero 01588 int error = delta_y - (delta_x >> 1); 01589 01590 while (x1 != x2) { 01591 if (error >= 0) { 01592 if (error || (ix > 0)) { 01593 y1 += iy; 01594 error -= delta_x; 01595 } 01596 // else do nothing 01597 } 01598 // else do nothing 01599 01600 x1 += ix; 01601 error += delta_y; 01602 01603 if(callback(x1, y1, userData) == 0) { 01604 return ; 01605 } 01606 } 01607 } 01608 else { 01609 // error may go below zero 01610 int error = delta_x - (delta_y >> 1); 01611 01612 while (y1 != y2) { 01613 if (error >= 0) { 01614 if (error || (iy > 0)) { 01615 x1 += ix; 01616 error -= delta_y; 01617 } 01618 // else do nothing 01619 } 01620 // else do nothing 01621 01622 y1 += iy; 01623 error += delta_x; 01624 01625 if(callback(x1, y1, userData) == 0) { 01626 return; 01627 } 01628 } 01629 } 01630 } 01631 01632 /****************************** Interpolation ********************************/ 01633 01634 static float tri_signed_area(const float v1[3], const float v2[3], const float v3[3], const int i, const int j) 01635 { 01636 return 0.5f*((v1[i]-v2[i])*(v2[j]-v3[j]) + (v1[j]-v2[j])*(v3[i]-v2[i])); 01637 } 01638 01639 static int barycentric_weights(const float v1[3], const float v2[3], const float v3[3], const float co[3], const float n[3], float w[3]) 01640 { 01641 float xn, yn, zn, a1, a2, a3, asum; 01642 short i, j; 01643 01644 /* find best projection of face XY, XZ or YZ: barycentric weights of 01645 the 2d projected coords are the same and faster to compute */ 01646 xn= (float)fabs(n[0]); 01647 yn= (float)fabs(n[1]); 01648 zn= (float)fabs(n[2]); 01649 if(zn>=xn && zn>=yn) {i= 0; j= 1;} 01650 else if(yn>=xn && yn>=zn) {i= 0; j= 2;} 01651 else {i= 1; j= 2;} 01652 01653 a1= tri_signed_area(v2, v3, co, i, j); 01654 a2= tri_signed_area(v3, v1, co, i, j); 01655 a3= tri_signed_area(v1, v2, co, i, j); 01656 01657 asum= a1 + a2 + a3; 01658 01659 if (fabsf(asum) < FLT_EPSILON) { 01660 /* zero area triangle */ 01661 w[0]= w[1]= w[2]= 1.0f/3.0f; 01662 return 1; 01663 } 01664 01665 asum= 1.0f/asum; 01666 w[0]= a1*asum; 01667 w[1]= a2*asum; 01668 w[2]= a3*asum; 01669 01670 return 0; 01671 } 01672 01673 void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) 01674 { 01675 float w2[3]; 01676 01677 w[0]= w[1]= w[2]= w[3]= 0.0f; 01678 01679 /* first check for exact match */ 01680 if(equals_v3v3(co, v1)) 01681 w[0]= 1.0f; 01682 else if(equals_v3v3(co, v2)) 01683 w[1]= 1.0f; 01684 else if(equals_v3v3(co, v3)) 01685 w[2]= 1.0f; 01686 else if(v4 && equals_v3v3(co, v4)) 01687 w[3]= 1.0f; 01688 else { 01689 /* otherwise compute barycentric interpolation weights */ 01690 float n1[3], n2[3], n[3]; 01691 int degenerate; 01692 01693 sub_v3_v3v3(n1, v1, v3); 01694 if (v4) { 01695 sub_v3_v3v3(n2, v2, v4); 01696 } 01697 else { 01698 sub_v3_v3v3(n2, v2, v3); 01699 } 01700 cross_v3_v3v3(n, n1, n2); 01701 01702 /* OpenGL seems to split this way, so we do too */ 01703 if (v4) { 01704 degenerate= barycentric_weights(v1, v2, v4, co, n, w); 01705 SWAP(float, w[2], w[3]); 01706 01707 if(degenerate || (w[0] < 0.0f)) { 01708 /* if w[1] is negative, co is on the other side of the v1-v3 edge, 01709 so we interpolate using the other triangle */ 01710 degenerate= barycentric_weights(v2, v3, v4, co, n, w2); 01711 01712 if(!degenerate) { 01713 w[0]= 0.0f; 01714 w[1]= w2[0]; 01715 w[2]= w2[1]; 01716 w[3]= w2[2]; 01717 } 01718 } 01719 } 01720 else 01721 barycentric_weights(v1, v2, v3, co, n, w); 01722 } 01723 } 01724 01725 /* used by projection painting 01726 * note: using area_tri_signed_v2 means locations outside the triangle are correctly weighted */ 01727 void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) 01728 { 01729 float wtot_inv, wtot; 01730 01731 w[0] = area_tri_signed_v2(v2, v3, co); 01732 w[1] = area_tri_signed_v2(v3, v1, co); 01733 w[2] = area_tri_signed_v2(v1, v2, co); 01734 wtot = w[0]+w[1]+w[2]; 01735 01736 if (wtot != 0.0f) { 01737 wtot_inv = 1.0f/wtot; 01738 01739 w[0] = w[0]*wtot_inv; 01740 w[1] = w[1]*wtot_inv; 01741 w[2] = w[2]*wtot_inv; 01742 } 01743 else /* dummy values for zero area face */ 01744 w[0] = w[1] = w[2] = 1.0f/3.0f; 01745 } 01746 01747 /* given 2 triangles in 3D space, and a point in relation to the first triangle. 01748 * calculate the location of a point in relation to the second triangle. 01749 * Useful for finding relative positions with geometry */ 01750 void barycentric_transform(float pt_tar[3], float const pt_src[3], 01751 const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], 01752 const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]) 01753 { 01754 /* this works by moving the source triangle so its normal is pointing on the Z 01755 * axis where its barycentric wights can be calculated in 2D and its Z offset can 01756 * be re-applied. The weights are applied directly to the targets 3D points and the 01757 * z-depth is used to scale the targets normal as an offset. 01758 * This saves transforming the target into its Z-Up orientation and back (which could also work) */ 01759 const float z_up[3] = {0, 0, 1}; 01760 float no_tar[3], no_src[3]; 01761 float quat_src[4]; 01762 float pt_src_xy[3]; 01763 float tri_xy_src[3][3]; 01764 float w_src[3]; 01765 float area_tar, area_src; 01766 float z_ofs_src; 01767 01768 normal_tri_v3(no_tar, tri_tar_p1, tri_tar_p2, tri_tar_p3); 01769 normal_tri_v3(no_src, tri_src_p1, tri_src_p2, tri_src_p3); 01770 01771 rotation_between_vecs_to_quat(quat_src, no_src, z_up); 01772 normalize_qt(quat_src); 01773 01774 copy_v3_v3(pt_src_xy, pt_src); 01775 copy_v3_v3(tri_xy_src[0], tri_src_p1); 01776 copy_v3_v3(tri_xy_src[1], tri_src_p2); 01777 copy_v3_v3(tri_xy_src[2], tri_src_p3); 01778 01779 /* make the source tri xy space */ 01780 mul_qt_v3(quat_src, pt_src_xy); 01781 mul_qt_v3(quat_src, tri_xy_src[0]); 01782 mul_qt_v3(quat_src, tri_xy_src[1]); 01783 mul_qt_v3(quat_src, tri_xy_src[2]); 01784 01785 barycentric_weights_v2(tri_xy_src[0], tri_xy_src[1], tri_xy_src[2], pt_src_xy, w_src); 01786 interp_v3_v3v3v3(pt_tar, tri_tar_p1, tri_tar_p2, tri_tar_p3, w_src); 01787 01788 area_tar= sqrtf(area_tri_v3(tri_tar_p1, tri_tar_p2, tri_tar_p3)); 01789 area_src= sqrtf(area_tri_v2(tri_xy_src[0], tri_xy_src[1], tri_xy_src[2])); 01790 01791 z_ofs_src= pt_src_xy[2] - tri_xy_src[0][2]; 01792 madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar); 01793 } 01794 01795 /* given an array with some invalid values this function interpolates valid values 01796 * replacing the invalid ones */ 01797 int interp_sparse_array(float *array, int const list_size, const float skipval) 01798 { 01799 int found_invalid = 0; 01800 int found_valid = 0; 01801 int i; 01802 01803 for (i=0; i < list_size; i++) { 01804 if(array[i] == skipval) 01805 found_invalid= 1; 01806 else 01807 found_valid= 1; 01808 } 01809 01810 if(found_valid==0) { 01811 return -1; 01812 } 01813 else if (found_invalid==0) { 01814 return 0; 01815 } 01816 else { 01817 /* found invalid depths, interpolate */ 01818 float valid_last= skipval; 01819 int valid_ofs= 0; 01820 01821 float *array_up= MEM_callocN(sizeof(float) * list_size, "interp_sparse_array up"); 01822 float *array_down= MEM_callocN(sizeof(float) * list_size, "interp_sparse_array up"); 01823 01824 int *ofs_tot_up= MEM_callocN(sizeof(int) * list_size, "interp_sparse_array tup"); 01825 int *ofs_tot_down= MEM_callocN(sizeof(int) * list_size, "interp_sparse_array tdown"); 01826 01827 for (i=0; i < list_size; i++) { 01828 if(array[i] == skipval) { 01829 array_up[i]= valid_last; 01830 ofs_tot_up[i]= ++valid_ofs; 01831 } 01832 else { 01833 valid_last= array[i]; 01834 valid_ofs= 0; 01835 } 01836 } 01837 01838 valid_last= skipval; 01839 valid_ofs= 0; 01840 01841 for (i=list_size-1; i >= 0; i--) { 01842 if(array[i] == skipval) { 01843 array_down[i]= valid_last; 01844 ofs_tot_down[i]= ++valid_ofs; 01845 } 01846 else { 01847 valid_last= array[i]; 01848 valid_ofs= 0; 01849 } 01850 } 01851 01852 /* now blend */ 01853 for (i=0; i < list_size; i++) { 01854 if(array[i] == skipval) { 01855 if(array_up[i] != skipval && array_down[i] != skipval) { 01856 array[i]= ((array_up[i] * ofs_tot_down[i]) + (array_down[i] * ofs_tot_up[i])) / (float)(ofs_tot_down[i] + ofs_tot_up[i]); 01857 } else if (array_up[i] != skipval) { 01858 array[i]= array_up[i]; 01859 } else if (array_down[i] != skipval) { 01860 array[i]= array_down[i]; 01861 } 01862 } 01863 } 01864 01865 MEM_freeN(array_up); 01866 MEM_freeN(array_down); 01867 01868 MEM_freeN(ofs_tot_up); 01869 MEM_freeN(ofs_tot_down); 01870 } 01871 01872 return 1; 01873 } 01874 01875 /* Mean value weights - smooth interpolation weights for polygons with 01876 * more than 3 vertices */ 01877 static float mean_value_half_tan(const float v1[3], const float v2[3], const float v3[3]) 01878 { 01879 float d2[3], d3[3], cross[3], area, dot, len; 01880 01881 sub_v3_v3v3(d2, v2, v1); 01882 sub_v3_v3v3(d3, v3, v1); 01883 cross_v3_v3v3(cross, d2, d3); 01884 01885 area= len_v3(cross); 01886 dot= dot_v3v3(d2, d3); 01887 len= len_v3(d2)*len_v3(d3); 01888 01889 if(area == 0.0f) 01890 return 0.0f; 01891 else 01892 return (len - dot)/area; 01893 } 01894 01895 void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) 01896 { 01897 float totweight, t1, t2, len, *vmid, *vprev, *vnext; 01898 int i; 01899 01900 totweight= 0.0f; 01901 01902 for(i=0; i<n; i++) { 01903 vmid= v[i]; 01904 vprev= (i == 0)? v[n-1]: v[i-1]; 01905 vnext= (i == n-1)? v[0]: v[i+1]; 01906 01907 t1= mean_value_half_tan(co, vprev, vmid); 01908 t2= mean_value_half_tan(co, vmid, vnext); 01909 01910 len= len_v3v3(co, vmid); 01911 w[i]= (t1+t2)/len; 01912 totweight += w[i]; 01913 } 01914 01915 if(totweight != 0.0f) 01916 for(i=0; i<n; i++) 01917 w[i] /= totweight; 01918 } 01919 01920 /* (x1,v1)(t1=0)------(x2,v2)(t2=1), 0<t<1 --> (x,v)(t) */ 01921 void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) 01922 { 01923 float a[3],b[3]; 01924 float t2= t*t; 01925 float t3= t2*t; 01926 01927 /* cubic interpolation */ 01928 a[0]= v1[0] + v2[0] + 2*(x1[0] - x2[0]); 01929 a[1]= v1[1] + v2[1] + 2*(x1[1] - x2[1]); 01930 a[2]= v1[2] + v2[2] + 2*(x1[2] - x2[2]); 01931 01932 b[0]= -2*v1[0] - v2[0] - 3*(x1[0] - x2[0]); 01933 b[1]= -2*v1[1] - v2[1] - 3*(x1[1] - x2[1]); 01934 b[2]= -2*v1[2] - v2[2] - 3*(x1[2] - x2[2]); 01935 01936 x[0]= a[0]*t3 + b[0]*t2 + v1[0]*t + x1[0]; 01937 x[1]= a[1]*t3 + b[1]*t2 + v1[1]*t + x1[1]; 01938 x[2]= a[2]*t3 + b[2]*t2 + v1[2]*t + x1[2]; 01939 01940 v[0]= 3*a[0]*t2 + 2*b[0]*t + v1[0]; 01941 v[1]= 3*a[1]*t2 + 2*b[1]*t + v1[1]; 01942 v[2]= 3*a[2]*t2 + 2*b[2]*t + v1[2]; 01943 } 01944 01945 /* unfortunately internal calculations have to be done at double precision to achieve correct/stable results. */ 01946 01947 #define IS_ZERO(x) ((x>(-DBL_EPSILON) && x<DBL_EPSILON) ? 1 : 0) 01948 01949 /* Barycentric reverse */ 01950 void resolve_tri_uv(float uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2]) 01951 { 01952 /* find UV such that 01953 t= u*t0 + v*t1 + (1-u-v)*t2 01954 u*(t0-t2) + v*(t1-t2)= t-t2 */ 01955 const double a= st0[0]-st2[0], b= st1[0]-st2[0]; 01956 const double c= st0[1]-st2[1], d= st1[1]-st2[1]; 01957 const double det= a*d - c*b; 01958 01959 if(IS_ZERO(det)==0) { /* det should never be zero since the determinant is the signed ST area of the triangle. */ 01960 const double x[]= {st[0]-st2[0], st[1]-st2[1]}; 01961 01962 uv[0]= (float)((d*x[0] - b*x[1])/det); 01963 uv[1]= (float)(((-c)*x[0] + a*x[1])/det); 01964 } else zero_v2(uv); 01965 } 01966 01967 /* bilinear reverse */ 01968 void resolve_quad_uv(float uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]) 01969 { 01970 const double signed_area= (st0[0]*st1[1] - st0[1]*st1[0]) + (st1[0]*st2[1] - st1[1]*st2[0]) + 01971 (st2[0]*st3[1] - st2[1]*st3[0]) + (st3[0]*st0[1] - st3[1]*st0[0]); 01972 01973 /* X is 2D cross product (determinant) 01974 A= (p0-p) X (p0-p3)*/ 01975 const double a= (st0[0]-st[0])*(st0[1]-st3[1]) - (st0[1]-st[1])*(st0[0]-st3[0]); 01976 01977 /* B= ( (p0-p) X (p1-p2) + (p1-p) X (p0-p3) ) / 2 */ 01978 const double b= 0.5 * ( ((st0[0]-st[0])*(st1[1]-st2[1]) - (st0[1]-st[1])*(st1[0]-st2[0])) + 01979 ((st1[0]-st[0])*(st0[1]-st3[1]) - (st1[1]-st[1])*(st0[0]-st3[0])) ); 01980 01981 /* C = (p1-p) X (p1-p2) */ 01982 const double fC= (st1[0]-st[0])*(st1[1]-st2[1]) - (st1[1]-st[1])*(st1[0]-st2[0]); 01983 const double denom= a - 2*b + fC; 01984 01985 // clear outputs 01986 zero_v2(uv); 01987 01988 if(IS_ZERO(denom)!=0) { 01989 const double fDen= a-fC; 01990 if(IS_ZERO(fDen)==0) 01991 uv[0]= (float)(a / fDen); 01992 } else { 01993 const double desc_sq= b*b - a*fC; 01994 const double desc= sqrt(desc_sq<0.0?0.0:desc_sq); 01995 const double s= signed_area>0 ? (-1.0) : 1.0; 01996 01997 uv[0]= (float)(( (a-b) + s * desc ) / denom); 01998 } 01999 02000 /* find UV such that 02001 fST = (1-u)(1-v)*ST0 + u*(1-v)*ST1 + u*v*ST2 + (1-u)*v*ST3 */ 02002 { 02003 const double denom_s= (1-uv[0])*(st0[0]-st3[0]) + uv[0]*(st1[0]-st2[0]); 02004 const double denom_t= (1-uv[0])*(st0[1]-st3[1]) + uv[0]*(st1[1]-st2[1]); 02005 int i= 0; double denom= denom_s; 02006 02007 if(fabs(denom_s)<fabs(denom_t)) { 02008 i= 1; 02009 denom=denom_t; 02010 } 02011 02012 if(IS_ZERO(denom)==0) 02013 uv[1]= (float) (( (1-uv[0])*(st0[i]-st[i]) + uv[0]*(st1[i]-st[i]) ) / denom); 02014 } 02015 } 02016 02017 #undef IS_ZERO 02018 02019 /***************************** View & Projection *****************************/ 02020 02021 void orthographic_m4(float matrix[][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) 02022 { 02023 float Xdelta, Ydelta, Zdelta; 02024 02025 Xdelta = right - left; 02026 Ydelta = top - bottom; 02027 Zdelta = farClip - nearClip; 02028 if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) { 02029 return; 02030 } 02031 unit_m4(matrix); 02032 matrix[0][0] = 2.0f/Xdelta; 02033 matrix[3][0] = -(right + left)/Xdelta; 02034 matrix[1][1] = 2.0f/Ydelta; 02035 matrix[3][1] = -(top + bottom)/Ydelta; 02036 matrix[2][2] = -2.0f/Zdelta; /* note: negate Z */ 02037 matrix[3][2] = -(farClip + nearClip)/Zdelta; 02038 } 02039 02040 void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) 02041 { 02042 float Xdelta, Ydelta, Zdelta; 02043 02044 Xdelta = right - left; 02045 Ydelta = top - bottom; 02046 Zdelta = farClip - nearClip; 02047 02048 if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) { 02049 return; 02050 } 02051 mat[0][0] = nearClip * 2.0f/Xdelta; 02052 mat[1][1] = nearClip * 2.0f/Ydelta; 02053 mat[2][0] = (right + left)/Xdelta; /* note: negate Z */ 02054 mat[2][1] = (top + bottom)/Ydelta; 02055 mat[2][2] = -(farClip + nearClip)/Zdelta; 02056 mat[2][3] = -1.0f; 02057 mat[3][2] = (-2.0f * nearClip * farClip)/Zdelta; 02058 mat[0][1] = mat[0][2] = mat[0][3] = 02059 mat[1][0] = mat[1][2] = mat[1][3] = 02060 mat[3][0] = mat[3][1] = mat[3][3] = 0.0; 02061 02062 } 02063 02064 /* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords (used to jitter the view) */ 02065 void window_translate_m4(float winmat[][4], float perspmat[][4], const float x, const float y) 02066 { 02067 if(winmat[2][3] == -1.0f) { 02068 /* in the case of a win-matrix, this means perspective always */ 02069 float v1[3]; 02070 float v2[3]; 02071 float len1, len2; 02072 02073 v1[0]= perspmat[0][0]; 02074 v1[1]= perspmat[1][0]; 02075 v1[2]= perspmat[2][0]; 02076 02077 v2[0]= perspmat[0][1]; 02078 v2[1]= perspmat[1][1]; 02079 v2[2]= perspmat[2][1]; 02080 02081 len1= (1.0f / len_v3(v1)); 02082 len2= (1.0f / len_v3(v2)); 02083 02084 winmat[2][0] += len1 * winmat[0][0] * x; 02085 winmat[2][1] += len2 * winmat[1][1] * y; 02086 } 02087 else { 02088 winmat[3][0] += x; 02089 winmat[3][1] += y; 02090 } 02091 } 02092 02093 static void i_multmatrix(float icand[][4], float Vm[][4]) 02094 { 02095 int row, col; 02096 float temp[4][4]; 02097 02098 for(row=0 ; row<4 ; row++) 02099 for(col=0 ; col<4 ; col++) 02100 temp[row][col] = icand[row][0] * Vm[0][col] 02101 + icand[row][1] * Vm[1][col] 02102 + icand[row][2] * Vm[2][col] 02103 + icand[row][3] * Vm[3][col]; 02104 copy_m4_m4(Vm, temp); 02105 } 02106 02107 02108 void polarview_m4(float Vm[][4],float dist, float azimuth, float incidence, float twist) 02109 { 02110 02111 unit_m4(Vm); 02112 02113 translate_m4(Vm,0.0, 0.0, -dist); 02114 rotate_m4(Vm,'Z',-twist); 02115 rotate_m4(Vm,'X',-incidence); 02116 rotate_m4(Vm,'Z',-azimuth); 02117 } 02118 02119 void lookat_m4(float mat[][4],float vx, float vy, float vz, float px, float py, float pz, float twist) 02120 { 02121 float sine, cosine, hyp, hyp1, dx, dy, dz; 02122 float mat1[4][4]= MAT4_UNITY; 02123 02124 unit_m4(mat); 02125 02126 rotate_m4(mat, 'Z', -twist); 02127 02128 dx = px - vx; 02129 dy = py - vy; 02130 dz = pz - vz; 02131 hyp = dx * dx + dz * dz; /* hyp squared */ 02132 hyp1 = (float)sqrt(dy*dy + hyp); 02133 hyp = (float)sqrt(hyp); /* the real hyp */ 02134 02135 if (hyp1 != 0.0f) { /* rotate X */ 02136 sine = -dy / hyp1; 02137 cosine = hyp /hyp1; 02138 } else { 02139 sine = 0; 02140 cosine = 1.0f; 02141 } 02142 mat1[1][1] = cosine; 02143 mat1[1][2] = sine; 02144 mat1[2][1] = -sine; 02145 mat1[2][2] = cosine; 02146 02147 i_multmatrix(mat1, mat); 02148 02149 mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ 02150 mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */ 02151 02152 /* paragraph */ 02153 if (hyp != 0.0f) { /* rotate Y */ 02154 sine = dx / hyp; 02155 cosine = -dz / hyp; 02156 } else { 02157 sine = 0; 02158 cosine = 1.0f; 02159 } 02160 mat1[0][0] = cosine; 02161 mat1[0][2] = -sine; 02162 mat1[2][0] = sine; 02163 mat1[2][2] = cosine; 02164 02165 i_multmatrix(mat1, mat); 02166 translate_m4(mat,-vx,-vy,-vz); /* translate viewpoint to origin */ 02167 } 02168 02169 int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]) 02170 { 02171 float mat[4][4], vec[4]; 02172 int a, fl, flag= -1; 02173 02174 copy_m4_m4(mat, winmat); 02175 02176 for(a=0; a<8; a++) { 02177 vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0]; 02178 vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1]; 02179 vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2]; 02180 vec[3]= 1.0; 02181 mul_m4_v4(mat, vec); 02182 02183 fl= 0; 02184 if(bounds) { 02185 if(vec[0] > bounds[1]*vec[3]) fl |= 1; 02186 if(vec[0]< bounds[0]*vec[3]) fl |= 2; 02187 if(vec[1] > bounds[3]*vec[3]) fl |= 4; 02188 if(vec[1]< bounds[2]*vec[3]) fl |= 8; 02189 } 02190 else { 02191 if(vec[0] < -vec[3]) fl |= 1; 02192 if(vec[0] > vec[3]) fl |= 2; 02193 if(vec[1] < -vec[3]) fl |= 4; 02194 if(vec[1] > vec[3]) fl |= 8; 02195 } 02196 if(vec[2] < -vec[3]) fl |= 16; 02197 if(vec[2] > vec[3]) fl |= 32; 02198 02199 flag &= fl; 02200 if(flag==0) return 0; 02201 } 02202 02203 return flag; 02204 } 02205 02206 void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4]) 02207 { 02208 float mn[3], mx[3], vec[3]; 02209 int a; 02210 02211 copy_v3_v3(mn, min); 02212 copy_v3_v3(mx, max); 02213 02214 for(a=0; a<8; a++) { 02215 vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0]; 02216 vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1]; 02217 vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2]; 02218 02219 mul_m4_v3(mat, vec); 02220 DO_MINMAX(vec, mn, mx); 02221 } 02222 02223 copy_v3_v3(min, mn); 02224 copy_v3_v3(max, mx); 02225 } 02226 02227 /********************************** Mapping **********************************/ 02228 02229 void map_to_tube(float *u, float *v, const float x, const float y, const float z) 02230 { 02231 float len; 02232 02233 *v = (z + 1.0f) / 2.0f; 02234 02235 len= (float)sqrt(x*x+y*y); 02236 if(len > 0.0f) 02237 *u = (float)((1.0 - (atan2(x/len,y/len) / M_PI)) / 2.0); 02238 else 02239 *v = *u = 0.0f; /* to avoid un-initialized variables */ 02240 } 02241 02242 void map_to_sphere(float *u, float *v, const float x, const float y, const float z) 02243 { 02244 float len; 02245 02246 len= (float)sqrt(x*x+y*y+z*z); 02247 if(len > 0.0f) { 02248 if(x==0.0f && y==0.0f) *u= 0.0f; /* othwise domain error */ 02249 else *u = (1.0f - atan2f(x,y) / (float)M_PI) / 2.0f; 02250 02251 *v = 1.0f - (float)saacos(z/len)/(float)M_PI; 02252 } else { 02253 *v = *u = 0.0f; /* to avoid un-initialized variables */ 02254 } 02255 } 02256 02257 /********************************* Normals **********************************/ 02258 02259 void accumulate_vertex_normals(float n1[3], float n2[3], float n3[3], 02260 float n4[3], const float f_no[3], const float co1[3], const float co2[3], 02261 const float co3[3], const float co4[3]) 02262 { 02263 float vdiffs[4][3]; 02264 const int nverts= (n4!=NULL && co4!=NULL)? 4: 3; 02265 02266 /* compute normalized edge vectors */ 02267 sub_v3_v3v3(vdiffs[0], co2, co1); 02268 sub_v3_v3v3(vdiffs[1], co3, co2); 02269 02270 if(nverts==3) { 02271 sub_v3_v3v3(vdiffs[2], co1, co3); 02272 } 02273 else { 02274 sub_v3_v3v3(vdiffs[2], co4, co3); 02275 sub_v3_v3v3(vdiffs[3], co1, co4); 02276 normalize_v3(vdiffs[3]); 02277 } 02278 02279 normalize_v3(vdiffs[0]); 02280 normalize_v3(vdiffs[1]); 02281 normalize_v3(vdiffs[2]); 02282 02283 /* accumulate angle weighted face normal */ 02284 { 02285 float *vn[]= {n1, n2, n3, n4}; 02286 const float *prev_edge = vdiffs[nverts-1]; 02287 int i; 02288 02289 for(i=0; i<nverts; i++) { 02290 const float *cur_edge= vdiffs[i]; 02291 const float fac= saacos(-dot_v3v3(cur_edge, prev_edge)); 02292 02293 // accumulate 02294 madd_v3_v3fl(vn[i], f_no, fac); 02295 prev_edge = cur_edge; 02296 } 02297 } 02298 } 02299 02300 /********************************* Tangents **********************************/ 02301 02302 /* For normal map tangents we need to detect uv boundaries, and only average 02303 * tangents in case the uvs are connected. Alternative would be to store 1 02304 * tangent per face rather than 4 per face vertex, but that's not compatible 02305 * with games */ 02306 02307 02308 /* from BKE_mesh.h */ 02309 #define STD_UV_CONNECT_LIMIT 0.0001f 02310 02311 void sum_or_add_vertex_tangent(void *arena, VertexTangent **vtang, const float tang[3], const float uv[2]) 02312 { 02313 VertexTangent *vt; 02314 02315 /* find a tangent with connected uvs */ 02316 for(vt= *vtang; vt; vt=vt->next) { 02317 if(fabsf(uv[0]-vt->uv[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-vt->uv[1]) < STD_UV_CONNECT_LIMIT) { 02318 add_v3_v3(vt->tang, tang); 02319 return; 02320 } 02321 } 02322 02323 /* if not found, append a new one */ 02324 vt= BLI_memarena_alloc((MemArena *)arena, sizeof(VertexTangent)); 02325 copy_v3_v3(vt->tang, tang); 02326 vt->uv[0]= uv[0]; 02327 vt->uv[1]= uv[1]; 02328 02329 if(*vtang) 02330 vt->next= *vtang; 02331 *vtang= vt; 02332 } 02333 02334 float *find_vertex_tangent(VertexTangent *vtang, const float uv[2]) 02335 { 02336 VertexTangent *vt; 02337 static float nulltang[3] = {0.0f, 0.0f, 0.0f}; 02338 02339 for(vt= vtang; vt; vt=vt->next) 02340 if(fabsf(uv[0]-vt->uv[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-vt->uv[1]) < STD_UV_CONNECT_LIMIT) 02341 return vt->tang; 02342 02343 return nulltang; /* shouldn't happen, except for nan or so */ 02344 } 02345 02346 void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], float co2[3], float co3[3], float n[3], float tang[3]) 02347 { 02348 float s1= uv2[0] - uv1[0]; 02349 float s2= uv3[0] - uv1[0]; 02350 float t1= uv2[1] - uv1[1]; 02351 float t2= uv3[1] - uv1[1]; 02352 float det= (s1 * t2 - s2 * t1); 02353 02354 if(det != 0.0f) { /* otherwise 'tang' becomes nan */ 02355 float tangv[3], ct[3], e1[3], e2[3]; 02356 02357 det= 1.0f/det; 02358 02359 /* normals in render are inversed... */ 02360 sub_v3_v3v3(e1, co1, co2); 02361 sub_v3_v3v3(e2, co1, co3); 02362 tang[0] = (t2*e1[0] - t1*e2[0])*det; 02363 tang[1] = (t2*e1[1] - t1*e2[1])*det; 02364 tang[2] = (t2*e1[2] - t1*e2[2])*det; 02365 tangv[0] = (s1*e2[0] - s2*e1[0])*det; 02366 tangv[1] = (s1*e2[1] - s2*e1[1])*det; 02367 tangv[2] = (s1*e2[2] - s2*e1[2])*det; 02368 cross_v3_v3v3(ct, tang, tangv); 02369 02370 /* check flip */ 02371 if ((ct[0]*n[0] + ct[1]*n[1] + ct[2]*n[2]) < 0.0f) 02372 negate_v3(tang); 02373 } 02374 else { 02375 tang[0]= tang[1]= tang[2]= 0.0; 02376 } 02377 } 02378 02379 /****************************** Vector Clouds ********************************/ 02380 02381 /* vector clouds */ 02382 /* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight,float (*rpos)[3], float *rweight, 02383 float lloc[3],float rloc[3],float lrot[3][3],float lscale[3][3]) 02384 02385 input 02386 ( 02387 int list_size 02388 4 lists as pointer to array[list_size] 02389 1. current pos array of 'new' positions 02390 2. current weight array of 'new'weights (may be NULL pointer if you have no weights ) 02391 3. reference rpos array of 'old' positions 02392 4. reference rweight array of 'old'weights (may be NULL pointer if you have no weights ) 02393 ) 02394 output 02395 ( 02396 float lloc[3] center of mass pos 02397 float rloc[3] center of mass rpos 02398 float lrot[3][3] rotation matrix 02399 float lscale[3][3] scale matrix 02400 pointers may be NULL if not needed 02401 ) 02402 02403 */ 02404 /* can't believe there is none in math utils */ 02405 static float _det_m3(float m2[3][3]) 02406 { 02407 float det = 0.f; 02408 if (m2){ 02409 det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1]) 02410 -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1]) 02411 +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]); 02412 } 02413 return det; 02414 } 02415 02416 02417 void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight,float (*rpos)[3], float *rweight, 02418 float lloc[3],float rloc[3],float lrot[3][3],float lscale[3][3]) 02419 { 02420 float accu_com[3]= {0.0f,0.0f,0.0f}, accu_rcom[3]= {0.0f,0.0f,0.0f}; 02421 float accu_weight = 0.0f,accu_rweight = 0.0f,eps = 0.000001f; 02422 02423 int a; 02424 /* first set up a nice default response */ 02425 if (lloc) zero_v3(lloc); 02426 if (rloc) zero_v3(rloc); 02427 if (lrot) unit_m3(lrot); 02428 if (lscale) unit_m3(lscale); 02429 /* do com for both clouds */ 02430 if (pos && rpos && (list_size > 0)) /* paranoya check */ 02431 { 02432 /* do com for both clouds */ 02433 for(a=0; a<list_size; a++){ 02434 if (weight){ 02435 float v[3]; 02436 copy_v3_v3(v,pos[a]); 02437 mul_v3_fl(v,weight[a]); 02438 add_v3_v3(accu_com, v); 02439 accu_weight +=weight[a]; 02440 } 02441 else add_v3_v3(accu_com, pos[a]); 02442 02443 if (rweight){ 02444 float v[3]; 02445 copy_v3_v3(v,rpos[a]); 02446 mul_v3_fl(v,rweight[a]); 02447 add_v3_v3(accu_rcom, v); 02448 accu_rweight +=rweight[a]; 02449 } 02450 else add_v3_v3(accu_rcom, rpos[a]); 02451 02452 } 02453 if (!weight || !rweight){ 02454 accu_weight = accu_rweight = list_size; 02455 } 02456 02457 mul_v3_fl(accu_com,1.0f/accu_weight); 02458 mul_v3_fl(accu_rcom,1.0f/accu_rweight); 02459 if (lloc) copy_v3_v3(lloc,accu_com); 02460 if (rloc) copy_v3_v3(rloc,accu_rcom); 02461 if (lrot || lscale){ /* caller does not want rot nor scale, strange but legal */ 02462 /*so now do some reverse engeneering and see if we can split rotation from scale ->Polardecompose*/ 02463 /* build 'projection' matrix */ 02464 float m[3][3],mr[3][3],q[3][3],qi[3][3]; 02465 float va[3],vb[3],stunt[3]; 02466 float odet,ndet; 02467 int i=0,imax=15; 02468 zero_m3(m); 02469 zero_m3(mr); 02470 02471 /* build 'projection' matrix */ 02472 for(a=0; a<list_size; a++){ 02473 sub_v3_v3v3(va,rpos[a],accu_rcom); 02474 /* mul_v3_fl(va,bp->mass); mass needs renormalzation here ?? */ 02475 sub_v3_v3v3(vb,pos[a],accu_com); 02476 /* mul_v3_fl(va,rp->mass); */ 02477 m[0][0] += va[0] * vb[0]; 02478 m[0][1] += va[0] * vb[1]; 02479 m[0][2] += va[0] * vb[2]; 02480 02481 m[1][0] += va[1] * vb[0]; 02482 m[1][1] += va[1] * vb[1]; 02483 m[1][2] += va[1] * vb[2]; 02484 02485 m[2][0] += va[2] * vb[0]; 02486 m[2][1] += va[2] * vb[1]; 02487 m[2][2] += va[2] * vb[2]; 02488 02489 /* building the referenc matrix on the fly 02490 needed to scale properly later*/ 02491 02492 mr[0][0] += va[0] * va[0]; 02493 mr[0][1] += va[0] * va[1]; 02494 mr[0][2] += va[0] * va[2]; 02495 02496 mr[1][0] += va[1] * va[0]; 02497 mr[1][1] += va[1] * va[1]; 02498 mr[1][2] += va[1] * va[2]; 02499 02500 mr[2][0] += va[2] * va[0]; 02501 mr[2][1] += va[2] * va[1]; 02502 mr[2][2] += va[2] * va[2]; 02503 } 02504 copy_m3_m3(q,m); 02505 stunt[0] = q[0][0]; stunt[1] = q[1][1]; stunt[2] = q[2][2]; 02506 /* renormalizing for numeric stability */ 02507 mul_m3_fl(q,1.f/len_v3(stunt)); 02508 02509 /* this is pretty much Polardecompose 'inline' the algo based on Higham's thesis */ 02510 /* without the far case ... but seems to work here pretty neat */ 02511 odet = 0.f; 02512 ndet = _det_m3(q); 02513 while((odet-ndet)*(odet-ndet) > eps && i<imax){ 02514 invert_m3_m3(qi,q); 02515 transpose_m3(qi); 02516 add_m3_m3m3(q,q,qi); 02517 mul_m3_fl(q,0.5f); 02518 odet =ndet; 02519 ndet =_det_m3(q); 02520 i++; 02521 } 02522 02523 if (i){ 02524 float scale[3][3]; 02525 float irot[3][3]; 02526 if(lrot) copy_m3_m3(lrot,q); 02527 invert_m3_m3(irot,q); 02528 invert_m3_m3(qi,mr); 02529 mul_m3_m3m3(q,m,qi); 02530 mul_m3_m3m3(scale,irot,q); 02531 if(lscale) copy_m3_m3(lscale,scale); 02532 02533 } 02534 } 02535 } 02536 } 02537 02538 /******************************* Form Factor *********************************/ 02539 02540 static void vec_add_dir(float r[3], const float v1[3], const float v2[3], const float fac) 02541 { 02542 r[0]= v1[0] + fac*(v2[0] - v1[0]); 02543 r[1]= v1[1] + fac*(v2[1] - v1[1]); 02544 r[2]= v1[2] + fac*(v2[2] - v1[2]); 02545 } 02546 02547 static int ff_visible_quad(const float p[3], const float n[3], const float v0[3], const float v1[3], const float v2[3], float q0[3], float q1[3], float q2[3], float q3[3]) 02548 { 02549 static const float epsilon = 1e-6f; 02550 float c, sd[3]; 02551 02552 c= dot_v3v3(n, p); 02553 02554 /* signed distances from the vertices to the plane. */ 02555 sd[0]= dot_v3v3(n, v0) - c; 02556 sd[1]= dot_v3v3(n, v1) - c; 02557 sd[2]= dot_v3v3(n, v2) - c; 02558 02559 if(fabsf(sd[0]) < epsilon) sd[0] = 0.0f; 02560 if(fabsf(sd[1]) < epsilon) sd[1] = 0.0f; 02561 if(fabsf(sd[2]) < epsilon) sd[2] = 0.0f; 02562 02563 if(sd[0] > 0) { 02564 if(sd[1] > 0) { 02565 if(sd[2] > 0) { 02566 // +++ 02567 copy_v3_v3(q0, v0); 02568 copy_v3_v3(q1, v1); 02569 copy_v3_v3(q2, v2); 02570 copy_v3_v3(q3, q2); 02571 } 02572 else if(sd[2] < 0) { 02573 // ++- 02574 copy_v3_v3(q0, v0); 02575 copy_v3_v3(q1, v1); 02576 vec_add_dir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02577 vec_add_dir(q3, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02578 } 02579 else { 02580 // ++0 02581 copy_v3_v3(q0, v0); 02582 copy_v3_v3(q1, v1); 02583 copy_v3_v3(q2, v2); 02584 copy_v3_v3(q3, q2); 02585 } 02586 } 02587 else if(sd[1] < 0) { 02588 if(sd[2] > 0) { 02589 // +-+ 02590 copy_v3_v3(q0, v0); 02591 vec_add_dir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02592 vec_add_dir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02593 copy_v3_v3(q3, v2); 02594 } 02595 else if(sd[2] < 0) { 02596 // +-- 02597 copy_v3_v3(q0, v0); 02598 vec_add_dir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02599 vec_add_dir(q2, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02600 copy_v3_v3(q3, q2); 02601 } 02602 else { 02603 // +-0 02604 copy_v3_v3(q0, v0); 02605 vec_add_dir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02606 copy_v3_v3(q2, v2); 02607 copy_v3_v3(q3, q2); 02608 } 02609 } 02610 else { 02611 if(sd[2] > 0) { 02612 // +0+ 02613 copy_v3_v3(q0, v0); 02614 copy_v3_v3(q1, v1); 02615 copy_v3_v3(q2, v2); 02616 copy_v3_v3(q3, q2); 02617 } 02618 else if(sd[2] < 0) { 02619 // +0- 02620 copy_v3_v3(q0, v0); 02621 copy_v3_v3(q1, v1); 02622 vec_add_dir(q2, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02623 copy_v3_v3(q3, q2); 02624 } 02625 else { 02626 // +00 02627 copy_v3_v3(q0, v0); 02628 copy_v3_v3(q1, v1); 02629 copy_v3_v3(q2, v2); 02630 copy_v3_v3(q3, q2); 02631 } 02632 } 02633 } 02634 else if(sd[0] < 0) { 02635 if(sd[1] > 0) { 02636 if(sd[2] > 0) { 02637 // -++ 02638 vec_add_dir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02639 copy_v3_v3(q1, v1); 02640 copy_v3_v3(q2, v2); 02641 vec_add_dir(q3, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02642 } 02643 else if(sd[2] < 0) { 02644 // -+- 02645 vec_add_dir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02646 copy_v3_v3(q1, v1); 02647 vec_add_dir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02648 copy_v3_v3(q3, q2); 02649 } 02650 else { 02651 // -+0 02652 vec_add_dir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 02653 copy_v3_v3(q1, v1); 02654 copy_v3_v3(q2, v2); 02655 copy_v3_v3(q3, q2); 02656 } 02657 } 02658 else if(sd[1] < 0) { 02659 if(sd[2] > 0) { 02660 // --+ 02661 vec_add_dir(q0, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02662 vec_add_dir(q1, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02663 copy_v3_v3(q2, v2); 02664 copy_v3_v3(q3, q2); 02665 } 02666 else if(sd[2] < 0) { 02667 // --- 02668 return 0; 02669 } 02670 else { 02671 // --0 02672 return 0; 02673 } 02674 } 02675 else { 02676 if(sd[2] > 0) { 02677 // -0+ 02678 vec_add_dir(q0, v0, v2, (sd[0]/(sd[0]-sd[2]))); 02679 copy_v3_v3(q1, v1); 02680 copy_v3_v3(q2, v2); 02681 copy_v3_v3(q3, q2); 02682 } 02683 else if(sd[2] < 0) { 02684 // -0- 02685 return 0; 02686 } 02687 else { 02688 // -00 02689 return 0; 02690 } 02691 } 02692 } 02693 else { 02694 if(sd[1] > 0) { 02695 if(sd[2] > 0) { 02696 // 0++ 02697 copy_v3_v3(q0, v0); 02698 copy_v3_v3(q1, v1); 02699 copy_v3_v3(q2, v2); 02700 copy_v3_v3(q3, q2); 02701 } 02702 else if(sd[2] < 0) { 02703 // 0+- 02704 copy_v3_v3(q0, v0); 02705 copy_v3_v3(q1, v1); 02706 vec_add_dir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02707 copy_v3_v3(q3, q2); 02708 } 02709 else { 02710 // 0+0 02711 copy_v3_v3(q0, v0); 02712 copy_v3_v3(q1, v1); 02713 copy_v3_v3(q2, v2); 02714 copy_v3_v3(q3, q2); 02715 } 02716 } 02717 else if(sd[1] < 0) { 02718 if(sd[2] > 0) { 02719 // 0-+ 02720 copy_v3_v3(q0, v0); 02721 vec_add_dir(q1, v1, v2, (sd[1]/(sd[1]-sd[2]))); 02722 copy_v3_v3(q2, v2); 02723 copy_v3_v3(q3, q2); 02724 } 02725 else if(sd[2] < 0) { 02726 // 0-- 02727 return 0; 02728 } 02729 else { 02730 // 0-0 02731 return 0; 02732 } 02733 } 02734 else { 02735 if(sd[2] > 0) { 02736 // 00+ 02737 copy_v3_v3(q0, v0); 02738 copy_v3_v3(q1, v1); 02739 copy_v3_v3(q2, v2); 02740 copy_v3_v3(q3, q2); 02741 } 02742 else if(sd[2] < 0) { 02743 // 00- 02744 return 0; 02745 } 02746 else { 02747 // 000 02748 return 0; 02749 } 02750 } 02751 } 02752 02753 return 1; 02754 } 02755 02756 /* altivec optimization, this works, but is unused */ 02757 02758 #if 0 02759 #include <Accelerate/Accelerate.h> 02760 02761 typedef union { 02762 vFloat v; 02763 float f[4]; 02764 } vFloatResult; 02765 02766 static vFloat vec_splat_float(float val) 02767 { 02768 return (vFloat){val, val, val, val}; 02769 } 02770 02771 static float ff_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3) 02772 { 02773 vFloat vcos, rlen, vrx, vry, vrz, vsrx, vsry, vsrz, gx, gy, gz, vangle; 02774 vUInt8 rotate = (vUInt8){4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3}; 02775 vFloatResult vresult; 02776 float result; 02777 02778 /* compute r* */ 02779 vrx = (vFloat){q0[0], q1[0], q2[0], q3[0]} - vec_splat_float(p[0]); 02780 vry = (vFloat){q0[1], q1[1], q2[1], q3[1]} - vec_splat_float(p[1]); 02781 vrz = (vFloat){q0[2], q1[2], q2[2], q3[2]} - vec_splat_float(p[2]); 02782 02783 /* normalize r* */ 02784 rlen = vec_rsqrte(vrx*vrx + vry*vry + vrz*vrz + vec_splat_float(1e-16f)); 02785 vrx = vrx*rlen; 02786 vry = vry*rlen; 02787 vrz = vrz*rlen; 02788 02789 /* rotate r* for cross and dot */ 02790 vsrx= vec_perm(vrx, vrx, rotate); 02791 vsry= vec_perm(vry, vry, rotate); 02792 vsrz= vec_perm(vrz, vrz, rotate); 02793 02794 /* cross product */ 02795 gx = vsry*vrz - vsrz*vry; 02796 gy = vsrz*vrx - vsrx*vrz; 02797 gz = vsrx*vry - vsry*vrx; 02798 02799 /* normalize */ 02800 rlen = vec_rsqrte(gx*gx + gy*gy + gz*gz + vec_splat_float(1e-16f)); 02801 gx = gx*rlen; 02802 gy = gy*rlen; 02803 gz = gz*rlen; 02804 02805 /* angle */ 02806 vcos = vrx*vsrx + vry*vsry + vrz*vsrz; 02807 vcos= vec_max(vec_min(vcos, vec_splat_float(1.0f)), vec_splat_float(-1.0f)); 02808 vangle= vacosf(vcos); 02809 02810 /* dot */ 02811 vresult.v = (vec_splat_float(n[0])*gx + 02812 vec_splat_float(n[1])*gy + 02813 vec_splat_float(n[2])*gz)*vangle; 02814 02815 result= (vresult.f[0] + vresult.f[1] + vresult.f[2] + vresult.f[3])*(0.5f/(float)M_PI); 02816 result= MAX2(result, 0.0f); 02817 02818 return result; 02819 } 02820 02821 #endif 02822 02823 /* SSE optimization, acos code doesn't work */ 02824 02825 #if 0 02826 02827 #include <xmmintrin.h> 02828 02829 static __m128 sse_approx_acos(__m128 x) 02830 { 02831 /* needs a better approximation than taylor expansion of acos, since that 02832 * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work 02833 * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */ 02834 02835 return _mm_set_ps1(1.0f); 02836 } 02837 02838 static float ff_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3) 02839 { 02840 float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3]; 02841 float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result; 02842 float fresult[4] __attribute__((aligned(16))); 02843 __m128 qx, qy, qz, rx, ry, rz, rlen, srx, sry, srz, gx, gy, gz, glen, rcos, angle, aresult; 02844 02845 /* compute r */ 02846 qx = _mm_set_ps(q3[0], q2[0], q1[0], q0[0]); 02847 qy = _mm_set_ps(q3[1], q2[1], q1[1], q0[1]); 02848 qz = _mm_set_ps(q3[2], q2[2], q1[2], q0[2]); 02849 02850 rx = qx - _mm_set_ps1(p[0]); 02851 ry = qy - _mm_set_ps1(p[1]); 02852 rz = qz - _mm_set_ps1(p[2]); 02853 02854 /* normalize r */ 02855 rlen = _mm_rsqrt_ps(rx*rx + ry*ry + rz*rz + _mm_set_ps1(1e-16f)); 02856 rx = rx*rlen; 02857 ry = ry*rlen; 02858 rz = rz*rlen; 02859 02860 /* cross product */ 02861 srx = _mm_shuffle_ps(rx, rx, _MM_SHUFFLE(0,3,2,1)); 02862 sry = _mm_shuffle_ps(ry, ry, _MM_SHUFFLE(0,3,2,1)); 02863 srz = _mm_shuffle_ps(rz, rz, _MM_SHUFFLE(0,3,2,1)); 02864 02865 gx = sry*rz - srz*ry; 02866 gy = srz*rx - srx*rz; 02867 gz = srx*ry - sry*rx; 02868 02869 /* normalize g */ 02870 glen = _mm_rsqrt_ps(gx*gx + gy*gy + gz*gz + _mm_set_ps1(1e-16f)); 02871 gx = gx*glen; 02872 gy = gy*glen; 02873 gz = gz*glen; 02874 02875 /* compute angle */ 02876 rcos = rx*srx + ry*sry + rz*srz; 02877 rcos= _mm_max_ps(_mm_min_ps(rcos, _mm_set_ps1(1.0f)), _mm_set_ps1(-1.0f)); 02878 02879 angle = sse_approx_cos(rcos); 02880 aresult = (_mm_set_ps1(n[0])*gx + _mm_set_ps1(n[1])*gy + _mm_set_ps1(n[2])*gz)*angle; 02881 02882 /* sum together */ 02883 result= (fresult[0] + fresult[1] + fresult[2] + fresult[3])*(0.5f/(float)M_PI); 02884 result= MAX2(result, 0.0f); 02885 02886 return result; 02887 } 02888 02889 #endif 02890 02891 static void ff_normalize(float n[3]) 02892 { 02893 float d; 02894 02895 d= dot_v3v3(n, n); 02896 02897 if(d > 1.0e-35F) { 02898 d= 1.0f/sqrtf(d); 02899 02900 n[0] *= d; 02901 n[1] *= d; 02902 n[2] *= d; 02903 } 02904 } 02905 02906 static float ff_quad_form_factor(const float p[3], const float n[3], const float q0[3], const float q1[3], const float q2[3], const float q3[3]) 02907 { 02908 float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3]; 02909 float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result; 02910 02911 sub_v3_v3v3(r0, q0, p); 02912 sub_v3_v3v3(r1, q1, p); 02913 sub_v3_v3v3(r2, q2, p); 02914 sub_v3_v3v3(r3, q3, p); 02915 02916 ff_normalize(r0); 02917 ff_normalize(r1); 02918 ff_normalize(r2); 02919 ff_normalize(r3); 02920 02921 cross_v3_v3v3(g0, r1, r0); ff_normalize(g0); 02922 cross_v3_v3v3(g1, r2, r1); ff_normalize(g1); 02923 cross_v3_v3v3(g2, r3, r2); ff_normalize(g2); 02924 cross_v3_v3v3(g3, r0, r3); ff_normalize(g3); 02925 02926 a1= saacosf(dot_v3v3(r0, r1)); 02927 a2= saacosf(dot_v3v3(r1, r2)); 02928 a3= saacosf(dot_v3v3(r2, r3)); 02929 a4= saacosf(dot_v3v3(r3, r0)); 02930 02931 dot1= dot_v3v3(n, g0); 02932 dot2= dot_v3v3(n, g1); 02933 dot3= dot_v3v3(n, g2); 02934 dot4= dot_v3v3(n, g3); 02935 02936 result= (a1*dot1 + a2*dot2 + a3*dot3 + a4*dot4)*0.5f/(float)M_PI; 02937 result= MAX2(result, 0.0f); 02938 02939 return result; 02940 } 02941 02942 float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], float v3[3], float v4[3]) 02943 { 02944 /* computes how much hemisphere defined by point and normal is 02945 covered by a quad or triangle, cosine weighted */ 02946 float q0[3], q1[3], q2[3], q3[3], contrib= 0.0f; 02947 02948 if(ff_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3)) 02949 contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3); 02950 02951 if(v4 && ff_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3)) 02952 contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3); 02953 02954 return contrib; 02955 }