1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2006 Refractions Research Inc.
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU Lesser General Licence as published
10 * by the Free Software Foundation.
11 * See the COPYING file for more information.
13 **********************************************************************
15 * Last port: simplify/TaggedLineStringSimplifier.java r536 (JTS-1.12+)
17 **********************************************************************/
19 #include <geos/simplify/TaggedLineStringSimplifier.h>
20 #include <geos/simplify/LineSegmentIndex.h>
21 #include <geos/algorithm/LineIntersector.h>
22 #include <geos/simplify/TaggedLineString.h>
23 #include <geos/simplify/TaggedLineSegment.h>
24 #include <geos/geom/CoordinateSequence.h>
25 #include <geos/geom/LineString.h>
26 //#include <geos/geom/Geometry.h> // for auto_ptr destructor
27 //#include <geos/geom/GeometryFactory.h>
28 //#include <geos/geom/CoordinateSequenceFactory.h>
41 using namespace geos::geom
;
45 namespace simplify
{ // geos::simplify
48 TaggedLineStringSimplifier::TaggedLineStringSimplifier(
49 LineSegmentIndex
* nInputIndex
,
50 LineSegmentIndex
* nOutputIndex
)
52 inputIndex(nInputIndex
),
53 outputIndex(nOutputIndex
),
54 li(new algorithm::LineIntersector()),
57 distanceTolerance(0.0)
63 TaggedLineStringSimplifier::simplify(TaggedLineString
* nLine
)
68 linePts
= line
->getParentCoordinates();
72 std::cerr
<< "TaggedLineStringSimplifier[" << this << "] "
73 << " TaggedLineString[" << line
<< "] "
74 << " has " << linePts
->size() << " coords in input"
78 if ( ! linePts
->size() ) return;
79 simplifySection(0, linePts
->size() - 1, 0);
86 TaggedLineStringSimplifier::simplifySection(std::size_t i
,
87 std::size_t j
, std::size_t depth
)
92 std::cerr
<< "TaggedLineStringSimplifier[" << this << "] "
93 << " simplifying section " << i
<< "-" << j
97 vector
<std::size_t> sectionIndex(2);
103 std::cerr
<< "single segment, no flattening"
107 auto_ptr
<TaggedLineSegment
> newSeg(new
108 TaggedLineSegment(*(line
->getSegment(i
))));
110 line
->addToResult(newSeg
);
111 // leave this segment in the input index, for efficiency
115 bool isValidToSimplify
= true;
118 * Following logic ensures that there is enough points in the
120 * If there is already more points than the minimum, there's
122 * Otherwise, if in the worst case there wouldn't be enough points,
123 * don't flatten this segment (which avoids the worst case scenario)
125 if (line
->getResultSize() < line
->getMinimumSize())
127 std::size_t worstCaseSize
= depth
+ 1;
128 if (worstCaseSize
< line
->getMinimumSize())
129 isValidToSimplify
= false;
134 // pass distance by ref
135 std::size_t furthestPtIndex
= findFurthestPoint(linePts
, i
, j
, distance
);
138 std::cerr
<< "furthest point " << furthestPtIndex
139 << " at distance " << distance
143 // flattening must be less than distanceTolerance
144 if ( distance
> distanceTolerance
) isValidToSimplify
= false;
146 // test if flattened section would cause intersection
147 LineSegment
candidateSeg(linePts
->getAt(i
), linePts
->getAt(j
));
152 if (hasBadIntersection(line
, sectionIndex
, candidateSeg
))
153 isValidToSimplify
= false;
155 if (isValidToSimplify
)
158 auto_ptr
<TaggedLineSegment
> newSeg
= flatten(i
, j
);
161 std::cerr
<< "isValidToSimplify, adding seg "
162 << newSeg
->p0
<< ", " << newSeg
->p1
163 << " to TaggedLineSegment["<<line
<<"] result "
167 line
->addToResult(newSeg
);
171 simplifySection(i
, furthestPtIndex
, depth
);
172 simplifySection(furthestPtIndex
, j
, depth
);
178 auto_ptr
<TaggedLineSegment
>
179 TaggedLineStringSimplifier::flatten(std::size_t start
, std::size_t end
)
181 // make a new segment for the simplified geometry
182 const Coordinate
& p0
= linePts
->getAt(start
);
183 const Coordinate
& p1
= linePts
->getAt(end
);
184 auto_ptr
<TaggedLineSegment
> newSeg(new TaggedLineSegment(p0
, p1
));
185 // update the indexes
186 remove(line
, start
, end
);
187 outputIndex
->add(newSeg
.get());
193 TaggedLineStringSimplifier::hasBadIntersection(
194 const TaggedLineString
* parentLine
,
195 const vector
<std::size_t>& sectionIndex
,
196 const LineSegment
& candidateSeg
)
198 if (hasBadOutputIntersection(candidateSeg
))
201 if (hasBadInputIntersection(parentLine
, sectionIndex
, candidateSeg
))
209 TaggedLineStringSimplifier::hasBadOutputIntersection(
210 const LineSegment
& candidateSeg
)
212 auto_ptr
< vector
<LineSegment
*> > querySegs
=
213 outputIndex
->query(&candidateSeg
);
215 for (vector
<LineSegment
*>::iterator
216 it
= querySegs
->begin(), iEnd
= querySegs
->end();
220 LineSegment
* querySeg
= *it
;
222 if (hasInteriorIntersection(*querySeg
, candidateSeg
))
233 TaggedLineStringSimplifier::hasInteriorIntersection(
234 const LineSegment
& seg0
,
235 const LineSegment
& seg1
) const
237 li
->computeIntersection(seg0
.p0
, seg0
.p1
, seg1
.p0
, seg1
.p1
);
238 return li
->isInteriorIntersection();
243 TaggedLineStringSimplifier::hasBadInputIntersection(
244 const TaggedLineString
* parentLine
,
245 const vector
<std::size_t>& sectionIndex
,
246 const LineSegment
& candidateSeg
)
248 auto_ptr
< vector
<LineSegment
*> > querySegs
=
249 inputIndex
->query(&candidateSeg
);
251 for (vector
<LineSegment
*>::iterator
252 it
= querySegs
->begin(), iEnd
= querySegs
->end();
257 assert(dynamic_cast<TaggedLineSegment
*>(*it
));
258 TaggedLineSegment
* querySeg
=
259 static_cast<TaggedLineSegment
*>(*it
);
261 if (hasInteriorIntersection(*querySeg
, candidateSeg
))
264 if ( isInLineSection(parentLine
,
265 sectionIndex
, querySeg
) )
279 TaggedLineStringSimplifier::isInLineSection(
280 const TaggedLineString
* line
,
281 const vector
<std::size_t>& sectionIndex
,
282 const TaggedLineSegment
* seg
)
285 if (seg
->getParent() != line
->getParent())
288 std::size_t segIndex
= seg
->getIndex();
289 if (segIndex
>= sectionIndex
[0] && segIndex
< sectionIndex
[1])
297 TaggedLineStringSimplifier::remove(const TaggedLineString
* line
,
301 assert(end
<= line
->getSegments().size() );
302 assert(start
< end
); // I'm not sure this should always be true
304 for (std::size_t i
= start
; i
< end
; i
++)
306 const TaggedLineSegment
* seg
= line
->getSegment(i
);
307 inputIndex
->remove(seg
);
313 TaggedLineStringSimplifier::findFurthestPoint(
314 const geom::CoordinateSequence
* pts
,
315 std::size_t i
, std::size_t j
,
318 LineSegment
seg(pts
->getAt(i
), pts
->getAt(j
));
320 std::cerr
<< __FUNCTION__
<< "segment " << seg
323 double maxDist
= -1.0;
324 std::size_t maxIndex
= i
;
325 for (std::size_t k
= i
+ 1; k
< j
; k
++)
327 const Coordinate
& midPt
= pts
->getAt(k
);
328 double distance
= seg
.distance(midPt
);
330 std::cerr
<< "dist to " << midPt
334 if (distance
> maxDist
) {
336 std::cerr
<< "this is max"
343 maxDistance
= maxDist
;
348 } // namespace geos::simplify