/** * Because Delete Events have a link to their corresponding Insert event, * it is possible to compute exactly the range of events which must be * compared to a given Insert event object. */ void SimpleMCSweepLineIntersector::prepareEvents() { sort(events.begin(), events.end(), SweepLineEventLessThen()); for(size_t i=0; i<events.size(); ++i) { GEOS_CHECK_FOR_INTERRUPTS(); SweepLineEvent *ev=events[i]; if (ev->isDelete()) { ev->getInsertEvent()->setDeleteEventIndex(i); } } }
void SimpleMCSweepLineIntersector::add(Edge *edge, void* edgeSet) { MonotoneChainEdge *mce=edge->getMonotoneChainEdge(); auto& startIndex = mce->getStartIndexes(); size_t n = startIndex.size() - 1; events.reserve(events.size()+(n*2)); for(size_t i = 0; i < n; ++i) { GEOS_CHECK_FOR_INTERRUPTS(); MonotoneChain *mc=new MonotoneChain(mce, i); SweepLineEvent *insertEvent=new SweepLineEvent(edgeSet, mce->getMinX(i), nullptr, mc); events.push_back(insertEvent); events.push_back(new SweepLineEvent(edgeSet, mce->getMaxX(i), insertEvent, mc)); } }
/*private*/ void MCIndexNoder::intersectChains() { assert(segInt); SegmentOverlapAction overlapAction(*segInt); for (vector<MonotoneChain*>::iterator i=monoChains.begin(), iEnd=monoChains.end(); i != iEnd; ++i) { GEOS_CHECK_FOR_INTERRUPTS(); MonotoneChain* queryChain = *i; assert(queryChain); vector<void*> overlapChains; index.query(&(queryChain->getEnvelope()), overlapChains); for (vector<void*>::iterator j=overlapChains.begin(), jEnd=overlapChains.end(); j != jEnd; ++j) { MonotoneChain* testChain = static_cast<MonotoneChain*>(*j); assert(testChain); /** * following test makes sure we only compare each * pair of chains once and that we don't compare a * chain to itself */ if (testChain->getId() > queryChain->getId()) { queryChain->computeOverlaps(testChain, &overlapAction); nOverlaps++; } // short-circuit if possible if (segInt->isDone()) return; } } }
void SimpleMCSweepLineIntersector::computeIntersections(SegmentIntersector *si) { nOverlaps=0; prepareEvents(); for(size_t i=0; i<events.size(); ++i) { GEOS_CHECK_FOR_INTERRUPTS(); SweepLineEvent *ev=events[i]; if (ev->isInsert()) { processOverlaps(i, ev->getDeleteEventIndex(), ev, si); } if (si->getIsDone()) { break; } } }
IntersectionMatrix* RelateComputer::computeIM() { // since Geometries are finite and embedded in a 2-D space, the EE element must always be 2 im->set(Location::EXTERIOR,Location::EXTERIOR,2); // if the Geometries don't overlap there is nothing to do const Envelope *e1=(*arg)[0]->getGeometry()->getEnvelopeInternal(); const Envelope *e2=(*arg)[1]->getGeometry()->getEnvelopeInternal(); if (!e1->intersects(e2)) { computeDisjointIM(im.get()); return im.release(); } #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing self nodes 1" << std::endl; #endif std::unique_ptr<SegmentIntersector> si1 ( (*arg)[0]->computeSelfNodes(&li,false) ); GEOS_CHECK_FOR_INTERRUPTS(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing self nodes 2" << std::endl; #endif std::unique_ptr<SegmentIntersector> si2 ( (*arg)[1]->computeSelfNodes(&li,false) ); GEOS_CHECK_FOR_INTERRUPTS(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing edge intersections" << std::endl; #endif // compute intersections between edges of the two input geometries std::unique_ptr< SegmentIntersector> intersector ( (*arg)[0]->computeEdgeIntersections((*arg)[1], &li,false) ); GEOS_CHECK_FOR_INTERRUPTS(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "copying intersection nodes" << std::endl; #endif computeIntersectionNodes(0); computeIntersectionNodes(1); GEOS_CHECK_FOR_INTERRUPTS(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "copying nodes and labels" << std::endl; #endif GEOS_CHECK_FOR_INTERRUPTS(); /* * Copy the labelling for the nodes in the parent Geometries. * These override any labels determined by intersections * between the geometries. */ copyNodesAndLabels(0); copyNodesAndLabels(1); GEOS_CHECK_FOR_INTERRUPTS(); /* * complete the labelling for any nodes which only have a * label for a single geometry */ //Debug.addWatch(nodes.find(new Coordinate(110, 200))); //Debug.printWatch(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "labeling isolated nodes" << std::endl; #endif labelIsolatedNodes(); //Debug.printWatch(); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing proper intersection matrix" << std::endl; #endif /* * If a proper intersection was found, we can set a lower bound * on the IM. */ computeProperIntersectionIM(intersector.get(), im.get()); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing improper intersections" << std::endl; #endif /* * Now process improper intersections * (eg where one or other of the geometrys has a vertex at the * intersection point) * We need to compute the edge graph at all nodes to determine * the IM. */ // build EdgeEnds for all intersections EdgeEndBuilder eeBuilder; std::unique_ptr< std::vector<EdgeEnd*> > ee0 ( eeBuilder.computeEdgeEnds((*arg)[0]->getEdges()) ); insertEdgeEnds(ee0.get()); std::unique_ptr< std::vector<EdgeEnd*> > ee1 ( eeBuilder.computeEdgeEnds((*arg)[1]->getEdges()) ); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "inserting edge ends" << std::endl; #endif insertEdgeEnds(ee1.get()); //Debug.println("==== NodeList ==="); //Debug.print(nodes); #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "labeling node edges" << std::endl; #endif labelNodeEdges(); /** * Compute the labeling for isolated components. * Isolated components are components that do not touch any * other components in the graph. * They can be identified by the fact that they will * contain labels containing ONLY a single element, the one for * their parent geometry. * We only need to check components contained in the input graphs, * since isolated components will not have been replaced by new * components formed by intersections. */ #if GEOS_DEBUG std::cerr << "RelateComputer::computeIM: " << "computing labeling for isolated components" << std::endl; #endif //debugPrintln("Graph A isolated edges - "); labelIsolatedEdges(0,1); //debugPrintln("Graph B isolated edges - "); labelIsolatedEdges(1,0); // update the IM from all components updateIM( *im ); return im.release(); }
/*private*/ void LineStringSnapper::snapSegments(geom::CoordinateList& srcCoords, const geom::Coordinate::ConstVect& snapPts) { // nothing to do if there are no source coords.. if(srcCoords.empty()) { return; } GEOS_CHECK_FOR_INTERRUPTS(); #if GEOS_DEBUG cerr << "Snapping segments of: " << srcCoords << endl; #endif for(Coordinate::ConstVect::const_iterator it = snapPts.begin(), end = snapPts.end(); it != end; ++it) { assert(*it); const Coordinate& snapPt = *(*it); #if GEOS_DEBUG cerr << "Checking for a segment to snap to snapPt " << snapPt << endl; #endif CoordinateList::iterator too_far = srcCoords.end(); --too_far; CoordinateList::iterator segpos = findSegmentToSnap(snapPt, srcCoords.begin(), too_far); if(segpos == too_far) { #if GEOS_DEBUG cerr << " No segment to snap" << endl; #endif continue; } /* Check if the snap point falls outside of the segment */ // If the snap point is outside, this means that an endpoint // was not snap where it should have been // so what we should do is re-snap the endpoint to this // snapPt and then snap the closest between this and // previous (for pf < 0.0) or next (for pf > 1.0) segment // to the old endpoint. // --strk May 2013 // // TODO: simplify this code, make more readable // CoordinateList::iterator to = segpos; ++to; LineSegment seg(*segpos, *to); double pf = seg.projectionFactor(snapPt); if(pf >= 1.0) { #if GEOS_DEBUG cerr << " Segment to be snapped is closer on his end point" << endl; #endif Coordinate newSnapPt = seg.p1; *to = seg.p1 = snapPt; // now snap from-to (segpos) or to-next (segpos++) to newSnapPt if(to == too_far) { if(isClosed) { #if GEOS_DEBUG cerr << " His end point is the last one, but is closed " << endl; #endif *(srcCoords.begin()) = snapPt; // sync to start point to = srcCoords.begin(); } else { #if GEOS_DEBUG cerr << " His end point is the last one, inserting " << newSnapPt << " before it" << endl; #endif srcCoords.insert(to, newSnapPt); continue; } } ++to; LineSegment nextSeg(seg.p1, *to); if(nextSeg.distance(newSnapPt) < seg.distance(newSnapPt)) { #if GEOS_DEBUG cerr << " Next segment closer, inserting " << newSnapPt << " into " << nextSeg << endl; #endif // insert into next segment srcCoords.insert(to, newSnapPt); } else { #if GEOS_DEBUG cerr << " This segment closer, inserting " << newSnapPt << " into " << seg << endl; #endif // insert must happen one-past first point (before next point) ++segpos; srcCoords.insert(segpos, newSnapPt); } } else if(pf <= 0.0) { #if GEOS_DEBUG cerr << " Segment to be snapped is closer on his start point" << endl; #endif Coordinate newSnapPt = seg.p0; *segpos = seg.p0 = snapPt; // now snap prev-from (--segpos) or from-to (segpos) to newSnapPt if(segpos == srcCoords.begin()) { if(isClosed) { #if GEOS_DEBUG cerr << " His start point is the first one, but is closed " << endl; #endif segpos = srcCoords.end(); --segpos; *segpos = snapPt; // sync to end point } else { #if GEOS_DEBUG cerr << " His start point is the first one, inserting " << newSnapPt << " before it" << endl; #endif ++segpos; srcCoords.insert(segpos, newSnapPt); continue; } } #if GEOS_DEBUG cerr << " Before seg-snapping, srcCoors are: " << srcCoords << endl; #endif --segpos; LineSegment prevSeg(*segpos, seg.p0); if(prevSeg.distance(newSnapPt) < seg.distance(newSnapPt)) { #if GEOS_DEBUG cerr << " Prev segment closer, inserting " << newSnapPt << " into " << prevSeg << endl; #endif // insert into prev segment ++segpos; srcCoords.insert(segpos, newSnapPt); } else { #if GEOS_DEBUG cerr << " This segment closer, inserting " << newSnapPt << " into " << seg << endl; #endif // insert must happen one-past first point (before next point) srcCoords.insert(to, newSnapPt); } } else { //assert(pf != 0.0); #if GEOS_DEBUG cerr << " Segment to be snapped found, projection factor is " << pf << ", inserting point" << endl; #endif // insert must happen one-past first point (before next point) ++segpos; srcCoords.insert(segpos, snapPt); } } #if GEOS_DEBUG cerr << " After segment snapping, srcCoors are: " << srcCoords << endl; #endif }
/*private*/ void LineStringSnapper::snapVertices(geom::CoordinateList& srcCoords, const geom::Coordinate::ConstVect& snapPts) { // nothing to do if there are no source coords.. if(srcCoords.empty()) { return; } #if GEOS_DEBUG cerr << "Snapping vertices of: " << srcCoords << endl; #endif for(Coordinate::ConstVect::const_iterator it = snapPts.begin(), end = snapPts.end(); it != end; ++it) { GEOS_CHECK_FOR_INTERRUPTS(); assert(*it); const Coordinate& snapPt = *(*it); #if GEOS_DEBUG cerr << "Checking for a vertex to snap to snapPt " << snapPt << endl; #endif CoordinateList::iterator too_far = srcCoords.end(); if(isClosed) { --too_far; } CoordinateList::iterator vertpos = findVertexToSnap(snapPt, srcCoords.begin(), too_far); if(vertpos == too_far) { #if GEOS_DEBUG cerr << " No vertex to snap" << endl; #endif continue; } #if GEOS_DEBUG cerr << " Vertex to be snapped found, snapping" << endl; #endif *vertpos = snapPt; // keep final closing point in synch (rings only) if(vertpos == srcCoords.begin() && isClosed) { vertpos = srcCoords.end(); --vertpos; #if GEOS_DEBUG cerr << " Snapped vertex was first in a closed line, also snapping last" << endl; #endif *vertpos = snapPt; } #if GEOS_DEBUG cerr << " After snapping of vertex " << snapPt << ", srcCoors are: " << srcCoords << endl; #endif } #if GEOS_DEBUG cerr << " After vertices snapping, srcCoors are: " << srcCoords << endl; #endif }