00001 #ifndef PDOMAIN_H_INCLUDED
00002 #define PDOMAIN_H_INCLUDED
00003
00004 #include "pVec.h"
00005
00006 class pDomain
00007 {
00008 public:
00009 virtual bool Within(const pVec &) const = 0;
00010 virtual pVec Generate() const = 0;
00011
00012 virtual pDomain *copy() const = 0;
00013
00014 virtual ~pDomain() {}
00015 };
00016
00017
00018 class PDPoint : public pDomain
00019 {
00020 public:
00021 pVec p;
00022
00023 public:
00024 PDPoint(const pVec &p0)
00025 {
00026 p = p0;
00027 }
00028
00029 ~PDPoint()
00030 {
00031 }
00032
00033 bool Within(const pVec &pos) const
00034 {
00035 return false;
00036 }
00037
00038 pVec Generate() const
00039 {
00040 return p;
00041 }
00042
00043 pDomain *copy() const
00044 {
00045 PDPoint *P = new PDPoint(*this);
00046 return P;
00047 }
00048 };
00049
00050
00051 class PDLine : public pDomain
00052 {
00053 public:
00054 pVec p0, p1;
00055
00056 public:
00057 PDLine(const pVec &e0, const pVec &e1)
00058 {
00059 p0 = e0;
00060 p1 = e1 - e0;
00061 }
00062
00063 ~PDLine()
00064 {
00065 }
00066
00067 bool Within(const pVec &pos) const
00068 {
00069 return false;
00070 }
00071
00072 pVec Generate() const
00073 {
00074 return p0 + p1 * pRandf();
00075 }
00076
00077 pDomain *copy() const
00078 {
00079 PDLine *P = new PDLine(*this);
00080 return P;
00081 }
00082 };
00083
00084
00085 class PDTriangle : public pDomain
00086 {
00087 public:
00088 pVec p, u, v, uNrm, vNrm, nrm;
00089 float uLen, vLen, D;
00090
00091 public:
00092 PDTriangle(const pVec &p0, const pVec &p1, const pVec &p2)
00093 {
00094 p = p0;
00095 u = p1 - p0;
00096 v = p2 - p0;
00097
00098
00099 uLen = u.length();
00100 uNrm = u / uLen;
00101 vLen = v.length();
00102 vNrm = v / vLen;
00103
00104 nrm = Cross(uNrm, vNrm);
00105 nrm.normalize();
00106
00107 D = -(p * nrm);
00108 }
00109
00110 ~PDTriangle()
00111 {
00112 }
00113
00114 bool Within(const pVec &pos) const
00115 {
00116 return false;
00117 }
00118
00119 pVec Generate() const
00120 {
00121 float r1 = pRandf();
00122 float r2 = pRandf();
00123 pVec pos;
00124 if(r1 + r2 < 1.0f)
00125 pos = p + u * r1 + v * r2;
00126 else
00127 pos = p + u * (1.0f-r1) + v * (1.0f-r2);
00128
00129 return pos;
00130 }
00131
00132 pDomain *copy() const
00133 {
00134 PDTriangle *P = new PDTriangle(*this);
00135 return P;
00136 }
00137 };
00138
00139
00140 class PDRectangle : public pDomain
00141 {
00142 public:
00143 pVec p, u, v, uNrm, vNrm, nrm;
00144 float uLen, vLen, D;
00145
00146 public:
00147 PDRectangle(const pVec &p0, const pVec &u0, const pVec &v0)
00148 {
00149 p = p0;
00150 u = u0;
00151 v = v0;
00152
00153
00154 uLen = u.length();
00155 uNrm = u / uLen;
00156 vLen = v.length();
00157 vNrm = v / vLen;
00158
00159 nrm = Cross(uNrm, vNrm);
00160 nrm.normalize();
00161
00162 D = -(p * nrm);
00163 }
00164
00165 ~PDRectangle()
00166 {
00167
00168 }
00169
00170 bool Within(const pVec &pos) const
00171 {
00172 return false;
00173 }
00174
00175 pVec Generate() const
00176 {
00177 pVec pos = p + u * pRandf() + v * pRandf();
00178 return pos;
00179 }
00180
00181 pDomain *copy() const
00182 {
00183 PDRectangle *P = new PDRectangle(*this);
00184 return P;
00185 }
00186 };
00187
00188
00189 class PDPlane : public pDomain
00190 {
00191 public:
00192 pVec p, nrm;
00193 float D;
00194
00195 public:
00196 PDPlane(const pVec &p0, const pVec &nrm0)
00197 {
00198 p = p0;
00199 nrm = nrm0;
00200 nrm.normalize();
00201 D = -(p * nrm);
00202 }
00203
00204 ~PDPlane()
00205 {
00206 }
00207
00208
00209
00210 bool Within(const pVec &pos) const
00211 {
00212 return nrm * pos >= -D;
00213 }
00214
00215
00216 pVec Generate() const
00217 {
00218 return p;
00219 }
00220
00221 pDomain *copy() const
00222 {
00223 PDPlane *P = new PDPlane(*this);
00224 return P;
00225 }
00226 };
00227
00228
00229 class PDBox : public pDomain
00230 {
00231 public:
00232
00233 pVec p0, p1, dif;
00234
00235 public:
00236 PDBox(const pVec &e0, const pVec &e1)
00237 {
00238 p0 = e0;
00239 p1 = e1;
00240 if(e1.x() < e0.x()) { p0.x() = e1.x(); p1.x() = e1.x(); }
00241 if(e1.y() < e0.y()) { p0.y() = e1.y(); p1.y() = e1.y(); }
00242 if(e1.z() < e0.z()) { p0.z() = e1.z(); p1.z() = e1.z(); }
00243
00244 dif = p1 - p0;
00245 }
00246
00247 ~PDBox()
00248 {
00249 }
00250
00251 bool Within(const pVec &pos) const
00252 {
00253 return !((pos.x() < p0.x()) || (pos.x() > p1.x()) ||
00254 (pos.y() < p0.y()) || (pos.y() > p1.y()) ||
00255 (pos.z() < p0.z()) || (pos.z() > p1.z()));
00256 }
00257
00258 pVec Generate() const
00259 {
00260
00261 return p0 + CompMult(pRandVec(), dif);
00262 }
00263
00264 pDomain *copy() const
00265 {
00266 PDBox *P = new PDBox(*this);
00267 return P;
00268 }
00269 };
00270
00271
00272 class PDCylinder : public pDomain
00273 {
00274 public:
00275 pVec apex, axis, u, v;
00276 float len, radOut, radIn, radOutSqr, radInSqr, radDif, axisLenInvSqr;
00277 bool ThinShell;
00278
00279 public:
00280 PDCylinder(const pVec &e0, const pVec &e1, const float radOut0, const float radIn0 = 0.0f)
00281 {
00282 apex = e0;
00283 axis = e1 - e0;
00284
00285 if(radOut0 < radIn0) {
00286 radOut = radIn0; radIn = radOut0;
00287 } else {
00288 radOut = radOut0; radIn = radIn0;
00289 }
00290 radOutSqr = fsqr(radOut);
00291 radInSqr = fsqr(radIn);
00292
00293 ThinShell = (radIn == radOut);
00294 radDif = radOut - radIn;
00295
00296
00297
00298 pVec n = axis;
00299 float axisLenSqr = axis.length2();
00300 axisLenInvSqr = axisLenSqr ? (1.0f / axisLenSqr) : 0.0f;
00301 n *= sqrtf(axisLenInvSqr);
00302
00303
00304 pVec basis(1.0f, 0.0f, 0.0f);
00305 if (fabsf(basis * n) > 0.999f)
00306 basis = pVec(0.0f, 1.0f, 0.0f);
00307
00308
00309
00310 u = basis - n * (basis * n);
00311 u.normalize();
00312 v = Cross(n, u);
00313 }
00314
00315 ~PDCylinder()
00316 {
00317 }
00318
00319 bool Within(const pVec &pos) const
00320 {
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 pVec x = pos - apex;
00331
00332
00333 float dist = (axis * x) * axisLenInvSqr;
00334 if(dist < 0.0f || dist > 1.0f)
00335 return false;
00336
00337
00338 pVec xrad = x - axis * dist;
00339 float rSqr = xrad.length2();
00340
00341 return (rSqr <= radInSqr && rSqr >= radOutSqr);
00342 }
00343
00344 pVec Generate() const
00345 {
00346 float dist = pRandf();
00347 float theta = pRandf() * 2.0f * float(M_PI);
00348
00349 float r = radIn + pRandf() * radDif;
00350
00351
00352 float x = r * cosf(theta);
00353 float y = r * sinf(theta);
00354
00355 pVec pos = apex + axis * dist + u * x + v * y;
00356 return pos;
00357 }
00358
00359 pDomain *copy() const
00360 {
00361 PDCylinder *P = new PDCylinder(*this);
00362 return P;
00363 }
00364 };
00365
00366
00367 class PDCone : public pDomain
00368 {
00369 public:
00370 pVec apex, axis, u, v;
00371 float len, radOut, radIn, radOutSqr, radInSqr, radDif, axisLenInvSqr;
00372 bool ThinShell;
00373
00374 public:
00375 PDCone(const pVec &e0, const pVec &e1, const float radOut0, const float radIn0 = 0.0f)
00376 {
00377 apex = e0;
00378 axis = e1 - e0;
00379
00380 if(radOut0 < radIn0) {
00381 radOut = radIn0; radIn = radOut0;
00382 } else {
00383 radOut = radOut0; radIn = radIn0;
00384 }
00385 radOutSqr = fsqr(radOut);
00386 radInSqr = fsqr(radIn);
00387
00388 ThinShell = (radIn == radOut);
00389 radDif = radOut - radIn;
00390
00391
00392
00393 pVec n = axis;
00394 float axisLenSqr = axis.length2();
00395 axisLenInvSqr = axisLenSqr ? 1.0f / axisLenSqr : 0.0f;
00396 n *= sqrtf(axisLenInvSqr);
00397
00398
00399 pVec basis(1.0f, 0.0f, 0.0f);
00400 if (fabsf(basis * n) > 0.999f)
00401 basis = pVec(0.0f, 1.0f, 0.0f);
00402
00403
00404
00405 u = basis - n * (basis * n);
00406 u.normalize();
00407 v = Cross(n, u);
00408 }
00409
00410 ~PDCone()
00411 {
00412 }
00413
00414 bool Within(const pVec &pos) const
00415 {
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 pVec x = pos - apex;
00427
00428
00429
00430 float dist = (axis * x) * axisLenInvSqr;
00431 if(dist < 0.0f || dist > 1.0f)
00432 return false;
00433
00434
00435 pVec xrad = x - axis * dist;
00436 float rSqr = xrad.length2();
00437
00438 return (rSqr <= fsqr(dist * radIn) && rSqr >= fsqr(dist * radOut));
00439 }
00440
00441 pVec Generate() const
00442 {
00443 float dist = pRandf();
00444 float theta = pRandf() * 2.0f * float(M_PI);
00445
00446 float r = radIn + pRandf() * radDif;
00447
00448
00449 float x = r * cosf(theta);
00450 float y = r * sinf(theta);
00451
00452
00453 x *= dist;
00454 y *= dist;
00455
00456 pVec pos = apex + axis * dist + u * x + v * y;
00457 return pos;
00458 }
00459
00460 pDomain *copy() const
00461 {
00462 PDCone *P = new PDCone(*this);
00463 return P;
00464 }
00465 };
00466
00467
00468 class PDSphere : public pDomain
00469 {
00470 public:
00471 pVec ctr;
00472 float radOut, radIn, radOutSqr, radInSqr, radDif;
00473 bool ThinShell;
00474
00475 public:
00476 PDSphere(const pVec &ctr0, const float radOut0, const float radIn0 = 0.0f)
00477 {
00478 ctr = ctr0;
00479 if(radOut0 < radIn0) {
00480 radOut = radIn0; radIn = radOut0;
00481 } else {
00482 radOut = radOut0; radIn = radIn0;
00483 }
00484 if(radIn < 0.0f) radIn = 0.0f;
00485
00486 radOutSqr = fsqr(radOut);
00487 radInSqr = fsqr(radIn);
00488
00489 ThinShell = (radIn == radOut);
00490 radDif = radOut - radIn;
00491 }
00492
00493 ~PDSphere()
00494 {
00495 }
00496
00497 bool Within(const pVec &pos) const
00498 {
00499 pVec rvec(pos - ctr);
00500 float rSqr = rvec.length2();
00501 return rSqr <= radOutSqr && rSqr >= radInSqr;
00502 }
00503
00504 pVec Generate() const
00505 {
00506 pVec pos;
00507
00508 do {
00509 pos = pRandVec() - vHalf;
00510 } while (pos.length2() > fsqr(0.5));
00511 pos.normalize();
00512
00513
00514 if(ThinShell)
00515 pos = ctr + pos * radOut;
00516 else
00517 pos = ctr + pos * (radIn + pRandf() * radDif);
00518
00519 return pos;
00520 }
00521
00522 pDomain *copy() const
00523 {
00524 PDSphere *P = new PDSphere(*this);
00525 return P;
00526 }
00527 };
00528
00529
00530 class PDBlob : public pDomain
00531 {
00532 public:
00533 pVec ctr;
00534 float stdev, Scale1, Scale2;
00535
00536 public:
00537 PDBlob(const pVec &ctr0, const float stdev0)
00538 {
00539 ctr = ctr0;
00540 stdev = stdev0;
00541 float oneOverSigma = 1.0f/(stdev+0.000000000001f);
00542 Scale1 = -0.5f*fsqr(oneOverSigma);
00543 Scale2 = P_ONEOVERSQRT2PI * oneOverSigma;
00544 }
00545
00546 ~PDBlob()
00547 {
00548 }
00549
00550 bool Within(const pVec &pos) const
00551 {
00552 pVec x = pos - ctr;
00553
00554 float Gx = expf(x.length2() * Scale1) * Scale2;
00555 return (pRandf() < Gx);
00556 }
00557
00558 pVec Generate() const
00559 {
00560 return ctr + pNRandVec(stdev);
00561 }
00562
00563 pDomain *copy() const
00564 {
00565 PDBlob *P = new PDBlob(*this);
00566 return P;
00567 }
00568 };
00569
00570
00571 class PDDisc : public pDomain
00572 {
00573 public:
00574 pVec p, nrm, u, v;
00575 float radIn, radOut, radInSqr, radOutSqr, dif, D;
00576
00577 public:
00578 PDDisc(const pVec &ctr0, const pVec nrm0, const float radOut0, const float radIn0 = 0.0f)
00579 {
00580 p = ctr0;
00581 nrm = nrm0;
00582 nrm.normalize();
00583
00584 if(radOut0 > radIn0) {
00585 radOut = radOut0; radIn = radIn0;
00586 } else {
00587 radOut = radIn0; radIn = radOut0;
00588 }
00589 dif = radOut - radIn;
00590 radInSqr = fsqr(radIn);
00591 radOutSqr = fsqr(radOut);
00592
00593
00594 pVec basis(1.0f, 0.0f, 0.0f);
00595 if (fabsf(basis * nrm) > 0.999f)
00596 basis = pVec(0.0f, 1.0f, 0.0f);
00597
00598
00599
00600 u = basis - nrm * (basis * nrm);
00601 u.normalize();
00602 v = Cross(nrm, u);
00603 D = -(p * nrm);
00604 }
00605
00606 ~PDDisc()
00607 {
00608 }
00609
00610 bool Within(const pVec &pos) const
00611 {
00612 return false;
00613 }
00614
00615 pVec Generate() const
00616 {
00617
00618 float theta = pRandf() * 2.0f * float(M_PI);
00619
00620 float r = radIn + pRandf() * dif;
00621
00622 float x = r * cosf(theta);
00623 float y = r * sinf(theta);
00624
00625 pVec pos = p + u * x + v * y;
00626 return pos;
00627 }
00628
00629 pDomain *copy() const
00630 {
00631 PDDisc *P = new PDDisc(*this);
00632 return P;
00633 }
00634 };
00635
00636 #endif // PDOMAIN_H_INCLUDED