File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libgeos.x/i/geos/operation/linemerge/LineSequencer.h
Criterion Covered Total %
statement 18 19 94.7
branch 6 12 50.0
condition n/a
subroutine n/a
pod n/a
total 24 31 77.4


line stmt bran cond sub pod time code
1             /**********************************************************************
2             *
3             * GEOS - Geometry Engine Open Source
4             * http://geos.osgeo.org
5             *
6             * Copyright (C) 2011 Sandro Santilli
7             * Copyright (C) 2006 Refractions Research Inc.
8             *
9             * This is free software; you can redistribute and/or modify it under
10             * the terms of the GNU Lesser General Public Licence as published
11             * by the Free Software Foundation.
12             * See the COPYING file for more information.
13             *
14             **********************************************************************
15             *
16             * Last port: operation/linemerge/LineSequencer.java r378 (JTS-1.12)
17             *
18             **********************************************************************/
19              
20             #ifndef GEOS_OP_LINEMERGE_LINESEQUENCER_H
21             #define GEOS_OP_LINEMERGE_LINESEQUENCER_H
22              
23             #include
24              
25             #include // for composition
26             #include // for inlines
27             #include // for inlines
28              
29             #include
30             #include
31             #include // for unique_ptr
32              
33             #ifdef _MSC_VER
34             #pragma warning(push)
35             #pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
36             #endif
37              
38             // Forward declarations
39             namespace geos {
40             namespace geom {
41             class GeometryFactory;
42             class Geometry;
43             class LineString;
44             }
45             namespace planargraph {
46             class DirectedEdge;
47             class Subgraph;
48             class Node;
49             }
50             }
51              
52              
53             namespace geos {
54             namespace operation { // geos::operation
55             namespace linemerge { // geos::operation::linemerge
56              
57             /** \brief
58             * Builds a sequence from a set of LineStrings so that
59             * they are ordered end to end.
60             *
61             * A sequence is a complete non-repeating list of the linear
62             * components of the input. Each linestring is oriented
63             * so that identical endpoints are adjacent in the list.
64             *
65             * A typical use case is to convert a set of
66             * unoriented geometric links
67             * from a linear network
68             * (e.g. such as block faces on a bus route)
69             * into a continuous oriented path through the network.
70             *
71             * The input linestrings may form one or more connected sets.
72             * The input linestrings should be correctly noded, or the results may
73             * not be what is expected.
74             * The computed output is a single MultiLineString containing the ordered
75             * linestrings in the sequence.
76             *
77             * The sequencing employs the classic Eulerian path graph algorithm.
78             * Since Eulerian paths are not uniquely determined,
79             * further rules are used to
80             * make the computed sequence preserve as much as possible of the input
81             * ordering.
82             * Within a connected subset of lines, the ordering rules are:
83             *
84             * - If there is degree-1 node which is the start
85             * node of an linestring, use that node as the start of the sequence
86             * - If there is a degree-1 node which is the end
87             * node of an linestring, use that node as the end of the sequence
88             * - If the sequence has no degree-1 nodes, use any node as the start
89             *
90             * Note that not all arrangements of lines can be sequenced.
91             * For a connected set of edges in a graph,
92             * Euler's Theorem states that there is a sequence
93             * containing each edge once
94             * if and only if there are no more than 2 nodes of odd degree.
95             * If it is not possible to find a sequence, the isSequenceable method
96             * will return false.
97             *
98             */
99 2           class GEOS_DLL LineSequencer {
100              
101             private:
102             typedef std::list DirEdgeList;
103             typedef std::vector< DirEdgeList* > Sequences;
104              
105             LineMergeGraph graph;
106             const geom::GeometryFactory *factory;
107             unsigned int lineCount;
108             bool isRun;
109             std::unique_ptr sequencedGeometry;
110             bool isSequenceableVar;
111              
112             void addLine(const geom::LineString *lineString);
113             void computeSequence();
114             Sequences* findSequences();
115             DirEdgeList* findSequence(planargraph::Subgraph& graph);
116              
117             void delAll( Sequences& );
118              
119             /// return a newly allocated LineString
120             static geom::LineString* reverse(const geom::LineString *line);
121              
122             /**
123             * Builds a geometry ({@link LineString} or {@link MultiLineString} )
124             * representing the sequence.
125             *
126             * @param sequences
127             * a vector of vectors of const planarDirectedEdges
128             * with LineMergeEdges as their parent edges.
129             * Ownership of container _and_ contents retained by caller.
130             *
131             * @return the sequenced geometry, possibly NULL
132             * if no sequence exists
133             */
134             geom::Geometry* buildSequencedGeometry(const Sequences& sequences);
135              
136             static const planargraph::Node* findLowestDegreeNode(
137             const planargraph::Subgraph& graph);
138              
139             void addReverseSubpath(const planargraph::DirectedEdge *de,
140             DirEdgeList& deList,
141             DirEdgeList::iterator lit,
142             bool expectedClosed);
143              
144             /**
145             * Finds an {@link DirectedEdge} for an unvisited edge (if any),
146             * choosing the dirEdge which preserves orientation, if possible.
147             *
148             * @param node the node to examine
149             * @return the dirEdge found, or null
150             * if none were unvisited
151             */
152             static const planargraph::DirectedEdge* findUnvisitedBestOrientedDE(
153             const planargraph::Node* node);
154              
155             /**
156             * Computes a version of the sequence which is optimally
157             * oriented relative to the underlying geometry.
158             *
159             * Heuristics used are:
160             *
161             * - If the path has a degree-1 node which is the start
162             * node of an linestring, use that node as the start of the sequence
163             * - If the path has a degree-1 node which is the end
164             * node of an linestring, use that node as the end of the sequence
165             * - If the sequence has no degree-1 nodes, use any node as the start
166             * (NOTE: in this case could orient the sequence according to the
167             * majority of the linestring orientations)
168             *
169             * @param seq a List of planarDirectedEdges
170             * @return the oriented sequence, possibly same as input if already
171             * oriented
172             */
173             DirEdgeList* orient(DirEdgeList* seq);
174              
175             /**
176             * Reverse the sequence.
177             * This requires reversing the order of the dirEdges, and flipping
178             * each dirEdge as well
179             *
180             * @param seq a List of DirectedEdges, in sequential order
181             * @return the reversed sequence
182             */
183             DirEdgeList* reverse(DirEdgeList& seq);
184              
185             /**
186             * Tests whether a complete unique path exists in a graph
187             * using Euler's Theorem.
188             *
189             * @param graph the subgraph containing the edges
190             * @return true if a sequence exists
191             */
192             bool hasSequence(planargraph::Subgraph& graph);
193              
194             public:
195              
196 1           static geom::Geometry* sequence(const geom::Geometry& geom)
197             {
198 2 50         LineSequencer sequencer;
199 1 50         sequencer.add(geom);
200 2 50         return sequencer.getSequencedLineStrings();
201             }
202              
203 1           LineSequencer()
204             :
205             factory(nullptr),
206             lineCount(0),
207             isRun(false),
208             sequencedGeometry(nullptr),
209 1           isSequenceableVar(false)
210 1           {}
211              
212             /**
213             * Tests whether a {@link Geometry} is sequenced correctly.
214             * {@llink LineString}s are trivially sequenced.
215             * {@link MultiLineString}s are checked for correct sequencing.
216             * Otherwise, isSequenced is defined
217             * to be true for geometries that are not lineal.
218             *
219             * @param geom the geometry to test
220             * @return true if the geometry is sequenced or is not lineal
221             */
222             static bool isSequenced(const geom::Geometry* geom);
223              
224             /**
225             * Tests whether the arrangement of linestrings has a valid
226             * sequence.
227             *
228             * @return true if a valid sequence exists.
229             */
230             bool isSequenceable() {
231             computeSequence();
232             return isSequenceableVar;
233             }
234              
235             /**
236             * Adds a {@link Geometry} to be sequenced.
237             * May be called multiple times.
238             * Any dimension of Geometry may be added; the constituent
239             * linework will be extracted.
240             *
241             * @param geometry the geometry to add
242             */
243 1           void add(const geom::Geometry& geometry) {
244 1           geometry.applyComponentFilter(*this);
245 1           }
246              
247             template
248             void add(TargetContainer& geoms)
249             {
250             for (typename TargetContainer::const_iterator i = geoms.begin(),
251             e = geoms.end(); i != e; ++i)
252             {
253             const geom::Geometry* g = *i;
254             add(*g);
255             }
256             }
257              
258             /**
259             * Act as a GeometryComponentFilter so to extract
260             * the linearworks
261             */
262 1           void filter(const geom::Geometry* g)
263             {
264 1 50         if (const geom::LineString *ls=dynamic_cast(g))
    50          
265             {
266 1           addLine(ls);
267             }
268 1           }
269              
270             /**
271             * Returns the LineString or MultiLineString
272             * built by the sequencing process, if one exists.
273             *
274             * @param release release ownership of computed Geometry
275             * @return the sequenced linestrings,
276             * or null if a valid sequence
277             * does not exist.
278             */
279             geom::Geometry*
280 1           getSequencedLineStrings(bool release=1) {
281 1           computeSequence();
282 1 50         if (release) return sequencedGeometry.release();
283 0           else return sequencedGeometry.get();
284             }
285             };
286              
287             } // namespace geos::operation::linemerge
288             } // namespace geos::operation
289             } // namespace geos
290              
291             #ifdef _MSC_VER
292             #pragma warning(pop)
293             #endif
294              
295             #endif // GEOS_OP_LINEMERGE_LINESEQUENCER_H