00001 #ifndef _CONE_TRACING_HPP
00002 #define _CONE_TRACING_HPP
00003
00004 #include "handle.hpp"
00005 #include "geometry.hpp"
00006 #include "coloring.hpp"
00007 #include "grid.hpp"
00008
00009 namespace Arak {
00010
00016 inline Geometry::Triangle outerApprox(const Geometry::Point& vertex,
00017 const Geometry::Direction& min,
00018 const Geometry::Direction& max,
00019 const Geometry::Kernel::FT& radius) {
00020
00021
00022 Geometry::Point p = vertex + min.vector();
00023 double length = sqrt(CGAL::to_double(CGAL::squared_distance(p, vertex)));
00024 p = vertex + (p - vertex) * (CGAL::to_double(radius) / length);
00025 Geometry::Point q = vertex + max.vector();
00026 length = sqrt(CGAL::to_double(CGAL::squared_distance(q, vertex)));
00027 q = vertex + (q - vertex) * (CGAL::to_double(radius) / length);
00028
00029 const Geometry::Kernel::FT dsq = CGAL::squared_distance(vertex, p);
00030
00031 const Geometry::Kernel::FT bsq = CGAL::squared_distance(p, q);
00032
00033 const double hsq = CGAL::to_double(dsq) - CGAL::to_double(bsq) / 4.0;
00034
00035
00036
00037
00038
00039 double scale = sqrt(CGAL::to_double(dsq / hsq));
00040 return Geometry::Triangle(vertex,
00041 vertex + (p - vertex) * scale,
00042 vertex + (q - vertex) * scale);
00043 }
00044
00054 inline Geometry::Point intersection(const Geometry::Point& p,
00055 const Geometry::Direction& d,
00056 const Geometry::Segment& s) {
00057 const Geometry::Line line1 = s.supporting_line();
00058 const Geometry::Line line2(p, d);
00059 Geometry::Point contact;
00060 assert(CGAL::assign(contact, CGAL::intersection(line1, line2)));
00061 return contact;
00062 }
00063
00064
00065 class ScanEdge;
00066
00067
00068 typedef PointerHandle<ScanEdge> ScanEdgeHandle;
00069
00073 struct ScanVertex {
00074
00078 ScanEdgeHandle edge;
00079
00084 bool isMin;
00085
00089 ScanVertex(ScanEdgeHandle edge, bool isMin) : edge(edge), isMin(isMin) { }
00090
00091 };
00092
00096 struct ScanEdge {
00097
00101 Coloring::IntEdgeHandle edge;
00102
00106 Geometry::Direction dmin;
00107
00111 Geometry::Point pmin;
00112
00116 Geometry::Direction dmax;
00117
00121 Geometry::Point pmax;
00122
00127 bool pruned;
00128
00133 std::list<ScanEdgeHandle>::iterator it;
00134
00143 void init(const Geometry::Point& vertex,
00144 const Geometry::Direction& min,
00145 const Geometry::Direction& max,
00146 Coloring::IntEdgeHandle e) {
00147 this->pruned = true;
00148 this->edge = e;
00149
00150 const Geometry::Point& source = e->source();
00151 const Geometry::Point& target = e->target();
00152 Geometry::Point midpoint = CGAL::midpoint(source, target);
00153
00154 Geometry::Segment toSource(vertex, source);
00155 Geometry::Segment toTarget(vertex, target);
00156 Geometry::Segment toMidpoint(vertex, midpoint);
00157 Geometry::Direction ds = toSource.direction();
00158 Geometry::Direction dt = toTarget.direction();
00159 Geometry::Direction dm = toMidpoint.direction();
00160
00161 bool sourceIsMin = dm.counterclockwise_in_between(ds, dt);
00162 if (sourceIsMin) {
00163 dmin = ds;
00164 dmax = dt;
00165 } else {
00166 dmin = dt;
00167 dmax = ds;
00168 }
00169
00170 if (min.counterclockwise_in_between(dmin, dmax)) {
00171 dmin = min;
00172 pmin = intersection(vertex, min, e->segment());
00173 } else
00174 pmin = (sourceIsMin ? source : target);
00175
00176 if (max.counterclockwise_in_between(dmin, dmax)) {
00177 dmax = max;
00178 pmax = intersection(vertex, max, e->segment());
00179 } else
00180 pmax = (sourceIsMin ? target : source);
00181 }
00182
00186 inline ScanVertex min() {
00187 return ScanVertex(ScanEdgeHandle(this), true);
00188 };
00189
00193 inline ScanVertex max() {
00194 return ScanVertex(ScanEdgeHandle(this), false);
00195 };
00196 };
00197
00208 inline CGAL::Comparison_result compare(const Geometry::Direction& a,
00209 const Geometry::Direction& b,
00210 const Geometry::Direction& min) {
00211 if (a == b) return CGAL::EQUAL;
00212 if (a == min) return CGAL::SMALLER;
00213 if (b == min) return CGAL::LARGER;
00214 if (a.counterclockwise_in_between(min, b)) return CGAL::SMALLER;
00215 return CGAL::LARGER;
00216 }
00217
00222 class ScanVertexComparator {
00223
00224 private:
00225
00229 Geometry::Direction min;
00230
00231 public:
00232
00238 ScanVertexComparator(const Geometry::Direction& min) : min(min) { }
00239
00248 inline bool operator() (const ScanVertex& a,
00249 const ScanVertex& b) const {
00250 const Geometry::Direction& adir =
00251 (a.isMin ? a.edge->dmin : a.edge->dmax);
00252 const Geometry::Direction& bdir =
00253 (b.isMin ? b.edge->dmin : b.edge->dmax);
00254 return (compare(adir, bdir, min) == CGAL::SMALLER);
00255 }
00256 };
00257
00267 inline Geometry::Point intersection(const Geometry::Point& p,
00268 const Geometry::Direction& d,
00269 const ScanEdgeHandle se) {
00270 if (d == se->dmin) return se->pmin;
00271 if (d == se->dmax) return se->pmax;
00272 return intersection(p, d, se->edge->segment());
00273 }
00274
00284 inline bool cones_intersect(const Geometry::Direction& amin,
00285 const Geometry::Direction& amax,
00286 const Geometry::Direction& bmin,
00287 const Geometry::Direction& bmax) {
00288 return ((amin == bmin) ||
00289 (amax == bmax) ||
00290 bmin.counterclockwise_in_between(amin, amax) ||
00291 bmax.counterclockwise_in_between(amin, amax) ||
00292 amin.counterclockwise_in_between(bmin, bmax) ||
00293 amax.counterclockwise_in_between(bmin, bmax));
00294 }
00295
00305 inline bool cone_subset(const Geometry::Direction& amin,
00306 const Geometry::Direction& amax,
00307 const Geometry::Direction& bmin,
00308 const Geometry::Direction& bmax) {
00309 return (((amin == bmin) ||
00310 amin.counterclockwise_in_between(bmin, bmax))
00311 &&
00312 ((amax == bmax) ||
00313 amax.counterclockwise_in_between(bmin, bmax)));
00314 }
00315
00326 inline bool closer(const Geometry::Point& p,
00327 const Geometry::Direction& dir,
00328 ScanEdgeHandle a,
00329 ScanEdgeHandle b) {
00330 Geometry::Point ap = intersection(p, dir, a);
00331 Geometry::Point bp = intersection(p, dir, b);
00332 if (ap == bp) {
00333 bool a_at_min = (ap == a->pmin);
00334 bool b_at_min = (bp == b->pmin);
00335 if (a_at_min) {
00336 if (b_at_min) {
00337
00338 return (CGAL::orientation(b->pmin, b->pmax, a->pmax) ==
00339 CGAL::orientation(b->pmin, b->pmax, p));
00340 } else {
00341
00342 return false;
00343 }
00344 } else {
00345 if (b_at_min) {
00346
00347 return false;
00348 } else {
00349
00350 return (CGAL::orientation(b->pmin, b->pmax, a->pmax) ==
00351 CGAL::orientation(b->pmin, b->pmax, p));
00352 }
00353 }
00354 } else
00355 return (CGAL::compare_distance_to_point(p, ap, bp) == CGAL::SMALLER);
00356 }
00357
00362 struct ScanEvent {
00363
00367 Coloring::IntEdgeHandle edge;
00368
00374 Geometry::Direction dmin;
00375
00381 Geometry::Direction dmax;
00382
00386 Geometry::Point pmin;
00387
00391 Geometry::Point pmax;
00392 };
00393
00408 template <class OutputIterator>
00409 void coneTrace(const Coloring& coloring,
00410 const Geometry::Point& vertex,
00411 const Geometry::Direction& min,
00412 const Geometry::Direction& max,
00413 const Geometry::Kernel::FT& radius,
00414 const Geometry::Triangle& filter,
00415 OutputIterator out) {
00416 typedef typename std::set<Coloring::IntEdgeHandle> EdgeHandleSet;
00417 static EdgeHandleSet edges;
00418 edges.clear();
00419 const Coloring::InteriorEdgeIndex& index =
00420 coloring.getInteriorEdgeIndex();
00421 #ifdef RECTANGULAR_FILTER
00422 Geometry::Rectangle rFilter = boundingRectangle(filter[0],
00423 filter[1],
00424 filter[2]);
00425 Coloring::InteriorEdgeIndex::ConstRectangleCellIterator
00426 it(index, rFilter), end;
00427 #else
00428 Coloring::InteriorEdgeIndex::ConstTriangleCellIterator
00429 it(index, filter), end;
00430 #endif
00431 while (it != end) {
00432 const Coloring::InteriorEdgeIndex::Cell::ItemList& obsList =
00433 it->getItemList();
00434 edges.insert(obsList.begin(), obsList.end());
00435 ++it;
00436 }
00437
00438 if (edges.empty()) return;
00439
00440
00441 const size_t MAX_NUM_SCAN_EDGES = 1024;
00442 static ScanEdge _se[MAX_NUM_SCAN_EDGES];
00443 assert(edges.size() <= MAX_NUM_SCAN_EDGES);
00444
00445 typedef typename std::vector<ScanVertex> ScanVertexSequence;
00446 static ScanVertexSequence scanVertices;
00447 scanVertices.clear();
00448 int i = 0;
00449 for (EdgeHandleSet::iterator it = edges.begin(); it != edges.end(); it++) {
00450 _se[i].init(vertex, min, max, *it);
00451 ScanEdgeHandle seh(_se[i]);
00452 i++;
00453
00454 if (!cones_intersect(min, max, seh->dmin, seh->dmax)) continue;
00455
00456 scanVertices.push_back(seh->max());
00457 scanVertices.push_back(seh->min());
00458 }
00459
00460 if (scanVertices.empty()) return;
00461
00462 ScanVertexComparator comp(min);
00463 std::sort(scanVertices.begin(), scanVertices.end(), comp);
00464
00465
00466
00467
00468
00469
00470
00471 typedef std::list<ScanEdgeHandle> ScanEdgeHandleList;
00472 ScanEdgeHandleList front_to_back;
00473
00474 ScanEdgeHandle front;
00475 front_to_back.push_back(front);
00476
00477 ScanEvent curEvent;
00478 curEvent.edge = Coloring::IntEdgeHandle();
00479
00480 for (ScanVertexSequence::iterator svi = scanVertices.begin();
00481 svi != scanVertices.end(); svi++) {
00482
00483 front = front_to_back.front();
00484
00485 const Geometry::Direction& dir =
00486 (svi->isMin ? svi->edge->dmin : svi->edge->dmax);
00487
00488
00489 if (svi->isMin) {
00490
00491
00492 for (ScanEdgeHandleList::iterator sehi = front_to_back.begin();
00493 sehi != front_to_back.end(); ++sehi) {
00494 ScanEdgeHandle seh = *sehi;
00495 if (!seh.valid() || closer(vertex, dir, svi->edge, seh)) {
00496 svi->edge->it = front_to_back.insert(sehi, svi->edge);
00497 svi->edge->pruned = false;
00498
00499 if (seh.valid()) {
00500 ++sehi;
00501 while ((seh = *sehi).valid()) {
00502 if (cone_subset(seh->dmin, seh->dmax,
00503 svi->edge->dmin, svi->edge->dmax)) {
00504 seh->pruned = true;
00505 sehi = front_to_back.erase(sehi);
00506 } else
00507 ++sehi;
00508 }
00509 }
00510 break;
00511 } else if (cone_subset(svi->edge->dmin, svi->edge->dmax,
00512 seh->dmin, seh->dmax)) {
00513
00514
00515 svi->edge->pruned = true;
00516 break;
00517 }
00518 }
00519 } else {
00520
00521
00522 if (!(svi->edge->pruned))
00523 front_to_back.erase(svi->edge->it);
00524 }
00525
00526 if (front != front_to_back.front()) {
00527
00528
00529 if (curEvent.edge.valid() && (curEvent.dmin != dir)) {
00530
00531 curEvent.dmax = dir;
00532 curEvent.pmax = intersection(vertex, dir, front);
00533 out = curEvent;
00534 ++out;
00535 }
00536
00537 if (front_to_back.front().valid()) {
00538 curEvent.edge = front_to_back.front()->edge;
00539 curEvent.dmin = dir;
00540 curEvent.pmin = intersection(vertex, dir, front_to_back.front());
00541 } else
00542 curEvent.edge = Coloring::IntEdgeHandle();
00543 }
00544 }
00545 }
00546
00559 template <class OutputIterator>
00560 void coneTrace(const Coloring& coloring,
00561 const Geometry::Point& vertex,
00562 const Geometry::Direction& min,
00563 const Geometry::Direction& max,
00564 const Geometry::Kernel::FT& radius,
00565 OutputIterator out) {
00566 Geometry::Triangle outer = outerApprox(vertex, min, max, radius);
00567 coneTrace(coloring, vertex, min, max, radius, outer, out);
00568 }
00569
00570 }
00571
00572 #endif