00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include "PQP.h"
00044 #include "BVTQ.h"
00045 #include "Build.h"
00046 #include "MatVec.h"
00047 #include "GetTime.h"
00048 #include "TriDist.h"
00049
00050 enum BUILD_STATE
00051 {
00052 PQP_BUILD_STATE_EMPTY,
00053 PQP_BUILD_STATE_BEGUN,
00054 PQP_BUILD_STATE_PROCESSED
00055 };
00056
00057 PQP_Model::PQP_Model()
00058 {
00059
00060
00061 b = 0;
00062 num_bvs_alloced = 0;
00063 num_bvs = 0;
00064
00065
00066
00067 tris = 0;
00068 num_tris = 0;
00069 num_tris_alloced = 0;
00070
00071 last_tri = 0;
00072
00073 build_state = PQP_BUILD_STATE_EMPTY;
00074 }
00075
00076 PQP_Model::~PQP_Model()
00077 {
00078 if (b != NULL)
00079 delete [] b;
00080 if (tris != NULL)
00081 delete [] tris;
00082 }
00083
00084 int
00085 PQP_Model::BeginModel(int n)
00086 {
00087
00088
00089 if (build_state != PQP_BUILD_STATE_EMPTY)
00090 {
00091 delete [] b;
00092 delete [] tris;
00093
00094 num_tris = num_bvs = num_tris_alloced = num_bvs_alloced = 0;
00095 }
00096
00097
00098
00099 if (n <= 0) n = 8;
00100 num_tris_alloced = n;
00101 tris = new Tri[n];
00102 if (!tris)
00103 {
00104 fprintf(stderr, "PQP Error! Out of memory for tri array on "
00105 "BeginModel() call!\n");
00106 return PQP_ERR_MODEL_OUT_OF_MEMORY;
00107 }
00108
00109
00110
00111 if (build_state != PQP_BUILD_STATE_EMPTY)
00112 {
00113 fprintf(stderr,
00114 "PQP Warning! Called BeginModel() on a PQP_Model that \n"
00115 "was not empty. This model was cleared and previous\n"
00116 "triangle additions were lost.\n");
00117 build_state = PQP_BUILD_STATE_BEGUN;
00118 return PQP_ERR_BUILD_OUT_OF_SEQUENCE;
00119 }
00120
00121 build_state = PQP_BUILD_STATE_BEGUN;
00122 return PQP_OK;
00123 }
00124
00125 int
00126 PQP_Model::AddTri(const PQP_REAL *p1,
00127 const PQP_REAL *p2,
00128 const PQP_REAL *p3,
00129 int id)
00130 {
00131 if (build_state == PQP_BUILD_STATE_EMPTY)
00132 {
00133 BeginModel();
00134 }
00135 else if (build_state == PQP_BUILD_STATE_PROCESSED)
00136 {
00137 fprintf(stderr,"PQP Warning! Called AddTri() on PQP_Model \n"
00138 "object that was already ended. AddTri() was\n"
00139 "ignored. Must do a BeginModel() to clear the\n"
00140 "model for addition of new triangles\n");
00141 return PQP_ERR_BUILD_OUT_OF_SEQUENCE;
00142 }
00143
00144
00145
00146 if (num_tris >= num_tris_alloced)
00147 {
00148 Tri *temp;
00149 temp = new Tri[num_tris_alloced*2];
00150 if (!temp)
00151 {
00152 fprintf(stderr, "PQP Error! Out of memory for tri array on"
00153 " AddTri() call!\n");
00154 return PQP_ERR_MODEL_OUT_OF_MEMORY;
00155 }
00156 memcpy(temp, tris, sizeof(Tri)*num_tris);
00157 delete [] tris;
00158 tris = temp;
00159 num_tris_alloced = num_tris_alloced*2;
00160 }
00161
00162
00163
00164 tris[num_tris].p1[0] = p1[0];
00165 tris[num_tris].p1[1] = p1[1];
00166 tris[num_tris].p1[2] = p1[2];
00167
00168 tris[num_tris].p2[0] = p2[0];
00169 tris[num_tris].p2[1] = p2[1];
00170 tris[num_tris].p2[2] = p2[2];
00171
00172 tris[num_tris].p3[0] = p3[0];
00173 tris[num_tris].p3[1] = p3[1];
00174 tris[num_tris].p3[2] = p3[2];
00175
00176 tris[num_tris].id = id;
00177
00178 num_tris += 1;
00179
00180 return PQP_OK;
00181 }
00182
00183 int
00184 PQP_Model::EndModel()
00185 {
00186 if (build_state == PQP_BUILD_STATE_PROCESSED)
00187 {
00188 fprintf(stderr,"PQP Warning! Called EndModel() on PQP_Model \n"
00189 "object that was already ended. EndModel() was\n"
00190 "ignored. Must do a BeginModel() to clear the\n"
00191 "model for addition of new triangles\n");
00192 return PQP_ERR_BUILD_OUT_OF_SEQUENCE;
00193 }
00194
00195
00196
00197 if (num_tris == 0)
00198 {
00199 fprintf(stderr,"PQP Error! EndModel() called on model with"
00200 " no triangles\n");
00201 return PQP_ERR_BUILD_EMPTY_MODEL;
00202 }
00203
00204
00205
00206 if (num_tris_alloced > num_tris)
00207 {
00208 Tri *new_tris = new Tri[num_tris];
00209 if (!new_tris)
00210 {
00211 fprintf(stderr, "PQP Error! Out of memory for tri array "
00212 "in EndModel() call!\n");
00213 return PQP_ERR_MODEL_OUT_OF_MEMORY;
00214 }
00215 memcpy(new_tris, tris, sizeof(Tri)*num_tris);
00216 delete [] tris;
00217 tris = new_tris;
00218 num_tris_alloced = num_tris;
00219 }
00220
00221
00222
00223 b = new BV[2*num_tris - 1];
00224 if (!b)
00225 {
00226 fprintf(stderr,"PQP Error! out of memory for BV array "
00227 "in EndModel()\n");
00228 return PQP_ERR_MODEL_OUT_OF_MEMORY;
00229 }
00230 num_bvs_alloced = 2*num_tris - 1;
00231 num_bvs = 0;
00232
00233
00234
00235 build_model(this);
00236 build_state = PQP_BUILD_STATE_PROCESSED;
00237
00238 last_tri = tris;
00239
00240 return PQP_OK;
00241 }
00242
00243 int
00244 PQP_Model::MemUsage(int msg)
00245 {
00246 int mem_bv_list = sizeof(BV)*num_bvs;
00247 int mem_tri_list = sizeof(Tri)*num_tris;
00248
00249 int total_mem = mem_bv_list + mem_tri_list + sizeof(PQP_Model);
00250
00251 if (msg)
00252 {
00253 fprintf(stderr,"Total for model %p: %d bytes\n", this, total_mem);
00254 fprintf(stderr,"BVs: %d alloced, take %ld bytes each\n",
00255 num_bvs, sizeof(BV));
00256 fprintf(stderr,"Tris: %d alloced, take %ld bytes each\n",
00257 num_tris, sizeof(Tri));
00258 }
00259
00260 return total_mem;
00261 }
00262
00263
00264
00265
00266
00267 PQP_CollideResult::PQP_CollideResult()
00268 {
00269 pairs = 0;
00270 num_pairs = num_pairs_alloced = 0;
00271 num_bv_tests = 0;
00272 num_tri_tests = 0;
00273 }
00274
00275 PQP_CollideResult::~PQP_CollideResult()
00276 {
00277 delete [] pairs;
00278 }
00279
00280 void
00281 PQP_CollideResult::FreePairsList()
00282 {
00283 num_pairs = num_pairs_alloced = 0;
00284 delete [] pairs;
00285 pairs = 0;
00286 }
00287
00288
00289 void
00290 PQP_CollideResult::SizeTo(int n)
00291 {
00292 CollisionPair *temp;
00293
00294 if (n < num_pairs)
00295 {
00296 fprintf(stderr, "PQP Error: Internal error in "
00297 "'PQP_CollideResult::SizeTo(int n)'\n");
00298 fprintf(stderr, " n = %d, but num_pairs = %d\n", n, num_pairs);
00299 return;
00300 }
00301
00302 temp = new CollisionPair[n];
00303 memcpy(temp, pairs, num_pairs*sizeof(CollisionPair));
00304 delete [] pairs;
00305 pairs = temp;
00306 num_pairs_alloced = n;
00307 return;
00308 }
00309
00310 void
00311 PQP_CollideResult::Add(int a, int b)
00312 {
00313 if (num_pairs >= num_pairs_alloced)
00314 {
00315
00316
00317 SizeTo(num_pairs_alloced*2+8);
00318 }
00319
00320
00321
00322 pairs[num_pairs].id1 = a;
00323 pairs[num_pairs].id2 = b;
00324 num_pairs++;
00325 }
00326
00327
00328
00329 inline
00330 PQP_REAL
00331 max(PQP_REAL a, PQP_REAL b, PQP_REAL c)
00332 {
00333 PQP_REAL t = a;
00334 if (b > t) t = b;
00335 if (c > t) t = c;
00336 return t;
00337 }
00338
00339 inline
00340 PQP_REAL
00341 min(PQP_REAL a, PQP_REAL b, PQP_REAL c)
00342 {
00343 PQP_REAL t = a;
00344 if (b < t) t = b;
00345 if (c < t) t = c;
00346 return t;
00347 }
00348
00349 int
00350 project6(PQP_REAL *ax,
00351 PQP_REAL *p1, PQP_REAL *p2, PQP_REAL *p3,
00352 PQP_REAL *q1, PQP_REAL *q2, PQP_REAL *q3)
00353 {
00354 PQP_REAL P1 = VdotV(ax, p1);
00355 PQP_REAL P2 = VdotV(ax, p2);
00356 PQP_REAL P3 = VdotV(ax, p3);
00357 PQP_REAL Q1 = VdotV(ax, q1);
00358 PQP_REAL Q2 = VdotV(ax, q2);
00359 PQP_REAL Q3 = VdotV(ax, q3);
00360
00361 PQP_REAL mx1 = max(P1, P2, P3);
00362 PQP_REAL mn1 = min(P1, P2, P3);
00363 PQP_REAL mx2 = max(Q1, Q2, Q3);
00364 PQP_REAL mn2 = min(Q1, Q2, Q3);
00365
00366 if (mn1 > mx2) return 0;
00367 if (mn2 > mx1) return 0;
00368 return 1;
00369 }
00370
00371
00372
00373
00374 int
00375 TriContact(PQP_REAL *P1, PQP_REAL *P2, PQP_REAL *P3,
00376 PQP_REAL *Q1, PQP_REAL *Q2, PQP_REAL *Q3)
00377 {
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 PQP_REAL p1[3], p2[3], p3[3];
00389 PQP_REAL q1[3], q2[3], q3[3];
00390 PQP_REAL e1[3], e2[3], e3[3];
00391 PQP_REAL f1[3], f2[3], f3[3];
00392 PQP_REAL g1[3], g2[3], g3[3];
00393 PQP_REAL h1[3], h2[3], h3[3];
00394 PQP_REAL n1[3], m1[3];
00395
00396 PQP_REAL ef11[3], ef12[3], ef13[3];
00397 PQP_REAL ef21[3], ef22[3], ef23[3];
00398 PQP_REAL ef31[3], ef32[3], ef33[3];
00399
00400 p1[0] = P1[0] - P1[0]; p1[1] = P1[1] - P1[1]; p1[2] = P1[2] - P1[2];
00401 p2[0] = P2[0] - P1[0]; p2[1] = P2[1] - P1[1]; p2[2] = P2[2] - P1[2];
00402 p3[0] = P3[0] - P1[0]; p3[1] = P3[1] - P1[1]; p3[2] = P3[2] - P1[2];
00403
00404 q1[0] = Q1[0] - P1[0]; q1[1] = Q1[1] - P1[1]; q1[2] = Q1[2] - P1[2];
00405 q2[0] = Q2[0] - P1[0]; q2[1] = Q2[1] - P1[1]; q2[2] = Q2[2] - P1[2];
00406 q3[0] = Q3[0] - P1[0]; q3[1] = Q3[1] - P1[1]; q3[2] = Q3[2] - P1[2];
00407
00408 e1[0] = p2[0] - p1[0]; e1[1] = p2[1] - p1[1]; e1[2] = p2[2] - p1[2];
00409 e2[0] = p3[0] - p2[0]; e2[1] = p3[1] - p2[1]; e2[2] = p3[2] - p2[2];
00410 e3[0] = p1[0] - p3[0]; e3[1] = p1[1] - p3[1]; e3[2] = p1[2] - p3[2];
00411
00412 f1[0] = q2[0] - q1[0]; f1[1] = q2[1] - q1[1]; f1[2] = q2[2] - q1[2];
00413 f2[0] = q3[0] - q2[0]; f2[1] = q3[1] - q2[1]; f2[2] = q3[2] - q2[2];
00414 f3[0] = q1[0] - q3[0]; f3[1] = q1[1] - q3[1]; f3[2] = q1[2] - q3[2];
00415
00416 VcrossV(n1, e1, e2);
00417 VcrossV(m1, f1, f2);
00418
00419 VcrossV(g1, e1, n1);
00420 VcrossV(g2, e2, n1);
00421 VcrossV(g3, e3, n1);
00422 VcrossV(h1, f1, m1);
00423 VcrossV(h2, f2, m1);
00424 VcrossV(h3, f3, m1);
00425
00426 VcrossV(ef11, e1, f1);
00427 VcrossV(ef12, e1, f2);
00428 VcrossV(ef13, e1, f3);
00429 VcrossV(ef21, e2, f1);
00430 VcrossV(ef22, e2, f2);
00431 VcrossV(ef23, e2, f3);
00432 VcrossV(ef31, e3, f1);
00433 VcrossV(ef32, e3, f2);
00434 VcrossV(ef33, e3, f3);
00435
00436
00437
00438 if (!project6(n1, p1, p2, p3, q1, q2, q3)) return 0;
00439 if (!project6(m1, p1, p2, p3, q1, q2, q3)) return 0;
00440
00441 if (!project6(ef11, p1, p2, p3, q1, q2, q3)) return 0;
00442 if (!project6(ef12, p1, p2, p3, q1, q2, q3)) return 0;
00443 if (!project6(ef13, p1, p2, p3, q1, q2, q3)) return 0;
00444 if (!project6(ef21, p1, p2, p3, q1, q2, q3)) return 0;
00445 if (!project6(ef22, p1, p2, p3, q1, q2, q3)) return 0;
00446 if (!project6(ef23, p1, p2, p3, q1, q2, q3)) return 0;
00447 if (!project6(ef31, p1, p2, p3, q1, q2, q3)) return 0;
00448 if (!project6(ef32, p1, p2, p3, q1, q2, q3)) return 0;
00449 if (!project6(ef33, p1, p2, p3, q1, q2, q3)) return 0;
00450
00451 if (!project6(g1, p1, p2, p3, q1, q2, q3)) return 0;
00452 if (!project6(g2, p1, p2, p3, q1, q2, q3)) return 0;
00453 if (!project6(g3, p1, p2, p3, q1, q2, q3)) return 0;
00454 if (!project6(h1, p1, p2, p3, q1, q2, q3)) return 0;
00455 if (!project6(h2, p1, p2, p3, q1, q2, q3)) return 0;
00456 if (!project6(h3, p1, p2, p3, q1, q2, q3)) return 0;
00457
00458 return 1;
00459 }
00460
00461 inline
00462 PQP_REAL
00463 TriDistance(PQP_REAL R[3][3], PQP_REAL T[3], Tri *t1, Tri *t2,
00464 PQP_REAL p[3], PQP_REAL q[3])
00465 {
00466
00467
00468 PQP_REAL tri1[3][3], tri2[3][3];
00469
00470 VcV(tri1[0], t1->p1);
00471 VcV(tri1[1], t1->p2);
00472 VcV(tri1[2], t1->p3);
00473 MxVpV(tri2[0], R, t2->p1, T);
00474 MxVpV(tri2[1], R, t2->p2, T);
00475 MxVpV(tri2[2], R, t2->p3, T);
00476
00477 return TriDist(p,q,tri1,tri2);
00478 }
00479
00480
00481 void
00482 CollideRecurse(PQP_CollideResult *res,
00483 PQP_REAL R[3][3], PQP_REAL T[3],
00484 PQP_Model *o1, int b1,
00485 PQP_Model *o2, int b2, int flag)
00486 {
00487
00488
00489 res->num_bv_tests++;
00490
00491 if (!BV_Overlap(R, T, o1->child(b1), o2->child(b2))) return;
00492
00493
00494
00495 int l1 = o1->child(b1)->Leaf();
00496 int l2 = o2->child(b2)->Leaf();
00497
00498 if (l1 && l2)
00499 {
00500 res->num_tri_tests++;
00501
00502 #if 1
00503
00504
00505 Tri *t1 = &o1->tris[-o1->child(b1)->first_child - 1];
00506 Tri *t2 = &o2->tris[-o2->child(b2)->first_child - 1];
00507 PQP_REAL q1[3], q2[3], q3[3];
00508 PQP_REAL *p1 = t1->p1;
00509 PQP_REAL *p2 = t1->p2;
00510 PQP_REAL *p3 = t1->p3;
00511 MxVpV(q1, res->R, t2->p1, res->T);
00512 MxVpV(q2, res->R, t2->p2, res->T);
00513 MxVpV(q3, res->R, t2->p3, res->T);
00514 if (TriContact(p1, p2, p3, q1, q2, q3))
00515 {
00516
00517
00518 res->Add(t1->id, t2->id);
00519 }
00520 #else
00521 PQP_REAL p[3], q[3];
00522
00523 Tri *t1 = &o1->tris[-o1->child(b1)->first_child - 1];
00524 Tri *t2 = &o2->tris[-o2->child(b2)->first_child - 1];
00525
00526 if (TriDistance(res->R,res->T,t1,t2,p,q) == 0.0)
00527 {
00528
00529
00530 res->Add(t1->id, t2->id);
00531 }
00532 #endif
00533
00534 return;
00535 }
00536
00537
00538
00539 PQP_REAL sz1 = o1->child(b1)->GetSize();
00540 PQP_REAL sz2 = o2->child(b2)->GetSize();
00541
00542 PQP_REAL Rc[3][3],Tc[3],Ttemp[3];
00543
00544 if (l2 || (!l1 && (sz1 > sz2)))
00545 {
00546 int c1 = o1->child(b1)->first_child;
00547 int c2 = c1 + 1;
00548
00549 MTxM(Rc,o1->child(c1)->R,R);
00550 #if PQP_BV_TYPE & OBB_TYPE
00551 VmV(Ttemp,T,o1->child(c1)->To);
00552 #else
00553 VmV(Ttemp,T,o1->child(c1)->Tr);
00554 #endif
00555 MTxV(Tc,o1->child(c1)->R,Ttemp);
00556 CollideRecurse(res,Rc,Tc,o1,c1,o2,b2,flag);
00557
00558 if ((flag == PQP_FIRST_CONTACT) && (res->num_pairs > 0)) return;
00559
00560 MTxM(Rc,o1->child(c2)->R,R);
00561 #if PQP_BV_TYPE & OBB_TYPE
00562 VmV(Ttemp,T,o1->child(c2)->To);
00563 #else
00564 VmV(Ttemp,T,o1->child(c2)->Tr);
00565 #endif
00566 MTxV(Tc,o1->child(c2)->R,Ttemp);
00567 CollideRecurse(res,Rc,Tc,o1,c2,o2,b2,flag);
00568 }
00569 else
00570 {
00571 int c1 = o2->child(b2)->first_child;
00572 int c2 = c1 + 1;
00573
00574 MxM(Rc,R,o2->child(c1)->R);
00575 #if PQP_BV_TYPE & OBB_TYPE
00576 MxVpV(Tc,R,o2->child(c1)->To,T);
00577 #else
00578 MxVpV(Tc,R,o2->child(c1)->Tr,T);
00579 #endif
00580 CollideRecurse(res,Rc,Tc,o1,b1,o2,c1,flag);
00581
00582 if ((flag == PQP_FIRST_CONTACT) && (res->num_pairs > 0)) return;
00583
00584 MxM(Rc,R,o2->child(c2)->R);
00585 #if PQP_BV_TYPE & OBB_TYPE
00586 MxVpV(Tc,R,o2->child(c2)->To,T);
00587 #else
00588 MxVpV(Tc,R,o2->child(c2)->Tr,T);
00589 #endif
00590 CollideRecurse(res,Rc,Tc,o1,b1,o2,c2,flag);
00591 }
00592 }
00593
00594 int
00595 PQP_Collide(PQP_CollideResult *res,
00596 PQP_REAL R1[3][3], PQP_REAL T1[3], PQP_Model *o1,
00597 PQP_REAL R2[3][3], PQP_REAL T2[3], PQP_Model *o2,
00598 int flag)
00599 {
00600 double t1 = GetTime();
00601
00602
00603
00604 if (o1->build_state != PQP_BUILD_STATE_PROCESSED)
00605 return PQP_ERR_UNPROCESSED_MODEL;
00606 if (o2->build_state != PQP_BUILD_STATE_PROCESSED)
00607 return PQP_ERR_UNPROCESSED_MODEL;
00608
00609
00610
00611 res->num_bv_tests = 0;
00612 res->num_tri_tests = 0;
00613
00614
00615
00616 res->num_pairs = 0;
00617
00618
00619
00620
00621
00622 MTxM(res->R,R1,R2);
00623 PQP_REAL Ttemp[3];
00624 VmV(Ttemp, T2, T1);
00625 MTxV(res->T, R1, Ttemp);
00626
00627
00628
00629 PQP_REAL Rtemp[3][3], R[3][3], T[3];
00630
00631 MxM(Rtemp,res->R,o2->child(0)->R);
00632 MTxM(R,o1->child(0)->R,Rtemp);
00633
00634 #if PQP_BV_TYPE & OBB_TYPE
00635 MxVpV(Ttemp,res->R,o2->child(0)->To,res->T);
00636 VmV(Ttemp,Ttemp,o1->child(0)->To);
00637 #else
00638 MxVpV(Ttemp,res->R,o2->child(0)->Tr,res->T);
00639 VmV(Ttemp,Ttemp,o1->child(0)->Tr);
00640 #endif
00641
00642 MTxV(T,o1->child(0)->R,Ttemp);
00643
00644
00645
00646 CollideRecurse(res,R,T,o1,0,o2,0,flag);
00647
00648 double t2 = GetTime();
00649 res->query_time_secs = t2 - t1;
00650
00651 return PQP_OK;
00652 }
00653
00654 #if PQP_BV_TYPE & RSS_TYPE // distance/tolerance only available with RSS
00655
00656
00657
00658
00659
00660
00661
00662 void
00663 DistanceRecurse(PQP_DistanceResult *res,
00664 PQP_REAL R[3][3], PQP_REAL T[3],
00665 PQP_Model *o1, int b1,
00666 PQP_Model *o2, int b2)
00667 {
00668 PQP_REAL sz1 = o1->child(b1)->GetSize();
00669 PQP_REAL sz2 = o2->child(b2)->GetSize();
00670 int l1 = o1->child(b1)->Leaf();
00671 int l2 = o2->child(b2)->Leaf();
00672
00673 if (l1 && l2)
00674 {
00675
00676
00677 res->num_tri_tests++;
00678
00679 PQP_REAL p[3], q[3];
00680
00681 Tri *t1 = &o1->tris[-o1->child(b1)->first_child - 1];
00682 Tri *t2 = &o2->tris[-o2->child(b2)->first_child - 1];
00683
00684 PQP_REAL d = TriDistance(res->R,res->T,t1,t2,p,q);
00685
00686 if (d < res->distance)
00687 {
00688 res->distance = d;
00689
00690 VcV(res->p1, p);
00691 VcV(res->p2, q);
00692
00693 o1->last_tri = t1;
00694 o2->last_tri = t2;
00695 }
00696
00697 return;
00698 }
00699
00700
00701
00702
00703
00704 int a1,a2,c1,c2;
00705 PQP_REAL R1[3][3], T1[3], R2[3][3], T2[3], Ttemp[3];
00706
00707 if (l2 || (!l1 && (sz1 > sz2)))
00708 {
00709
00710
00711 a1 = o1->child(b1)->first_child;
00712 a2 = b2;
00713 c1 = o1->child(b1)->first_child+1;
00714 c2 = b2;
00715
00716 MTxM(R1,o1->child(a1)->R,R);
00717 #if PQP_BV_TYPE & RSS_TYPE
00718 VmV(Ttemp,T,o1->child(a1)->Tr);
00719 #else
00720 VmV(Ttemp,T,o1->child(a1)->To);
00721 #endif
00722 MTxV(T1,o1->child(a1)->R,Ttemp);
00723
00724 MTxM(R2,o1->child(c1)->R,R);
00725 #if PQP_BV_TYPE & RSS_TYPE
00726 VmV(Ttemp,T,o1->child(c1)->Tr);
00727 #else
00728 VmV(Ttemp,T,o1->child(c1)->To);
00729 #endif
00730 MTxV(T2,o1->child(c1)->R,Ttemp);
00731 }
00732 else
00733 {
00734
00735
00736 a1 = b1;
00737 a2 = o2->child(b2)->first_child;
00738 c1 = b1;
00739 c2 = o2->child(b2)->first_child+1;
00740
00741 MxM(R1,R,o2->child(a2)->R);
00742 #if PQP_BV_TYPE & RSS_TYPE
00743 MxVpV(T1,R,o2->child(a2)->Tr,T);
00744 #else
00745 MxVpV(T1,R,o2->child(a2)->To,T);
00746 #endif
00747
00748 MxM(R2,R,o2->child(c2)->R);
00749 #if PQP_BV_TYPE & RSS_TYPE
00750 MxVpV(T2,R,o2->child(c2)->Tr,T);
00751 #else
00752 MxVpV(T2,R,o2->child(c2)->To,T);
00753 #endif
00754 }
00755
00756 res->num_bv_tests += 2;
00757
00758 PQP_REAL d1 = BV_Distance(R1, T1, o1->child(a1), o2->child(a2));
00759 PQP_REAL d2 = BV_Distance(R2, T2, o1->child(c1), o2->child(c2));
00760
00761 if (d2 < d1)
00762 {
00763 if ((d2 < (res->distance - res->abs_err)) ||
00764 (d2*(1 + res->rel_err) < res->distance))
00765 {
00766 DistanceRecurse(res, R2, T2, o1, c1, o2, c2);
00767 }
00768
00769 if ((d1 < (res->distance - res->abs_err)) ||
00770 (d1*(1 + res->rel_err) < res->distance))
00771 {
00772 DistanceRecurse(res, R1, T1, o1, a1, o2, a2);
00773 }
00774 }
00775 else
00776 {
00777 if ((d1 < (res->distance - res->abs_err)) ||
00778 (d1*(1 + res->rel_err) < res->distance))
00779 {
00780 DistanceRecurse(res, R1, T1, o1, a1, o2, a2);
00781 }
00782
00783 if ((d2 < (res->distance - res->abs_err)) ||
00784 (d2*(1 + res->rel_err) < res->distance))
00785 {
00786 DistanceRecurse(res, R2, T2, o1, c1, o2, c2);
00787 }
00788 }
00789 }
00790
00791 void
00792 DistanceQueueRecurse(PQP_DistanceResult *res,
00793 PQP_REAL R[3][3], PQP_REAL T[3],
00794 PQP_Model *o1, int b1,
00795 PQP_Model *o2, int b2)
00796 {
00797 BVTQ bvtq(res->qsize);
00798
00799 BVT min_test;
00800 min_test.b1 = b1;
00801 min_test.b2 = b2;
00802 McM(min_test.R,R);
00803 VcV(min_test.T,T);
00804
00805 while(1)
00806 {
00807 int l1 = o1->child(min_test.b1)->Leaf();
00808 int l2 = o2->child(min_test.b2)->Leaf();
00809
00810 if (l1 && l2)
00811 {
00812
00813
00814 res->num_tri_tests++;
00815
00816 PQP_REAL p[3], q[3];
00817
00818 Tri *t1 = &o1->tris[-o1->child(min_test.b1)->first_child - 1];
00819 Tri *t2 = &o2->tris[-o2->child(min_test.b2)->first_child - 1];
00820
00821 PQP_REAL d = TriDistance(res->R,res->T,t1,t2,p,q);
00822
00823 if (d < res->distance)
00824 {
00825 res->distance = d;
00826
00827 VcV(res->p1, p);
00828 VcV(res->p2, q);
00829
00830 o1->last_tri = t1;
00831 o2->last_tri = t2;
00832 }
00833 }
00834 else if (bvtq.GetNumTests() == bvtq.GetSize() - 1)
00835 {
00836
00837
00838 DistanceQueueRecurse(res,min_test.R,min_test.T,
00839 o1,min_test.b1,o2,min_test.b2);
00840 }
00841 else
00842 {
00843
00844
00845 PQP_REAL sz1 = o1->child(min_test.b1)->GetSize();
00846 PQP_REAL sz2 = o2->child(min_test.b2)->GetSize();
00847
00848 res->num_bv_tests += 2;
00849
00850 BVT bvt1,bvt2;
00851 PQP_REAL Ttemp[3];
00852
00853 if (l2 || (!l1 && (sz1 > sz2)))
00854 {
00855
00856
00857
00858 int c1 = o1->child(min_test.b1)->first_child;
00859 int c2 = c1 + 1;
00860
00861
00862
00863 bvt1.b1 = c1;
00864 bvt1.b2 = min_test.b2;
00865 MTxM(bvt1.R,o1->child(c1)->R,min_test.R);
00866 #if PQP_BV_TYPE & RSS_TYPE
00867 VmV(Ttemp,min_test.T,o1->child(c1)->Tr);
00868 #else
00869 VmV(Ttemp,min_test.T,o1->child(c1)->To);
00870 #endif
00871 MTxV(bvt1.T,o1->child(c1)->R,Ttemp);
00872 bvt1.d = BV_Distance(bvt1.R,bvt1.T,
00873 o1->child(bvt1.b1),o2->child(bvt1.b2));
00874
00875
00876
00877 bvt2.b1 = c2;
00878 bvt2.b2 = min_test.b2;
00879 MTxM(bvt2.R,o1->child(c2)->R,min_test.R);
00880 #if PQP_BV_TYPE & RSS_TYPE
00881 VmV(Ttemp,min_test.T,o1->child(c2)->Tr);
00882 #else
00883 VmV(Ttemp,min_test.T,o1->child(c2)->To);
00884 #endif
00885 MTxV(bvt2.T,o1->child(c2)->R,Ttemp);
00886 bvt2.d = BV_Distance(bvt2.R,bvt2.T,
00887 o1->child(bvt2.b1),o2->child(bvt2.b2));
00888 }
00889 else
00890 {
00891
00892
00893
00894 int c1 = o2->child(min_test.b2)->first_child;
00895 int c2 = c1 + 1;
00896
00897
00898
00899 bvt1.b1 = min_test.b1;
00900 bvt1.b2 = c1;
00901 MxM(bvt1.R,min_test.R,o2->child(c1)->R);
00902 #if PQP_BV_TYPE & RSS_TYPE
00903 MxVpV(bvt1.T,min_test.R,o2->child(c1)->Tr,min_test.T);
00904 #else
00905 MxVpV(bvt1.T,min_test.R,o2->child(c1)->To,min_test.T);
00906 #endif
00907 bvt1.d = BV_Distance(bvt1.R,bvt1.T,
00908 o1->child(bvt1.b1),o2->child(bvt1.b2));
00909
00910
00911
00912 bvt2.b1 = min_test.b1;
00913 bvt2.b2 = c2;
00914 MxM(bvt2.R,min_test.R,o2->child(c2)->R);
00915 #if PQP_BV_TYPE & RSS_TYPE
00916 MxVpV(bvt2.T,min_test.R,o2->child(c2)->Tr,min_test.T);
00917 #else
00918 MxVpV(bvt2.T,min_test.R,o2->child(c2)->To,min_test.T);
00919 #endif
00920 bvt2.d = BV_Distance(bvt2.R,bvt2.T,
00921 o1->child(bvt2.b1),o2->child(bvt2.b2));
00922 }
00923
00924 bvtq.AddTest(bvt1);
00925 bvtq.AddTest(bvt2);
00926 }
00927
00928 if (bvtq.Empty())
00929 {
00930 break;
00931 }
00932 else
00933 {
00934 min_test = bvtq.ExtractMinTest();
00935
00936 if ((min_test.d + res->abs_err >= res->distance) &&
00937 ((min_test.d * (1 + res->rel_err)) >= res->distance))
00938 {
00939 break;
00940 }
00941 }
00942 }
00943 }
00944
00945 int
00946 PQP_Distance(PQP_DistanceResult *res,
00947 PQP_REAL R1[3][3], PQP_REAL T1[3], PQP_Model *o1,
00948 PQP_REAL R2[3][3], PQP_REAL T2[3], PQP_Model *o2,
00949 PQP_REAL rel_err, PQP_REAL abs_err,
00950 int qsize)
00951 {
00952
00953 double time1 = GetTime();
00954
00955
00956
00957 if (o1->build_state != PQP_BUILD_STATE_PROCESSED)
00958 return PQP_ERR_UNPROCESSED_MODEL;
00959 if (o2->build_state != PQP_BUILD_STATE_PROCESSED)
00960 return PQP_ERR_UNPROCESSED_MODEL;
00961
00962
00963
00964
00965
00966 MTxM(res->R,R1,R2);
00967 PQP_REAL Ttemp[3];
00968 VmV(Ttemp, T2, T1);
00969 MTxV(res->T, R1, Ttemp);
00970
00971
00972
00973
00974 PQP_REAL p[3],q[3];
00975 res->distance = TriDistance(res->R,res->T,o1->last_tri,o2->last_tri,p,q);
00976 VcV(res->p1,p);
00977 VcV(res->p2,q);
00978
00979
00980
00981 res->abs_err = abs_err;
00982 res->rel_err = rel_err;
00983
00984
00985
00986 res->num_bv_tests = 0;
00987 res->num_tri_tests = 0;
00988
00989
00990
00991 PQP_REAL Rtemp[3][3], R[3][3], T[3];
00992
00993 MxM(Rtemp,res->R,o2->child(0)->R);
00994 MTxM(R,o1->child(0)->R,Rtemp);
00995
00996 #if PQP_BV_TYPE & RSS_TYPE
00997 MxVpV(Ttemp,res->R,o2->child(0)->Tr,res->T);
00998 VmV(Ttemp,Ttemp,o1->child(0)->Tr);
00999 #else
01000 MxVpV(Ttemp,res->R,o2->child(0)->To,res->T);
01001 VmV(Ttemp,Ttemp,o1->child(0)->To);
01002 #endif
01003 MTxV(T,o1->child(0)->R,Ttemp);
01004
01005
01006
01007 if (qsize <= 2)
01008 {
01009 DistanceRecurse(res,R,T,o1,0,o2,0);
01010 }
01011 else
01012 {
01013 res->qsize = qsize;
01014
01015 DistanceQueueRecurse(res,R,T,o1,0,o2,0);
01016 }
01017
01018
01019
01020 PQP_REAL u[3];
01021 VmV(u, res->p2, res->T);
01022 MTxV(res->p2, res->R, u);
01023
01024 double time2 = GetTime();
01025 res->query_time_secs = time2 - time1;
01026
01027 return PQP_OK;
01028 }
01029
01030
01031
01032
01033 void
01034 ToleranceRecurse(PQP_ToleranceResult *res,
01035 PQP_REAL R[3][3], PQP_REAL T[3],
01036 PQP_Model *o1, int b1, PQP_Model *o2, int b2)
01037 {
01038 PQP_REAL sz1 = o1->child(b1)->GetSize();
01039 PQP_REAL sz2 = o2->child(b2)->GetSize();
01040 int l1 = o1->child(b1)->Leaf();
01041 int l2 = o2->child(b2)->Leaf();
01042
01043 if (l1 && l2)
01044 {
01045
01046
01047 res->num_tri_tests++;
01048
01049 PQP_REAL p[3], q[3];
01050
01051 Tri *t1 = &o1->tris[-o1->child(b1)->first_child - 1];
01052 Tri *t2 = &o2->tris[-o2->child(b2)->first_child - 1];
01053
01054 PQP_REAL d = TriDistance(res->R,res->T,t1,t2,p,q);
01055
01056 if (d <= res->tolerance)
01057 {
01058
01059
01060 res->closer_than_tolerance = 1;
01061 res->distance = d;
01062 VcV(res->p1, p);
01063 VcV(res->p2, q);
01064
01065 }
01066
01067 return;
01068 }
01069
01070 int a1,a2,c1,c2;
01071 PQP_REAL R1[3][3], T1[3], R2[3][3], T2[3], Ttemp[3];
01072
01073 if (l2 || (!l1 && (sz1 > sz2)))
01074 {
01075
01076
01077 a1 = o1->child(b1)->first_child;
01078 a2 = b2;
01079 c1 = o1->child(b1)->first_child+1;
01080 c2 = b2;
01081
01082 MTxM(R1,o1->child(a1)->R,R);
01083 #if PQP_BV_TYPE & RSS_TYPE
01084 VmV(Ttemp,T,o1->child(a1)->Tr);
01085 #else
01086 VmV(Ttemp,T,o1->child(a1)->To);
01087 #endif
01088 MTxV(T1,o1->child(a1)->R,Ttemp);
01089
01090 MTxM(R2,o1->child(c1)->R,R);
01091 #if PQP_BV_TYPE & RSS_TYPE
01092 VmV(Ttemp,T,o1->child(c1)->Tr);
01093 #else
01094 VmV(Ttemp,T,o1->child(c1)->To);
01095 #endif
01096 MTxV(T2,o1->child(c1)->R,Ttemp);
01097 }
01098 else
01099 {
01100
01101
01102 a1 = b1;
01103 a2 = o2->child(b2)->first_child;
01104 c1 = b1;
01105 c2 = o2->child(b2)->first_child+1;
01106
01107 MxM(R1,R,o2->child(a2)->R);
01108 #if PQP_BV_TYPE & RSS_TYPE
01109 MxVpV(T1,R,o2->child(a2)->Tr,T);
01110 #else
01111 MxVpV(T1,R,o2->child(a2)->To,T);
01112 #endif
01113 MxM(R2,R,o2->child(c2)->R);
01114 #if PQP_BV_TYPE & RSS_TYPE
01115 MxVpV(T2,R,o2->child(c2)->Tr,T);
01116 #else
01117 MxVpV(T2,R,o2->child(c2)->To,T);
01118 #endif
01119 }
01120
01121 res->num_bv_tests += 2;
01122
01123 PQP_REAL d1 = BV_Distance(R1, T1, o1->child(a1), o2->child(a2));
01124 PQP_REAL d2 = BV_Distance(R2, T2, o1->child(c1), o2->child(c2));
01125
01126 if (d2 < d1)
01127 {
01128 if (d2 <= res->tolerance) ToleranceRecurse(res, R2, T2, o1, c1, o2, c2);
01129 if (res->closer_than_tolerance) return;
01130 if (d1 <= res->tolerance) ToleranceRecurse(res, R1, T1, o1, a1, o2, a2);
01131 }
01132 else
01133 {
01134 if (d1 <= res->tolerance) ToleranceRecurse(res, R1, T1, o1, a1, o2, a2);
01135 if (res->closer_than_tolerance) return;
01136 if (d2 <= res->tolerance) ToleranceRecurse(res, R2, T2, o1, c1, o2, c2);
01137 }
01138 }
01139
01140 void
01141 ToleranceQueueRecurse(PQP_ToleranceResult *res,
01142 PQP_REAL R[3][3], PQP_REAL T[3],
01143 PQP_Model *o1, int b1,
01144 PQP_Model *o2, int b2)
01145 {
01146 BVTQ bvtq(res->qsize);
01147 BVT min_test;
01148 min_test.b1 = b1;
01149 min_test.b2 = b2;
01150 McM(min_test.R,R);
01151 VcV(min_test.T,T);
01152
01153 while(1)
01154 {
01155 int l1 = o1->child(min_test.b1)->Leaf();
01156 int l2 = o2->child(min_test.b2)->Leaf();
01157
01158 if (l1 && l2)
01159 {
01160
01161
01162 res->num_tri_tests++;
01163
01164 PQP_REAL p[3], q[3];
01165
01166 Tri *t1 = &o1->tris[-o1->child(min_test.b1)->first_child - 1];
01167 Tri *t2 = &o2->tris[-o2->child(min_test.b2)->first_child - 1];
01168
01169 PQP_REAL d = TriDistance(res->R,res->T,t1,t2,p,q);
01170
01171 if (d <= res->tolerance)
01172 {
01173
01174
01175 res->closer_than_tolerance = 1;
01176 res->distance = d;
01177 VcV(res->p1, p);
01178 VcV(res->p2, q);
01179
01180 return;
01181 }
01182 }
01183 else if (bvtq.GetNumTests() == bvtq.GetSize() - 1)
01184 {
01185
01186
01187 ToleranceQueueRecurse(res,min_test.R,min_test.T,
01188 o1,min_test.b1,o2,min_test.b2);
01189 if (res->closer_than_tolerance == 1) return;
01190 }
01191 else
01192 {
01193
01194
01195 PQP_REAL sz1 = o1->child(min_test.b1)->GetSize();
01196 PQP_REAL sz2 = o2->child(min_test.b2)->GetSize();
01197
01198 res->num_bv_tests += 2;
01199
01200 BVT bvt1,bvt2;
01201 PQP_REAL Ttemp[3];
01202
01203 if (l2 || (!l1 && (sz1 > sz2)))
01204 {
01205
01206
01207
01208 int c1 = o1->child(min_test.b1)->first_child;
01209 int c2 = c1 + 1;
01210
01211
01212
01213 bvt1.b1 = c1;
01214 bvt1.b2 = min_test.b2;
01215 MTxM(bvt1.R,o1->child(c1)->R,min_test.R);
01216 #if PQP_BV_TYPE & RSS_TYPE
01217 VmV(Ttemp,min_test.T,o1->child(c1)->Tr);
01218 #else
01219 VmV(Ttemp,min_test.T,o1->child(c1)->To);
01220 #endif
01221 MTxV(bvt1.T,o1->child(c1)->R,Ttemp);
01222 bvt1.d = BV_Distance(bvt1.R,bvt1.T,
01223 o1->child(bvt1.b1),o2->child(bvt1.b2));
01224
01225
01226
01227 bvt2.b1 = c2;
01228 bvt2.b2 = min_test.b2;
01229 MTxM(bvt2.R,o1->child(c2)->R,min_test.R);
01230 #if PQP_BV_TYPE & RSS_TYPE
01231 VmV(Ttemp,min_test.T,o1->child(c2)->Tr);
01232 #else
01233 VmV(Ttemp,min_test.T,o1->child(c2)->To);
01234 #endif
01235 MTxV(bvt2.T,o1->child(c2)->R,Ttemp);
01236 bvt2.d = BV_Distance(bvt2.R,bvt2.T,
01237 o1->child(bvt2.b1),o2->child(bvt2.b2));
01238 }
01239 else
01240 {
01241
01242
01243
01244 int c1 = o2->child(min_test.b2)->first_child;
01245 int c2 = c1 + 1;
01246
01247
01248
01249 bvt1.b1 = min_test.b1;
01250 bvt1.b2 = c1;
01251 MxM(bvt1.R,min_test.R,o2->child(c1)->R);
01252 #if PQP_BV_TYPE & RSS_TYPE
01253 MxVpV(bvt1.T,min_test.R,o2->child(c1)->Tr,min_test.T);
01254 #else
01255 MxVpV(bvt1.T,min_test.R,o2->child(c1)->To,min_test.T);
01256 #endif
01257 bvt1.d = BV_Distance(bvt1.R,bvt1.T,
01258 o1->child(bvt1.b1),o2->child(bvt1.b2));
01259
01260
01261
01262 bvt2.b1 = min_test.b1;
01263 bvt2.b2 = c2;
01264 MxM(bvt2.R,min_test.R,o2->child(c2)->R);
01265 #if PQP_BV_TYPE & RSS_TYPE
01266 MxVpV(bvt2.T,min_test.R,o2->child(c2)->Tr,min_test.T);
01267 #else
01268 MxVpV(bvt2.T,min_test.R,o2->child(c2)->To,min_test.T);
01269 #endif
01270 bvt2.d = BV_Distance(bvt2.R,bvt2.T,
01271 o1->child(bvt2.b1),o2->child(bvt2.b2));
01272 }
01273
01274
01275
01276 if (bvt1.d <= res->tolerance) bvtq.AddTest(bvt1);
01277 if (bvt2.d <= res->tolerance) bvtq.AddTest(bvt2);
01278 }
01279
01280 if (bvtq.Empty() || (bvtq.MinTest() > res->tolerance))
01281 {
01282 res->closer_than_tolerance = 0;
01283 return;
01284 }
01285 else
01286 {
01287 min_test = bvtq.ExtractMinTest();
01288 }
01289 }
01290 }
01291
01292 int
01293 PQP_Tolerance(PQP_ToleranceResult *res,
01294 PQP_REAL R1[3][3], PQP_REAL T1[3], PQP_Model *o1,
01295 PQP_REAL R2[3][3], PQP_REAL T2[3], PQP_Model *o2,
01296 PQP_REAL tolerance,
01297 int qsize)
01298 {
01299 double time1 = GetTime();
01300
01301
01302
01303 if (o1->build_state != PQP_BUILD_STATE_PROCESSED)
01304 return PQP_ERR_UNPROCESSED_MODEL;
01305 if (o2->build_state != PQP_BUILD_STATE_PROCESSED)
01306 return PQP_ERR_UNPROCESSED_MODEL;
01307
01308
01309
01310
01311 MTxM(res->R,R1,R2);
01312 PQP_REAL Ttemp[3];
01313 VmV(Ttemp, T2, T1);
01314 MTxV(res->T, R1, Ttemp);
01315
01316
01317
01318 if (tolerance < 0.0) tolerance = 0.0;
01319 res->tolerance = tolerance;
01320
01321
01322
01323 res->num_bv_tests = 0;
01324 res->num_tri_tests = 0;
01325
01326
01327
01328 res->closer_than_tolerance = 0;
01329
01330
01331
01332 PQP_REAL Rtemp[3][3], R[3][3], T[3];
01333
01334 MxM(Rtemp,res->R,o2->child(0)->R);
01335 MTxM(R,o1->child(0)->R,Rtemp);
01336 #if PQP_BV_TYPE & RSS_TYPE
01337 MxVpV(Ttemp,res->R,o2->child(0)->Tr,res->T);
01338 VmV(Ttemp,Ttemp,o1->child(0)->Tr);
01339 #else
01340 MxVpV(Ttemp,res->R,o2->child(0)->To,res->T);
01341 VmV(Ttemp,Ttemp,o1->child(0)->To);
01342 #endif
01343 MTxV(T,o1->child(0)->R,Ttemp);
01344
01345
01346
01347 PQP_REAL d = BV_Distance(R, T, o1->child(0), o2->child(0));
01348
01349 if (d <= res->tolerance)
01350 {
01351
01352
01353 if (qsize <= 2)
01354 {
01355 ToleranceRecurse(res, R, T, o1, 0, o2, 0);
01356 }
01357 else
01358 {
01359 res->qsize = qsize;
01360 ToleranceQueueRecurse(res, R, T, o1, 0, o2, 0);
01361 }
01362 }
01363
01364
01365
01366 PQP_REAL u[3];
01367 VmV(u, res->p2, res->T);
01368 MTxV(res->p2, res->R, u);
01369
01370 double time2 = GetTime();
01371 res->query_time_secs = time2 - time1;
01372
01373 return PQP_OK;
01374 }
01375
01376 #endif