00001
00002
00003
00004
00005
00006
00007
00008 #ifndef pdomain_h
00009 #define pdomain_h
00010
00011 #include "pError.h"
00012 #include "pVec.h"
00013
00014 #include <vector>
00015
00016 namespace PAPI
00017 {
00018 const float P_PLANAR_EPSILON = 1e-3f;
00019
00038 class pDomain
00039 {
00040 public:
00041 virtual bool Within(const pVec &) const = 0;
00042 virtual pVec Generate() const = 0;
00043 virtual float Size() const = 0;
00044
00045 virtual pDomain *copy() const = 0;
00046
00047 virtual ~pDomain() {}
00048 };
00049
00061 class PDUnion : public pDomain
00062 {
00063 public:
00064 std::vector<pDomain *> Doms;
00065 float TotalSize;
00066
00067 public:
00068 PDUnion()
00069 {
00070 TotalSize = 0.0f;
00071 }
00072
00073 PDUnion(const pDomain &A, const pDomain &B)
00074 {
00075 TotalSize = A.Size() + B.Size();
00076 Doms.push_back(A.copy());
00077 Doms.push_back(B.copy());
00078 }
00079
00080 PDUnion(const pDomain &A, const pDomain &B, const pDomain &C)
00081 {
00082 TotalSize = A.Size() + B.Size() + C.Size();
00083 Doms.push_back(A.copy());
00084 Doms.push_back(B.copy());
00085 Doms.push_back(C.copy());
00086 }
00087
00091 PDUnion(const std::vector<pDomain *> &DomList)
00092 {
00093 TotalSize = 0.0f;
00094 for(std::vector<pDomain *>::const_iterator it = DomList.begin(); it != DomList.end(); it++) {
00095 Doms.push_back((*it)->copy());
00096 TotalSize += (*it)->Size();
00097 }
00098 }
00099
00100
00101 PDUnion(const PDUnion &P)
00102 {
00103 TotalSize = 0.0f;
00104 for(std::vector<pDomain *>::const_iterator it = P.Doms.begin(); it != P.Doms.end(); it++) {
00105 Doms.push_back((*it)->copy());
00106 TotalSize += (*it)->Size();
00107 }
00108 }
00109
00110 ~PDUnion()
00111 {
00112 for(std::vector<pDomain *>::const_iterator it = Doms.begin(); it != Doms.end(); it++) {
00113 delete (*it);
00114 }
00115 }
00116
00118 void insert(const pDomain &A)
00119 {
00120 TotalSize += A.Size();
00121 Doms.push_back(A.copy());
00122 }
00123
00124 bool Within(const pVec &pos) const
00125 {
00126 for(std::vector<pDomain *>::const_iterator it = Doms.begin(); it != Doms.end(); it++)
00127 if((*it)->Within(pos)) return true;
00128 return false;
00129 }
00130
00131 pVec Generate() const
00132 {
00133 float Choose = pRandf() * TotalSize, PastProb = 0.0f;
00134 for(std::vector<pDomain *>::const_iterator it = Doms.begin(); it != Doms.end(); it++) {
00135 PastProb += (*it)->Size();
00136 if(Choose <= PastProb)
00137 return (*it)->Generate();
00138 }
00139 throw PErrInternalError("Sizes didn't add up to TotalSize in PDUnion::Generate().");
00140 }
00141
00142 float Size() const
00143 {
00144 return TotalSize;
00145 }
00146
00147 pDomain *copy() const
00148 {
00149 PDUnion *P = new PDUnion(*this);
00150 return P;
00151 }
00152 };
00153
00157 class PDPoint : public pDomain
00158 {
00159 public:
00160 pVec p;
00161
00162 public:
00163 PDPoint(const pVec &p0)
00164 {
00165 p = p0;
00166 }
00167
00168 ~PDPoint()
00169 {
00170
00171 }
00172
00173 bool Within(const pVec &pos) const
00174 {
00175 return p == pos;
00176 }
00177
00178 pVec Generate() const
00179 {
00180 return p;
00181 }
00182
00183 float Size() const
00184 {
00185 return 1.0f;
00186 }
00187
00188 pDomain *copy() const
00189 {
00190 PDPoint *P = new PDPoint(*this);
00191 return P;
00192 }
00193 };
00194
00200 class PDLine : public pDomain
00201 {
00202 public:
00203 pVec p0, vec, vecNrm;
00204 float len;
00205
00206 public:
00207 PDLine(const pVec &e0, const pVec &e1)
00208 {
00209 p0 = e0;
00210 vec = e1 - e0;
00211 vecNrm = vec;
00212 vecNrm.normalize();
00213 len = vec.length();
00214 }
00215
00216 ~PDLine()
00217 {
00218 }
00219
00220 bool Within(const pVec &pos) const
00221 {
00222 pVec to = pos - p0;
00223 float d = dot(vecNrm, to);
00224 float dif = fabs(d - to.length()) / len;
00225 return dif < 1e-7f;
00226 }
00227
00228 pVec Generate() const
00229 {
00230 return p0 + vec * pRandf();
00231 }
00232
00233 float Size() const
00234 {
00235 return len;
00236 }
00237
00238 pDomain *copy() const
00239 {
00240 PDLine *P = new PDLine(*this);
00241 return P;
00242 }
00243 };
00244
00245
00246 static inline void NewBasis(const pVec &u, const pVec &v, pVec &s1, pVec &s2)
00247 {
00248 pVec w = Cross(u, v);
00249
00250 float det = 1.0f / (w.z()*u.x()*v.y() - w.z()*u.y()*v.x() - u.z()*w.x()*v.y() - u.x()*v.z()*w.y() + v.z()*w.x()*u.y() + u.z()*v.x()*w.y());
00251
00252 s1 = pVec((v.y()*w.z() - v.z()*w.y()), (v.z()*w.x() - v.x()*w.z()), (v.x()*w.y() - v.y()*w.x()));
00253 s1 *= det;
00254 s2 = pVec((u.y()*w.z() - u.z()*w.y()), (u.z()*w.x() - u.x()*w.z()), (u.x()*w.y() - u.y()*w.x()));
00255 s2 *= -det;
00256 }
00257
00261
00265 class PDTriangle : public pDomain
00266 {
00267 public:
00268 pVec p, u, v, uNrm, vNrm, nrm, s1, s2;
00269 float uLen, vLen, D, area;
00270
00271 public:
00272 PDTriangle(const pVec &p0, const pVec &p1, const pVec &p2)
00273 {
00274 p = p0;
00275 u = p1 - p0;
00276 v = p2 - p0;
00277
00278 uLen = u.length();
00279 uNrm = u / uLen;
00280 vLen = v.length();
00281 vNrm = v / vLen;
00282
00283 nrm = Cross(uNrm, vNrm);
00284 nrm.normalize();
00285
00286 D = -dot(p, nrm);
00287
00288 NewBasis(u, v, s1, s2);
00289
00290
00291 pVec Hgt = v - uNrm * dot(uNrm, v);
00292 float h = Hgt.length();
00293 area = 0.5f * uLen * h;
00294 }
00295
00296 ~PDTriangle()
00297 {
00298 }
00299
00300 bool Within(const pVec &pos) const
00301 {
00302 pVec offset = pos - p;
00303 float d = dot(offset, nrm);
00304
00305 if(d > P_PLANAR_EPSILON) return false;
00306
00307
00308
00309 float upos = dot(offset, s1);
00310 float vpos = dot(offset, s2);
00311
00312
00313 return !(upos < 0 || vpos < 0 || (upos + vpos) > 1);
00314 }
00315
00316 pVec Generate() const
00317 {
00318 float r1 = pRandf();
00319 float r2 = pRandf();
00320 pVec pos;
00321 if(r1 + r2 < 1.0f)
00322 pos = p + u * r1 + v * r2;
00323 else
00324 pos = p + u * (1.0f-r1) + v * (1.0f-r2);
00325
00326 return pos;
00327 }
00328
00329 float Size() const
00330 {
00331 return area;
00332 }
00333
00334 pDomain *copy() const
00335 {
00336 PDTriangle *P = new PDTriangle(*this);
00337 return P;
00338 }
00339 };
00340
00346 class PDRectangle : public pDomain
00347 {
00348 public:
00349 pVec p, u, v, uNrm, vNrm, nrm, s1, s2;
00350 float uLen, vLen, D, area;
00351
00352 public:
00353 PDRectangle(const pVec &p0, const pVec &u0, const pVec &v0)
00354 {
00355 p = p0;
00356 u = u0;
00357 v = v0;
00358
00359 uLen = u.length();
00360 uNrm = u / uLen;
00361 vLen = v.length();
00362 vNrm = v / vLen;
00363
00364 nrm = Cross(uNrm, vNrm);
00365 nrm.normalize();
00366
00367 D = -dot(p, nrm);
00368
00369 NewBasis(u, v, s1, s2);
00370
00371
00372 pVec Hgt = v - uNrm * dot(uNrm, v);
00373 float h = Hgt.length();
00374 area = uLen * h;
00375 }
00376
00377 ~PDRectangle()
00378 {
00379
00380 }
00381
00382 bool Within(const pVec &pos) const
00383 {
00384 pVec offset = pos - p;
00385 float d = dot(offset, nrm);
00386
00387 if(d > P_PLANAR_EPSILON) return false;
00388
00389
00390
00391 float upos = dot(offset, s1);
00392 float vpos = dot(offset, s2);
00393
00394
00395 return !(upos < 0 || upos > 1 || vpos < 0 || vpos > 1);
00396 }
00397
00398 pVec Generate() const
00399 {
00400 pVec pos = p + u * pRandf() + v * pRandf();
00401 return pos;
00402 }
00403
00404 float Size() const
00405 {
00406 return area;
00407 }
00408
00409 pDomain *copy() const
00410 {
00411 PDRectangle *P = new PDRectangle(*this);
00412 return P;
00413 }
00414 };
00415
00422 class PDDisc : public pDomain
00423 {
00424 public:
00425 pVec p, nrm, u, v;
00426 float radIn, radOut, radInSqr, radOutSqr, dif, D, area;
00427
00428 public:
00429 PDDisc(const pVec &Center, const pVec Normal, const float OuterRadius, const float InnerRadius = 0.0f)
00430 {
00431 p = Center;
00432 nrm = Normal;
00433 nrm.normalize();
00434
00435 if(InnerRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00436 if(OuterRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00437
00438 if(OuterRadius > InnerRadius) {
00439 radOut = OuterRadius; radIn = InnerRadius;
00440 } else {
00441 radOut = InnerRadius; radIn = OuterRadius;
00442 }
00443
00444 radInSqr = fsqr(radIn);
00445 radOutSqr = fsqr(radOut);
00446 dif = radOut - radIn;
00447
00448
00449 pVec basis(1.0f, 0.0f, 0.0f);
00450 if (fabsf(dot(basis, nrm)) > 0.999f)
00451 basis = pVec(0.0f, 1.0f, 0.0f);
00452
00453
00454
00455 u = basis - nrm * dot(basis, nrm);
00456 u.normalize();
00457 v = Cross(nrm, u);
00458 D = -dot(p, nrm);
00459
00460 if(dif == 0.0f)
00461 area = 2.0f * M_PI * radOut;
00462 else
00463 area = M_PI * radOutSqr - M_PI * radInSqr;
00464 }
00465
00466 ~PDDisc()
00467 {
00468 }
00469
00470 bool Within(const pVec &pos) const
00471 {
00472 pVec offset = pos - p;
00473 float d = dot(offset, nrm);
00474
00475 if(d > P_PLANAR_EPSILON) return false;
00476
00477 float len = offset.length2();
00478 return len >= radInSqr && len <= radOutSqr;
00479 }
00480
00481 pVec Generate() const
00482 {
00483
00484 float theta = pRandf() * 2.0f * float(M_PI);
00485
00486 float r = radIn + pRandf() * dif;
00487
00488 float x = r * cosf(theta);
00489 float y = r * sinf(theta);
00490
00491 pVec pos = p + u * x + v * y;
00492 return pos;
00493 }
00494
00495 float Size() const
00496 {
00497 return 1.0f;
00498 }
00499
00500 pDomain *copy() const
00501 {
00502 PDDisc *P = new PDDisc(*this);
00503 return P;
00504 }
00505 };
00506
00513 class PDPlane : public pDomain
00514 {
00515 public:
00516 pVec p, nrm;
00517 float D;
00518
00519 public:
00520 PDPlane(const pVec &p0, const pVec &Normal)
00521 {
00522 p = p0;
00523 nrm = Normal;
00524 nrm.normalize();
00525 D = -dot(p, nrm);
00526 }
00527
00528 ~PDPlane()
00529 {
00530 }
00531
00532
00533
00534 bool Within(const pVec &pos) const
00535 {
00536 return dot(nrm, pos) >= -D;
00537 }
00538
00539
00540 pVec Generate() const
00541 {
00542 return p;
00543 }
00544
00545 float Size() const
00546 {
00547 return 1.0f;
00548 }
00549
00550 pDomain *copy() const
00551 {
00552 PDPlane *P = new PDPlane(*this);
00553 return P;
00554 }
00555 };
00556
00565 class PDBox : public pDomain
00566 {
00567 public:
00568
00569 pVec p0, p1, dif;
00570 float vol;
00571
00572 public:
00573 PDBox(const pVec &e0, const pVec &e1)
00574 {
00575 p0 = e0;
00576 p1 = e1;
00577 if(e1.x() < e0.x()) { p0.x() = e1.x(); p1.x() = e0.x(); }
00578 if(e1.y() < e0.y()) { p0.y() = e1.y(); p1.y() = e0.y(); }
00579 if(e1.z() < e0.z()) { p0.z() = e1.z(); p1.z() = e0.z(); }
00580
00581 dif = p1 - p0;
00582 vol = dot(dif, pVec(1,1,1));
00583 }
00584
00585 ~PDBox()
00586 {
00587 }
00588
00589 bool Within(const pVec &pos) const
00590 {
00591 return !((pos.x() < p0.x()) || (pos.x() > p1.x()) ||
00592 (pos.y() < p0.y()) || (pos.y() > p1.y()) ||
00593 (pos.z() < p0.z()) || (pos.z() > p1.z()));
00594 }
00595
00596 pVec Generate() const
00597 {
00598
00599 return p0 + CompMult(pRandVec(), dif);
00600 }
00601
00602 float Size() const
00603 {
00604 return vol;
00605 }
00606
00607 pDomain *copy() const
00608 {
00609 PDBox *P = new PDBox(*this);
00610 return P;
00611 }
00612 };
00613
00620 class PDCylinder : public pDomain
00621 {
00622 public:
00623 pVec apex, axis, u, v;
00624 float radOut, radIn, radOutSqr, radInSqr, radDif, axisLenInvSqr, vol;
00625 bool ThinShell;
00626
00627 public:
00628 PDCylinder(const pVec &e0, const pVec &e1, const float OuterRadius, const float InnerRadius = 0.0f)
00629 {
00630 apex = e0;
00631 axis = e1 - e0;
00632
00633 if(InnerRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00634 if(OuterRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00635
00636 if(OuterRadius < InnerRadius) {
00637 radOut = InnerRadius; radIn = OuterRadius;
00638 } else {
00639 radOut = OuterRadius; radIn = InnerRadius;
00640 }
00641
00642 radOutSqr = fsqr(radOut);
00643 radInSqr = fsqr(radIn);
00644
00645 ThinShell = (radIn == radOut);
00646 radDif = radOut - radIn;
00647
00648
00649
00650 pVec n = axis;
00651 float axisLenSqr = axis.length2();
00652 float len = sqrtf(axisLenSqr);
00653 axisLenInvSqr = axisLenSqr ? (1.0f / axisLenSqr) : 0.0f;
00654 n *= sqrtf(axisLenInvSqr);
00655
00656
00657 pVec basis(1.0f, 0.0f, 0.0f);
00658 if (fabsf(dot(basis, n)) > 0.999f)
00659 basis = pVec(0.0f, 1.0f, 0.0f);
00660
00661
00662
00663 u = basis - n * dot(basis, n);
00664 u.normalize();
00665 v = Cross(n, u);
00666
00667 float EndCapArea = M_PI * radOutSqr - M_PI * radInSqr;
00668 if(ThinShell)
00669 vol = len * 2.0f * M_PI * radOut;
00670 else
00671 vol = EndCapArea * len;
00672 }
00673
00674 ~PDCylinder()
00675 {
00676 }
00677
00678 bool Within(const pVec &pos) const
00679 {
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 pVec x = pos - apex;
00690
00691
00692 float dist = dot(axis, x) * axisLenInvSqr;
00693 if(dist < 0.0f || dist > 1.0f)
00694 return false;
00695
00696
00697 pVec xrad = x - axis * dist;
00698 float rSqr = xrad.length2();
00699
00700 return (rSqr >= radInSqr && rSqr <= radOutSqr);
00701 }
00702
00703 pVec Generate() const
00704 {
00705 float dist = pRandf();
00706 float theta = pRandf() * 2.0f * float(M_PI);
00707
00708 float r = radIn + pRandf() * radDif;
00709
00710
00711 float x = r * cosf(theta);
00712 float y = r * sinf(theta);
00713
00714 pVec pos = apex + axis * dist + u * x + v * y;
00715 return pos;
00716 }
00717
00718 float Size() const
00719 {
00720 return vol;
00721 }
00722
00723 pDomain *copy() const
00724 {
00725 PDCylinder *P = new PDCylinder(*this);
00726 return P;
00727 }
00728 };
00729
00739 class PDCone : public pDomain
00740 {
00741 public:
00742 pVec apex, axis, u, v;
00743 float radOut, radIn, radOutSqr, radInSqr, radDif, axisLenInvSqr, vol;
00744 bool ThinShell;
00745
00746 public:
00747 PDCone(const pVec &e0, const pVec &e1, const float OuterRadius, const float InnerRadius = 0.0f)
00748 {
00749 apex = e0;
00750 axis = e1 - e0;
00751
00752 if(InnerRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00753 if(OuterRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00754
00755 if(OuterRadius < InnerRadius) {
00756 radOut = InnerRadius; radIn = OuterRadius;
00757 } else {
00758 radOut = OuterRadius; radIn = InnerRadius;
00759 }
00760
00761 radOutSqr = fsqr(radOut);
00762 radInSqr = fsqr(radIn);
00763
00764 ThinShell = (radIn == radOut);
00765 radDif = radOut - radIn;
00766
00767
00768
00769 pVec n = axis;
00770 float axisLenSqr = axis.length2();
00771 float len = sqrtf(axisLenSqr);
00772 axisLenInvSqr = axisLenSqr ? 1.0f / axisLenSqr : 0.0f;
00773 n *= sqrtf(axisLenInvSqr);
00774
00775
00776 pVec basis(1.0f, 0.0f, 0.0f);
00777 if (fabsf(dot(basis, n)) > 0.999f)
00778 basis = pVec(0.0f, 1.0f, 0.0f);
00779
00780
00781
00782 u = basis - n * dot(basis, n);
00783 u.normalize();
00784 v = Cross(n, u);
00785
00786 if(ThinShell)
00787 vol = sqrtf(axisLenSqr + radOutSqr) * M_PI * radOut;
00788 else {
00789 float OuterVol = 0.33333333f * M_PI * radOutSqr * len;
00790 float InnerVol = 0.33333333f * M_PI * radInSqr * len;
00791 vol = OuterVol - InnerVol;
00792 }
00793 }
00794
00795 ~PDCone()
00796 {
00797 }
00798
00799 bool Within(const pVec &pos) const
00800 {
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 pVec x = pos - apex;
00812
00813
00814
00815 float dist = dot(axis, x) * axisLenInvSqr;
00816 if(dist < 0.0f || dist > 1.0f)
00817 return false;
00818
00819
00820 pVec xrad = x - axis * dist;
00821 float rSqr = xrad.length2();
00822
00823 return (rSqr >= fsqr(dist * radIn) && rSqr <= fsqr(dist * radOut));
00824 }
00825
00826 pVec Generate() const
00827 {
00828 float dist = pRandf();
00829 float theta = pRandf() * 2.0f * float(M_PI);
00830
00831 float r = radIn + pRandf() * radDif;
00832
00833
00834 float x = r * cosf(theta);
00835 float y = r * sinf(theta);
00836
00837
00838 x *= dist;
00839 y *= dist;
00840
00841 pVec pos = apex + axis * dist + u * x + v * y;
00842 return pos;
00843 }
00844
00845 float Size() const
00846 {
00847 return vol;
00848 }
00849
00850 pDomain *copy() const
00851 {
00852 PDCone *P = new PDCone(*this);
00853 return P;
00854 }
00855 };
00856
00863 class PDSphere : public pDomain
00864 {
00865 public:
00866 pVec ctr;
00867 float radOut, radIn, radOutSqr, radInSqr, radDif, vol;
00868 bool ThinShell;
00869
00870 public:
00871 PDSphere(const pVec &Center, const float OuterRadius, const float InnerRadius = 0.0f)
00872 {
00873 ctr = Center;
00874
00875 if(InnerRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00876 if(OuterRadius < 0) throw PErrInvalidValue("Can't have negative radius.");
00877
00878 if(OuterRadius < InnerRadius) {
00879 radOut = InnerRadius; radIn = OuterRadius;
00880 } else {
00881 radOut = OuterRadius; radIn = InnerRadius;
00882 }
00883
00884 radOutSqr = fsqr(radOut);
00885 radInSqr = fsqr(radIn);
00886
00887 ThinShell = (radIn == radOut);
00888 radDif = radOut - radIn;
00889
00890 if(ThinShell)
00891 vol = 4.0f * M_PI * radOutSqr;
00892 else {
00893 float OuterVol = 1.33333333f * M_PI * radOutSqr * radOut;
00894 float InnerVol = 1.33333333f * M_PI * radInSqr * radIn;
00895 vol = OuterVol - InnerVol;
00896 }
00897 }
00898
00899 ~PDSphere()
00900 {
00901 }
00902
00903 bool Within(const pVec &pos) const
00904 {
00905 pVec rvec(pos - ctr);
00906 float rSqr = rvec.length2();
00907 return rSqr <= radOutSqr && rSqr >= radInSqr;
00908 }
00909
00910 pVec Generate() const
00911 {
00912 pVec pos;
00913
00914 do {
00915 pos = pRandVec() - vHalf;
00916 } while (pos.length2() > fsqr(0.5));
00917 pos.normalize();
00918
00919
00920 if(ThinShell)
00921 pos = ctr + pos * radOut;
00922 else
00923 pos = ctr + pos * (radIn + pRandf() * radDif);
00924
00925 return pos;
00926 }
00927
00928 float Size() const
00929 {
00930 return vol;
00931 }
00932
00933 pDomain *copy() const
00934 {
00935 PDSphere *P = new PDSphere(*this);
00936 return P;
00937 }
00938 };
00939
00946 class PDBlob : public pDomain
00947 {
00948 public:
00949 pVec ctr;
00950 float stdev, Scale1, Scale2;
00951
00952 public:
00953 PDBlob(const pVec &Center, const float StandardDev)
00954 {
00955 ctr = Center;
00956 stdev = StandardDev;
00957 float oneOverSigma = 1.0f/(stdev+0.000000000001f);
00958 Scale1 = -0.5f*fsqr(oneOverSigma);
00959 Scale2 = P_ONEOVERSQRT2PI * oneOverSigma;
00960 }
00961
00962 ~PDBlob()
00963 {
00964 }
00965
00966 bool Within(const pVec &pos) const
00967 {
00968 pVec x = pos - ctr;
00969 float Gx = expf(x.length2() * Scale1) * Scale2;
00970 return (pRandf() < Gx);
00971 }
00972
00973 pVec Generate() const
00974 {
00975 return ctr + pNRandVec(stdev);
00976 }
00977
00978 float Size() const
00979 {
00980 return 1.0f;
00981 }
00982
00983 pDomain *copy() const
00984 {
00985 PDBlob *P = new PDBlob(*this);
00986 return P;
00987 }
00988 };
00989
00990 };
00991
00992 #endif