1 /**********************************************************************
4 * GEOS - Geometry Engine Open Source
5 * http://geos.refractions.net
7 * Copyright (C) 2009-2010 Sandro Santilli <strk@keybit.net>
8 * Copyright (C) 2006 Refractions Research Inc.
10 * This is free software; you can redistribute and/or modify it under
11 * the terms of the GNU Lesser General Public Licence as published
12 * by the Free Software Foundation.
13 * See the COPYING file for more information.
15 ***********************************************************************
17 * Last port: operation/overlay/snap/LineStringSnapper.java r320 (JTS-1.12)
19 **********************************************************************/
21 #include <geos/operation/overlay/snap/LineStringSnapper.h>
22 #include <geos/geom/CoordinateSequence.h>
23 #include <geos/geom/Coordinate.h>
24 #include <geos/geom/CoordinateList.h>
25 #include <geos/util/UniqueCoordinateArrayFilter.h>
26 #include <geos/geom/LineSegment.h>
41 //using namespace std;
42 using namespace geos::geom
;
45 namespace operation
{ // geos.operation
46 namespace overlay
{ // geos.operation.overlay
47 namespace snap
{ // geos.operation.overlay.snap
50 std::auto_ptr
<Coordinate::Vect
>
51 LineStringSnapper::snapTo(const geom::Coordinate::ConstVect
& snapPts
)
53 geom::CoordinateList
coordList(srcPts
);
55 snapVertices(coordList
, snapPts
);
56 snapSegments(coordList
, snapPts
);
58 return coordList
.toCoordinateArray();
63 LineStringSnapper::snapVertices(geom::CoordinateList
& srcCoords
,
64 const geom::Coordinate::ConstVect
& snapPts
)
66 if ( srcCoords
.empty() ) return;
69 cerr
<< "Snapping vertices of: " << srcCoords
<< endl
;
72 using geom::CoordinateList
;
74 geom::Coordinate::ConstVect::const_iterator not_found
= snapPts
.end();
76 // try snapping vertices
77 // if src is a ring then don't snap final vertex
78 CoordinateList::iterator it
= srcCoords
.begin();
79 CoordinateList::iterator end
= srcCoords
.end();
80 CoordinateList::iterator last
= end
; --last
;
81 if ( isClosed
) --end
;
82 for ( ; it
!= end
; ++it
)
84 Coordinate
& srcPt
= *it
;
87 cerr
<< "Checking for a snap for source coordinate " << srcPt
<< endl
;
90 geom::Coordinate::ConstVect::const_iterator found
= findSnapForVertex(srcPt
, snapPts
);
91 if ( found
== not_found
)
92 { // no snaps found (or no need to snap)
94 cerr
<< " no snap found" << endl
;
100 const Coordinate
& snapPt
= *(*found
);
103 cerr
<< " found snap point " << snapPt
<< endl
;
106 // update src with snap pt
110 cerr
<< " source point became " << srcPt
<< endl
;
113 // keep final closing point in synch (rings only)
114 if (it
== srcCoords
.begin() && isClosed
)
122 Coordinate::ConstVect::const_iterator
123 LineStringSnapper::findSnapForVertex(const Coordinate
& pt
,
124 const Coordinate::ConstVect
& snapPts
)
127 // TODO: use std::find_if
128 Coordinate::ConstVect::const_iterator end
=snapPts
.end();
129 for ( Coordinate::ConstVect::const_iterator
135 const Coordinate
& snapPt
= *(*it
);
137 // shouldn't we look for *all* segments to be snapped rather then a single one?
138 if ( snapPt
.equals2D(pt
) )
141 cerr
<< " points are equal, returning not-found " << endl
;
147 double dist
= snapPt
.distance(pt
);
149 cerr
<< " distance from snap point " << snapPt
<< ": " << dist
<< endl
;
152 if ( dist
< snapTolerance
)
155 cerr
<< " snap point within tolerance, returning iterator to it" << endl
;
162 cerr
<< " no snap point within distance, returning not-found" << endl
;
171 LineStringSnapper::snapSegments(geom::CoordinateList
& srcCoords
,
172 const geom::Coordinate::ConstVect
& snapPts
)
175 // nothing to do if there are no source coords..
176 if ( srcCoords
.empty() ) return;
179 cerr
<< "Snapping segments of: " << srcCoords
<< endl
;
182 for ( Coordinate::ConstVect::const_iterator
183 it
=snapPts
.begin(), end
=snapPts
.end();
188 const Coordinate
& snapPt
= *(*it
);
191 cerr
<< "Checking for a segment to snap to snapPt " << snapPt
<< endl
;
194 // shouldn't we look for *all* segments to be snapped
195 // rather then a single one?
196 CoordinateList::iterator too_far
= srcCoords
.end(); --too_far
;
197 CoordinateList::iterator segpos
=
198 findSegmentToSnap(snapPt
, srcCoords
.begin(), too_far
);
199 if ( segpos
== too_far
)
202 cerr
<< " No segment to snap" << endl
;
207 cerr
<< " Segment to be snapped found, inserting point" << endl
;
209 // insert must happen one-past first point (before next point)
211 srcCoords
.insert(segpos
, snapPt
);
215 cerr
<< " After segment snapping, srcCoors are: " << srcCoords
<< endl
;
221 /* NOTE: this is called findSegmentIndexToSnap in JTS */
222 CoordinateList::iterator
223 LineStringSnapper::findSegmentToSnap(
224 const Coordinate
& snapPt
,
225 CoordinateList::iterator from
,
226 CoordinateList::iterator too_far
)
229 double minDist
= snapTolerance
+1; // make sure the first closer then
230 // snapTolerance is accepted
231 CoordinateList::iterator match
=too_far
;
233 // TODO: use std::find_if
234 for ( ; from
!= too_far
; ++from
)
237 CoordinateList::iterator to
= from
;
242 cerr
<< " Checking segment " << seg
<< endl
;
245 /** * Check if the snap pt is equal to one of
246 * the segment endpoints.
248 * If the snap pt is already in the src list,
249 * don't snap at all (unless allowSnappingToSourceVertices
252 if ( seg
.p0
.equals2D(snapPt
) || seg
.p1
.equals2D(snapPt
) )
255 if (allowSnappingToSourceVertices
) {
257 cerr
<< " snap point matches a segment endpoint, checking next segment"
263 cerr
<< " snap point matches a segment endpoint, giving up seek" << endl
;
269 double dist
= seg
.distance(snapPt
);
270 if ( dist
< snapTolerance
) {
271 if ( dist
< minDist
) {
273 cerr
<< " snap point distance " << dist
<< " within tolerance "
274 << snapTolerance
<< " and closer than previous candidate " << minDist
282 cerr
<< " snap point distance " << dist
<< " within tolerance "
283 << snapTolerance
<< " but not closer than previous candidate " << minDist
290 cerr
<< " snap point distance " << dist
<< " bigger than tolerance "
291 << snapTolerance
<< endl
;
299 } // namespace geos.operation.snap
300 } // namespace geos.operation.overlay
301 } // namespace geos.operation