1 /********************************************************************** 2 * 3 * GEOS - Geometry Engine Open Source 4 * http://geos.osgeo.org 5 * 6 * Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca> 7 * 8 * This is free software; you can redistribute and/or modify it under 9 * the terms of the GNU Lesser General Public Licence as published 10 * by the Free Software Foundation. 11 * See the COPYING file for more information. 12 * 13 **********************************************************************/ 14 15 #include <geos/operation/overlayng/LineLimiter.h> 16 #include <geos/geom/CoordinateSequence.h> 17 #include <geos/geom/Envelope.h> 18 #include <geos/geom/Coordinate.h> 19 20 #include <algorithm> 21 22 namespace geos { // geos 23 namespace operation { // geos.operation 24 namespace overlayng { // geos.operation.overlayng 25 26 /*public*/ 27 std::vector<std::unique_ptr<CoordinateArraySequence>>& limit(const CoordinateSequence * pts)28LineLimiter::limit(const CoordinateSequence *pts) 29 { 30 // Reset for new limit run 31 lastOutside = nullptr; 32 ptList.reset(nullptr); 33 sections.clear(); 34 35 for (std::size_t i = 0; i < pts->size(); i++) { 36 const Coordinate* p = &(pts->getAt(i)); 37 if (limitEnv->intersects(*p)) { 38 addPoint(p); 39 } 40 else { 41 addOutside(p); 42 } 43 } 44 // finish last section, if any 45 finishSection(); 46 return sections; 47 } 48 49 /*private*/ 50 void addPoint(const Coordinate * p)51LineLimiter::addPoint(const Coordinate* p) 52 { 53 startSection(); 54 ptList->emplace_back(*p); 55 } 56 57 /*private*/ 58 void addOutside(const Coordinate * p)59LineLimiter::addOutside(const Coordinate* p) 60 { 61 bool segIntersects = isLastSegmentIntersecting(p); 62 if (!segIntersects) { 63 finishSection(); 64 } 65 else { 66 if(lastOutside != nullptr) { 67 addPoint(lastOutside); 68 } 69 addPoint(p); 70 } 71 lastOutside = p; 72 } 73 74 /*private*/ 75 bool isLastSegmentIntersecting(const Coordinate * p)76LineLimiter::isLastSegmentIntersecting(const Coordinate* p) 77 { 78 if (lastOutside == nullptr) { 79 // last point must have been inside 80 if (isSectionOpen()) 81 return true; 82 return false; 83 } 84 return limitEnv->intersects(*lastOutside, *p); 85 } 86 87 /*private*/ 88 bool isSectionOpen()89LineLimiter::isSectionOpen() 90 { 91 return ptList != nullptr; 92 } 93 94 /*private*/ 95 void startSection()96LineLimiter::startSection() 97 { 98 if (!isSectionOpen()) { 99 ptList.reset(new std::vector<Coordinate>); 100 } 101 102 if (lastOutside != nullptr) { 103 ptList->emplace_back(*lastOutside); 104 } 105 lastOutside = nullptr; 106 } 107 108 /*private*/ 109 void finishSection()110LineLimiter::finishSection() 111 { 112 if (!isSectionOpen()) 113 return; 114 115 // finish off this section 116 if (lastOutside != nullptr) { 117 ptList->emplace_back(*lastOutside); 118 lastOutside = nullptr; 119 } 120 121 // remove repeated points from the section 122 ptList->erase(std::unique(ptList->begin(), ptList->end()), ptList->end()); 123 124 // std::unique_ptr<CoordinateArraySequence> cas(); 125 CoordinateArraySequence* cas = new CoordinateArraySequence(ptList.release()); 126 sections.emplace_back(cas); 127 ptList.reset(nullptr); 128 } 129 130 131 132 133 } // namespace geos.operation.overlayng 134 } // namespace geos.operation 135 } // namespace geos 136