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