/********************************************************************** * $Id: SubgraphDepthLocater.cpp,v 1.5.2.4 2005/06/30 18:31:21 strk Exp $ * * GEOS - Geometry Engine Open Source * http://geos.refractions.net * * Copyright (C) 2001-2002 Vivid Solutions Inc. * Copyright (C) 2005 Refractions Research Inc. * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * **********************************************************************/ #include namespace geos { SubgraphDepthLocater::SubgraphDepthLocater(vector *newSubgraphs){ seg=new LineSegment(); cga=new RobustCGAlgorithms(); subgraphs=newSubgraphs; } SubgraphDepthLocater::~SubgraphDepthLocater(){ delete seg; delete cga; } int SubgraphDepthLocater::getDepth(Coordinate &p) { vector *stabbedSegments=findStabbedSegments(p); // if no segments on stabbing line subgraph must be outside all others-> if ((int)stabbedSegments->size()==0) { delete stabbedSegments; return 0; } sort(stabbedSegments->begin(),stabbedSegments->end(),DepthSegmentLT); DepthSegment *ds=(*stabbedSegments)[0]; int ret = ds->leftDepth; vector::iterator it; for (it=stabbedSegments->begin(); it != stabbedSegments->end(); it++) delete *it; delete stabbedSegments; return ret; } /** * Finds all non-horizontal segments intersecting the stabbing line * The stabbing line is the ray to the right of stabbingRayLeftPt * * @param stabbingRayLeftPt the left-hand origin of the stabbing line * @return a List of DepthSegments intersecting the stabbing line */ vector* SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt) { vector *stabbedSegments=new vector(); unsigned int size = subgraphs->size(); for (unsigned int i=0; igetEnvelope(); if ( stabbingRayLeftPt.y < env->getMinY() || stabbingRayLeftPt.y > env->getMaxY() ) continue; findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(), stabbedSegments); } return stabbedSegments; } /** * Finds all non-horizontal segments intersecting the stabbing line * in the list of dirEdges-> * The stabbing line is the ray to the right of stabbingRayLeftPt-> * * @param stabbingRayLeftPt the left-hand origin of the stabbing line * @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line */ void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,vector *dirEdges,vector *stabbedSegments){ /** * Check all forward DirectedEdges only-> This is still general, * because each Edge has a forward DirectedEdge-> */ for(int i=0;i<(int)dirEdges->size();i++) { DirectedEdge *de=(*dirEdges)[i]; if (!de->isForward()) continue; findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments); } } /** * Finds all non-horizontal segments intersecting the stabbing line * in the input dirEdge-> * The stabbing line is the ray to the right of stabbingRayLeftPt-> * * @param stabbingRayLeftPt the left-hand origin of the stabbing line * @param stabbedSegments the current list of DepthSegments * intersecting the stabbing line */ void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,DirectedEdge *dirEdge,vector *stabbedSegments) { const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates(); // It seems that LineSegment is *very* slow... undef this // to see yourself #define SKIP_LS 1 int n = pts->getSize()-1; for (int i=0; ip0=pts->getAt(i); seg->p1=pts->getAt(i + 1); #else const Coordinate *low=&(pts->getAt(i)); const Coordinate *high=&(pts->getAt(i+1)); const Coordinate *swap=NULL; #endif #if DEBUG cerr<<" SubgraphDepthLocater::findStabbedSegments: segment "<toString()<<") "; #endif #ifndef SKIP_LS // ensure segment always points upwards //if (seg->p0.y > seg->p1.y) { seg->reverse(); #if DEBUG cerr<<" reverse ("<toString()<<") "; #endif } #else if (low->y > high->y) { swap=low; low=high; high=swap; } #endif // skip segment if it is left of the stabbing line // skip if segment is above or below stabbing line #ifndef SKIP_LS double maxx=max(seg->p0.x, seg->p1.x); #else double maxx=max(low->x, high->x); #endif if (maxx < stabbingRayLeftPt.x) { #if DEBUG cerr<<" segment is left to stabbing line, skipping "<isHorizontal()) #else if (low->y == high->y) #endif { #if DEBUG cerr<<" segment is horizontal, skipping "<p0.y || stabbingRayLeftPt.y > seg->p1.y) #else if (stabbingRayLeftPt.y < low->y || stabbingRayLeftPt.y > high->y) #endif { #if DEBUG cerr<<" segment above or below stabbing line, skipping "<p0, seg->p1, #else if (CGAlgorithms::computeOrientation(*low, *high, #endif stabbingRayLeftPt)==CGAlgorithms::RIGHT) { #if DEBUG cerr<<" stabbing ray right of segment, skipping"<getDepth(Position::LEFT); // if segment direction was flipped, use RHS depth instead if (! (seg->p0==pts->getAt(i))) depth=dirEdge->getDepth(Position::RIGHT); #else int depth = swap ? dirEdge->getDepth(Position::RIGHT) : dirEdge->getDepth(Position::LEFT); #endif #if DEBUG cerr<<" depth: "<p0 = *low; seg->p1 = *high; #endif DepthSegment *ds=new DepthSegment(seg, depth); stabbedSegments->push_back(ds); } } DepthSegment::DepthSegment(LineSegment *seg, int depth){ // input seg is assumed to be normalized upwardSeg=new LineSegment(*seg); //upwardSeg->normalize(); leftDepth=depth; } DepthSegment::~DepthSegment(){ delete upwardSeg; } /** * Defines a comparision operation on DepthSegments * which orders them left to right * *
* DS1 < DS2   if   DS1->seg is left of DS2->seg
* DS1 > DS2   if   DS1->seg is right of DS2->seg
* 
* * @param obj * @return */ int DepthSegment::compareTo(void* obj){ DepthSegment *other=(DepthSegment*) obj; /** * try and compute a determinate orientation for the segments-> * Test returns 1 if other is left of this (i->e-> this > other) */ int orientIndex=upwardSeg->orientationIndex(other->upwardSeg); /** * If comparison between this and other is indeterminate, * try the opposite call order-> * orientationIndex value is 1 if this is left of other, * so have to flip sign to get proper comparison value of * -1 if this is leftmost */ if (orientIndex==0) orientIndex=-1 * other->upwardSeg->orientationIndex(upwardSeg); // if orientation is determinate, return it if (orientIndex != 0) return orientIndex; // otherwise, segs must be collinear - sort based on minimum X value return compareX(upwardSeg, other->upwardSeg); } /** * Compare two collinear segments for left-most ordering-> * If segs are vertical, use vertical ordering for comparison-> * If segs are equal, return 0-> * Segments are assumed to be directed so that the second coordinate is >= to the first * (e->g-> up and to the right)-> * * @param seg0 a segment to compare * @param seg1 a segment to compare * @return */ int DepthSegment::compareX(LineSegment *seg0, LineSegment *seg1){ int compare0=seg0->p0.compareTo(seg1->p0); if (compare0!=0) return compare0; return seg0->p1.compareTo(seg1->p1); } bool DepthSegmentLT(DepthSegment *first, DepthSegment *second) { if (first->compareTo(second)<0) return true; else return false; } } // geos /********************************************************************** * $Log: SubgraphDepthLocater.cpp,v $ * Revision 1.5.2.4 2005/06/30 18:31:21 strk * Ported SubgraphDepthLocator optimizations from JTS code * * Revision 1.5.2.3 2005/06/28 21:13:54 strk * Fixed a bug introduced by LineSegment skip - made LineSegment skip a compile-time option * * Revision 1.5.2.2 2005/06/27 21:55:44 strk * Bug fix in DepthSegmentLT comparator as suggested by Graeme Hiebert * * Revision 1.5.2.1 2005/06/27 21:29:00 strk * Reduced Coordinate copies due to LineSegment overuse * * Revision 1.5 2004/07/08 19:34:49 strk * Mirrored JTS interface of CoordinateSequence, factory and * default implementations. * Added DefaultCoordinateSequenceFactory::instance() function. * * Revision 1.4 2004/07/02 13:28:28 strk * Fixed all #include lines to reflect headers layout change. * Added client application build tips in README. * * Revision 1.3 2004/05/05 12:29:44 strk * memleak fixed in ::getDepth * * Revision 1.2 2004/05/03 22:56:44 strk * leaks fixed, exception specification omitted. * * Revision 1.1 2004/04/10 08:40:01 ybychkov * "operation/buffer" upgraded to JTS 1.4 * * **********************************************************************/