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
00042
00043
00044
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_POLYGON_3D_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_POLYGON_3D_INL
00047
00048 #include "prim_common.h"
00049 #include "simple_polygon_3d.h"
00050
00051 namespace lass
00052 {
00053 namespace prim
00054 {
00055
00056 template <typename T, class EP, class NP>
00057 SimplePolygon3D<T, EP, NP>::SimplePolygon3D(const TPlane& iPlane) : plane_(iPlane)
00058 {
00059 }
00060
00061 template <typename T, class EP, class NP>
00062 SimplePolygon3D<T, EP, NP>::SimplePolygon3D(const TPoint& iA, const TPoint& iB, const TPoint& iC) :
00063 plane_(iA,iB,iC)
00064 {
00065 add(iA);
00066 add(iB);
00067 add(iC);
00068 }
00069
00070
00071
00072
00073 template <typename T, class EP, class NP>
00074 const typename SimplePolygon3D<T, EP, NP>::TPoint&
00075 SimplePolygon3D<T, EP, NP>::operator[](size_t iIndexOfVertex) const
00076 {
00077 LASS_ASSERT(iIndexOfVertex < vertices_.size());
00078 return vertices_[iIndexOfVertex];
00079 }
00080
00081
00082
00083
00084
00085 template <typename T, class EP, class NP>
00086 typename SimplePolygon3D<T, EP, NP>::TPoint&
00087 SimplePolygon3D<T, EP, NP>::operator[](size_t iIndexOfVertex)
00088 {
00089 LASS_ASSERT(iIndexOfVertex < vertices_.size());
00090 return vertices_[iIndexOfVertex];
00091 }
00092
00093
00094
00095
00096
00097
00098 template <typename T, class EP, class NP>
00099 const typename SimplePolygon3D<T, EP, NP>::TPoint&
00100 SimplePolygon3D<T, EP, NP>::at(int iIndexOfVertex) const
00101 {
00102 const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00103 LASS_ASSERT(isInRange(i));
00104 return vertices_[i];
00105 }
00106
00107
00108
00109
00110
00111
00112 template <typename T, class EP, class NP>
00113 typename SimplePolygon3D<T, EP, NP>::TPoint&
00114 SimplePolygon3D<T, EP, NP>::at(int iIndexOfVertex)
00115 {
00116 const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00117 LASS_ASSERT(isInRange(i));
00118 return vertices_[i];
00119 }
00120
00121
00122
00123
00124
00125 template <typename T, class EP, class NP>
00126 const typename SimplePolygon3D<T, EP, NP>::TLineSegment
00127 SimplePolygon3D<T, EP, NP>::edge(int iIndexOfTailVertex) const
00128 {
00129 return SimplePolygon3D<T, EP, NP>::TLineSegment(at(iIndexOfTailVertex), at(iIndexOfTailVertex + 1));
00130 }
00131
00132
00133
00134
00135
00136 template <typename T, class EP, class NP>
00137 const typename SimplePolygon3D<T, EP, NP>::TVector
00138 SimplePolygon3D<T, EP, NP>::vector(int iIndexOfTailVertex) const
00139 {
00140 return at(iIndexOfTailVertex + 1) - at(iIndexOfTailVertex);
00141 }
00142
00143
00144
00145
00146
00147 template <typename T, class EP, class NP>
00148 const typename SimplePolygon3D<T, EP, NP>::TPlane&
00149 SimplePolygon3D<T, EP, NP>::plane() const
00150 {
00151 return plane_;
00152 }
00153
00154
00155
00156
00157
00158 template <typename T, class EP, class NP>
00159 typename SimplePolygon3D<T, EP, NP>::TPlane&
00160 SimplePolygon3D<T, EP, NP>::plane()
00161 {
00162 return plane_;
00163 }
00164
00165
00166
00167
00168
00169 template <typename T, class EP, class NP>
00170 const typename SimplePolygon3D<T, EP, NP>::TVector
00171 SimplePolygon3D<T, EP, NP>::normal() const
00172 {
00173 return plane_.normal();
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 template <typename T, class EP, class NP>
00186 const XYZ SimplePolygon3D<T, EP, NP>::majorAxis() const
00187 {
00188 return plane_.majorAxis();
00189 }
00190
00191
00192
00193
00194
00195 template <typename T, class EP, class NP>
00196 void SimplePolygon3D<T, EP, NP>::add(const TPoint& iVertex)
00197 {
00198 vertices_.push_back(iVertex);
00199 }
00200
00201
00202
00203
00204 template <typename T, class EP, class NP>
00205 void SimplePolygon3D<T, EP, NP>::insert(int iIndexOfVertex, const TPoint& iVertex)
00206 {
00207 const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00208 LASS_ASSERT(isInRange(i));
00209 vertices_.insert(i, iVertex);
00210 }
00211
00212
00213
00214
00215
00216 template <typename T, class EP, class NP>
00217 void SimplePolygon3D<T, EP, NP>::remove(int iIndexOfVertex)
00218 {
00219 const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00220 LASS_ASSERT(isInRange(i));
00221 vertices_.remove(i);
00222 }
00223
00224
00225
00226
00227
00228 template <typename T, class EP, class NP>
00229 const bool SimplePolygon3D<T, EP, NP>::isEmpty() const
00230 {
00231 return vertices_.empty();
00232 }
00233
00234
00235
00236
00237
00238 template <typename T, class EP, class NP>
00239 const size_t SimplePolygon3D<T, EP, NP>::size() const
00240 {
00241 return vertices_.size();
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 template <typename T, class EP, class NP>
00259 const typename SimplePolygon3D<T, EP, NP>::TValue
00260 SimplePolygon3D<T, EP, NP>::signedArea() const
00261 {
00262 const size_t n = size();
00263 if (size < 3)
00264 {
00265 return TNumTraits::zero;
00266 }
00267
00268 const TVector& normal = normal().normal();
00269 const TPoint& reference = vertices_[0];
00270 TValue result = TNumTraits::zero;
00271 for (size_t prevI = 1, i = 2; i < n; prevI = i++)
00272 {
00273 const TVector a = vertices_[prevI] - reference;
00274 const TVector b = vertices_[i] - reference;
00275 result += dot(cross(a, b), normal);
00276 }
00277 return result / 2;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 template <typename T, class EP, class NP>
00289 const typename SimplePolygon3D<T, EP, NP>::TValue
00290 SimplePolygon3D<T, EP, NP>::area() const
00291 {
00292 return num::abs(signedArea());
00293 }
00294
00295
00296
00297
00298
00299 template <typename T, class EP, class NP>
00300 const typename SimplePolygon3D<T, EP, NP>::TValue
00301 SimplePolygon3D<T, EP, NP>::perimeter() const
00302 {
00303 TValue result = TNumTraits::zero;
00304 for (int i = 0; i < size(); ++i)
00305 {
00306 result += distance(at(i).position, at(i + 1).position);
00307 }
00308 return result;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 template <typename T, class EP, class NP>
00318 const typename SimplePolygon3D<T, EP, NP>::TPointH
00319 SimplePolygon3D<T, EP, NP>::vertexCentroid() const
00320 {
00321 TPointH result;
00322 for (size_t i = 0; i < size(); ++i)
00323 {
00324 result += vertices_[i];
00325 }
00326 return result;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 template <typename T, class EP, class NP>
00344 const typename SimplePolygon3D<T, EP, NP>::TPointH
00345 SimplePolygon3D<T, EP, NP>::surfaceCentroid() const
00346 {
00347 const size_t n = size();
00348 if (n < 3)
00349 {
00350 return vertexCentroid();
00351 }
00352
00353 const TVector& normal = normal().normal();
00354 const TPoint& reference = vertices_[0];
00355 TPointH result;
00356 for (size_t prevI = 1, i = 2; i < n; prevI = i++)
00357 {
00358 const TVector a = vertices_[prevI] - reference;
00359 const TVector b = vertices_[i] - reference;
00360 const TValue triangleWeight = dot(cross(a, b), normal);
00361 const TPointH triangleCentroid = a + b + reference;
00362 result += triangleWeight * triangleCentroid;
00363 }
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 template <typename T, class EP, class NP>
00382 const bool SimplePolygon3D<T, EP, NP>::isSimple() const
00383 {
00384 return mapping(majorAxis()).isSimple();
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 template <typename T, class EP, class NP>
00406 const bool SimplePolygon3D<T, EP, NP>::isConvex() const
00407 {
00408 if (size() < 3)
00409 {
00410 return true;
00411 }
00412
00413 TValue sign = TNumTraits::zero;
00414 for (int i = 0; i < size(); ++i)
00415 {
00416 const TValue s = num::sign(perpDot(vector(i - 1), vector(i)));
00417 if (sign != s && s != TNumTraits::zero)
00418 {
00419 if (sign != TNumTraits::zero)
00420 {
00421 return false;
00422 }
00423 else
00424 {
00425 sign = s;
00426 }
00427 }
00428 }
00429
00430 return true;
00431 }
00432
00433
00434
00435
00436
00437
00438 template <typename T, class EP, class NP>
00439 const Orientation SimplePolygon3D<T, EP, NP>::orientation() const
00440 {
00441 const TValue area = signedArea();
00442 if (area > TNumTraits::zero)
00443 {
00444 return oCounterClockWise;
00445 }
00446 else if (area < TNumTraits::zero)
00447 {
00448 return oClockWise;
00449 }
00450 else
00451 {
00452 return oInvalid;
00453 }
00454 }
00455
00456
00457
00458
00459
00460
00461 template <typename T, class EP, class NP>
00462 const bool SimplePolygon3D<T, EP, NP>::isReflex(int iIndexOfVertex) const
00463 {
00464 return dot(cross(vector(iIndexOfVertex - 1), vector(iIndexOfVertex)), normal()) < 0;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 template <typename T, class EP, class NP>
00487 const SimplePolygon2D<T> SimplePolygon3D<T, EP, NP>::mapping(XYZ iAxis) const
00488 {
00489 const XYZ x = iAxis + 1;
00490 const XYZ y = iAxis + 2;
00491 SimplePolygon2D<T> result;
00492
00493 const int n = size();
00494 for (int i = 0; i < n; ++i)
00495 {
00496 result.add(Point2D<T>(vertices_[i][x], vertices_[i][y]));
00497 }
00498
00499 return result;
00500 }
00501
00502
00503
00504 template <typename T, class EP, class NP>
00505 const Side SimplePolygon3D<T, EP, NP>::classify(const TPoint& iP) const
00506 {
00507 return contains(iP) ? sInside : sOutside;
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 template <typename T, class EP, class NP>
00520 const bool SimplePolygon3D<T, EP, NP>::contains(const TPoint& iP) const
00521 {
00522 const XYZ major = majorAxis();
00523 const XYZ x = major + 1;
00524 const XYZ y = major + 2;
00525
00526 size_t i, j;
00527 bool c = false;
00528 const size_t npol = size();
00529 for (i = 0, j = npol-1; i < npol; j = i++)
00530 {
00531 const TPoint& a = vertices_[i];
00532 const TPoint& b = vertices_[j];
00533 if ((((a[y]<=iP[y]) && (iP[y]<b[y])) ||
00534 ((b[y]<=iP[y]) && (iP[y]<a[y]))) &&
00535 (iP[x] < (b[x] - a[x]) * (iP[y] - a[y]) / (b[y] - a[y]) + a[x]))
00536 c = !c;
00537 }
00538 return c;
00539 }
00540
00541
00542
00543
00544
00545 template <typename T, class EP, class NP>
00546 void SimplePolygon3D<T, EP, NP>::flip()
00547 {
00548 plane_.flip();
00549 std::reverse(vertices_.begin(), vertices_.end());
00550 }
00551
00552
00553
00554
00555
00556
00557
00558 template <typename T, class EP, class NP>
00559 const bool SimplePolygon3D<T, EP, NP>::isInRange(int iIndexOfVertex) const
00560 {
00561 return iIndexOfVertex >= 0 && iIndexOfVertex < static_cast<int>(vertices_.size());
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 template<typename T, class EP, class NP, class PP>
00583 Result intersect(const SimplePolygon3D<T, EP, NP>& iPolygon,
00584 const LineSegment3D<T, PP>& iSegment,
00585 T& oT, const T& iMinT)
00586 {
00587 typedef Point2D<T> TPoint;
00588 typedef typename TPoint::TValue TValue;
00589
00590 TValue t;
00591 if (intersect(iPolygon.plane(), iSegment, t, iMinT) == rOne)
00592 {
00593 if (iPolygon.contains(iSegment.point(t)))
00594 {
00595 oT = t;
00596 return rOne;
00597 }
00598 }
00599 return rNone;
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 template <typename T, class EP1, class NP1, class EP2, class NP2>
00613 SimplePolygon3D<T, EP2, NP2> clip(const Plane3D<T, EP1, NP1>& iPlane,
00614 const SimplePolygon3D<T, EP2, NP2>& iPolygon)
00615 {
00616 typedef Plane3D<T, EP1, NP1> TPlane;
00617 typedef SimplePolygon3D<T, EP2, NP2> TPolygon;
00618 typedef Point3D<T> TPoint;
00619 typedef typename TPoint::TValue TValue;
00620 typedef typename TPoint::TNumTraits TNumTraits;
00621
00622 const size_t size = iPolygon.size();
00623 if (size < 2)
00624 {
00625 return iPolygon;
00626 }
00627
00628 bool allOut = true;
00629 bool allIn = true;
00630 std::vector<T> e(size);
00631 for (size_t i = 0; i < size; ++i)
00632 {
00633 e[i] = iPlane.equation(iPolygon[i]);
00634 allOut &= (e[i] <= TNumTraits::zero);
00635 allIn &= (e[i] >= TNumTraits::zero);
00636 }
00637
00638 if (allIn)
00639 {
00640 return iPolygon;
00641 }
00642
00643 if (allOut)
00644 {
00645 return TPolygon(iPolygon.plane());
00646 }
00647
00648 TPolygon result(iPolygon.plane());
00649 TPoint tail = iPolygon[size - 1];
00650 TValue tailE = e[size - 1];
00651 bool tailInside = tailE >= TNumTraits::zero;
00652
00653 for (size_t i = 0; i < size; ++i)
00654 {
00655 const TPoint& head = iPolygon[i];
00656 const TValue headE = e[i];
00657 const bool headInside = headE >= TNumTraits::zero;
00658
00659 if (tailInside)
00660 {
00661 if (headInside)
00662 {
00663
00664 result.add(head);
00665 }
00666 else
00667 {
00668
00669 const TValue t = tailE / (tailE - headE);
00670 LASS_ASSERT(0.0 <= t && t <= 1.0);
00671 const TPoint p = tail + t * (head - tail);
00672 result.add(p);
00673 }
00674 }
00675 else
00676 {
00677 if (headInside)
00678 {
00679
00680 const TValue t = tailE / (tailE - headE);
00681 LASS_ASSERT(0.0 <= t && t <= 1.0);
00682 const TPoint p = tail + t * (head - tail);
00683 result.add(p);
00684 result.add(head);
00685 }
00686 else
00687 {
00688
00689 }
00690 }
00691
00692 tail = head;
00693 tailE = headE;
00694 tailInside = headInside;
00695 }
00696
00697 return result;
00698 }
00699
00700
00701
00702 template <typename T, class EP, class NP>
00703 io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const SimplePolygon3D<T, EP, NP>& iPolygon)
00704 {
00705 const size_t n = iPolygon.size();
00706 LASS_ENFORCE_STREAM(ioOStream) << "<SimplePolygon3D>\n";
00707 for (size_t i = 0; i < n; ++i)
00708 {
00709 ioOStream << "<vertex id='" << static_cast<unsigned long>(i) << "'>" << iPolygon[i] << "</vertex>\n";
00710 }
00711 ioOStream << "<plane>" << iPolygon.plane() << "</plane>\n";
00712 ioOStream << "</SimplePolygon3D>\n";
00713 return ioOStream;
00714 }
00715
00716
00717
00718 template <typename T, class EP, class NP>
00719 std::ostream& operator<<(std::ostream& ioOStream, const SimplePolygon3D<T, EP, NP>& iPolygon)
00720 {
00721 const size_t n = iPolygon.size();
00722 LASS_ENFORCE_STREAM(ioOStream) << "{";
00723 if (n > 0)
00724 {
00725 ioOStream << iPolygon[0];
00726 }
00727 for (size_t i = 1; i < n; ++i)
00728 {
00729 ioOStream << ", " << iPolygon[i];
00730 }
00731 ioOStream << "}";
00732 return ioOStream;
00733 }
00734
00735
00736
00737 }
00738
00739 }
00740
00741 #endif
00742
00743