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