Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

cone_tracing.hpp

Go to the documentation of this file.
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     // Compute the other two vertices of the largest inner triangular
00021     // approximation to the cone.
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     // Squared hypotenuse length of inner triangle.
00029     const Geometry::Kernel::FT dsq = CGAL::squared_distance(vertex, p);
00030     // Squared base length of the inner triangle
00031     const Geometry::Kernel::FT bsq = CGAL::squared_distance(p, q);
00032     // Squared height of the inner triangle
00033     const double hsq = CGAL::to_double(dsq) - CGAL::to_double(bsq) / 4.0;
00034     // The inner and outer triangles are similar.  So the ratio
00035     // between d and h (the heights of the outer and inner
00036     // triangles) is the same as the ratio between the hypotenuse
00037     // length of the outer triangle and d, the hypotenuse length of
00038     // the inner triangle.
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   // Forward declaration.
00065   class ScanEdge;
00066 
00067   // A handle to a scan edge.
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       // Get the source, target, and midpoint of the edge.
00150       const Geometry::Point& source = e->source();
00151       const Geometry::Point& target = e->target();
00152       Geometry::Point midpoint = CGAL::midpoint(source, target);
00153       // Compute the directions to these points from the vertex.
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       // Determine the (counter-clockwise) order of these directions.
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       // Compute the minimum visible point on the segment.
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       // Compute the maximum visible point on the segment.
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     // a_at_min && b_at_min
00338     return (CGAL::orientation(b->pmin, b->pmax, a->pmax) ==
00339       CGAL::orientation(b->pmin, b->pmax, p));
00340   } else {
00341     // a_at_min && !b_at_min
00342     return false;
00343   }
00344       } else {
00345   if (b_at_min) {
00346     // !a_at_min && b_at_min
00347     return false;
00348   } else {
00349     // !a_at_min && !b_at_min
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; // Warning: this is not thread-safe
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     // If there are no edges, we are done.
00438     if (edges.empty()) return;
00439     // Create scan edges and vertices.  The scan edge objects are
00440     // allocated statically for efficiency.
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     // ScanEdge* _se = new ScanEdge[edges.size()];
00445     typedef typename std::vector<ScanVertex> ScanVertexSequence;
00446     static ScanVertexSequence scanVertices; // Warning: not thread-safe
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       // If the scan edge does not intersect the scan cone, ignore it.
00454       if (!cones_intersect(min, max, seh->dmin, seh->dmax)) continue;
00455       // Store the associated scan vertices.
00456       scanVertices.push_back(seh->max());
00457       scanVertices.push_back(seh->min());
00458     }
00459     // If there are no scan vertices, we are done.
00460     if (scanVertices.empty()) return;
00461     // Sort the scan vertices by direction.
00462     ScanVertexComparator comp(min);
00463     std::sort(scanVertices.begin(), scanVertices.end(), comp);
00464     /* Scan through the sorted vertices.  When a minimum vertex is
00465      * encountered, insert its edge into the list in order of its
00466      * depth along the current angle.  When a maximum vertex is
00467      * encountered, remove its edge from the list.  Whenever a change
00468      * occurs, append an event to the list of events.
00469      */
00470     // The list of scan edges, sorted by depth.
00471     typedef std::list<ScanEdgeHandle> ScanEdgeHandleList;
00472     ScanEdgeHandleList front_to_back;
00473     // Insert a sentinel in the list which means 'no current edge'.
00474     ScanEdgeHandle front;
00475     front_to_back.push_back(front);
00476     // The current scan event.
00477     ScanEvent curEvent;
00478     curEvent.edge = Coloring::IntEdgeHandle();
00479     // Scan through the vertices.
00480     for (ScanVertexSequence::iterator svi = scanVertices.begin(); 
00481    svi != scanVertices.end(); svi++) {
00482       // Get a handle to the edge that is currently in front.
00483       front = front_to_back.front();
00484       // Get the direction to the current vertex.
00485       const Geometry::Direction& dir = 
00486   (svi->isMin ? svi->edge->dmin : svi->edge->dmax);
00487       // Check to see if the current scan vertex is a minimum vertex
00488       // or a maximum vertex.
00489       if (svi->isMin) {
00490   // The current vertex is a minimum vertex.  Insert its scan
00491   // edge into sorted position in the list.
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       // Prune any deeper edges that are dominated by this one.
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       // This edge is dominated by the previous edge.  Do not
00514       // insert it in the list.
00515       svi->edge->pruned = true;
00516       break;
00517     }
00518   }
00519       } else {
00520   // The current vertex is a maximum vertex.  Remove its scan
00521   // edge from the list.
00522   if (!(svi->edge->pruned))
00523     front_to_back.erase(svi->edge->it);
00524       }
00525       // If the edge in front has changed, update the current event.
00526       if (front != front_to_back.front()) {
00527   // Check to see if there is an event in progress that must be
00528   // reported.
00529   if (curEvent.edge.valid() && (curEvent.dmin != dir)) {
00530     // Report the current event.
00531     curEvent.dmax = dir;
00532     curEvent.pmax = intersection(vertex, dir, front);
00533     out = curEvent;
00534     ++out;
00535   }
00536   // Update the current event.
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 } // End of namespace: Arak
00571 
00572 #endif

Generated on Wed May 25 14:39:16 2005 for Arak by doxygen 1.3.6