root/MGET/Branches/Jason/Libraries/geos-3.3.2/src/operation/buffer/SubgraphDepthLocater.cpp @ 891

Revision 891, 14.0 KB (checked in by jjr8, 18 months ago)

* Incremented build number.
* Added Libraries/geos-3.3.2

Line 
1/**********************************************************************
2 * $Id: SubgraphDepthLocater.cpp 3245 2011-02-23 16:46:10Z strk $
3 *
4 * GEOS - Geometry Engine Open Source
5 * http://geos.refractions.net
6 *
7 * Copyright (C) 2001-2002 Vivid Solutions Inc.
8 * Copyright (C) 2005 Refractions Research Inc.
9 *
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.
14 *
15 **********************************************************************
16 *
17 * Last port: operation/buffer/SubgraphDepthLocater.java r320 (JTS-1.12)
18 *
19 **********************************************************************/
20
21#include <vector>
22#include <cassert>
23#include <algorithm>
24
25#include <geos/operation/buffer/BufferSubgraph.h>
26#include <geos/operation/buffer/SubgraphDepthLocater.h>
27
28#include <geos/algorithm/CGAlgorithms.h>
29
30#include <geos/geom/Envelope.h>
31#include <geos/geom/CoordinateSequence.h>
32
33#include <geos/geomgraph/DirectedEdge.h>
34#include <geos/geomgraph/Edge.h>
35#include <geos/geomgraph/Position.h>
36
37#ifndef GEOS_DEBUG
38#define GEOS_DEBUG 0
39#endif
40
41using namespace std;
42using namespace geos::geomgraph;
43using namespace geos::algorithm;
44using namespace geos::geom;
45
46namespace geos {
47namespace operation { // geos.operation
48namespace buffer { // geos.operation.buffer
49
50/*
51 * A segment from a directed edge which has been assigned a depth value
52 * for its sides.
53 */
54class DepthSegment {
55
56private:
57
58        geom::LineSegment upwardSeg;
59
60        /*
61         * Compare two collinear segments for left-most ordering.
62         * If segs are vertical, use vertical ordering for comparison.
63         * If segs are equal, return 0.
64         * Segments are assumed to be directed so that the second
65         * coordinate is >= to the first
66         * (e.g. up and to the right).
67         *
68         * @param seg0 a segment to compare
69         * @param seg1 a segment to compare
70         * @return
71         */
72        static int compareX(const geom::LineSegment *seg0, const geom::LineSegment *seg1)
73        {
74                int compare0=seg0->p0.compareTo(seg1->p0);
75                if (compare0!=0) return compare0;
76                return seg0->p1.compareTo(seg1->p1);
77        }
78
79public:
80
81        int leftDepth;
82
83        /// @param seg will be copied to private space
84        DepthSegment(const geom::LineSegment &seg, int depth)
85                :
86                upwardSeg(seg),
87                leftDepth(depth)
88        {
89                // input seg is assumed to be normalized
90                //upwardSeg.normalize();
91        }
92
93        /**
94         * Defines a comparision operation on DepthSegments
95         * which orders them left to right
96         *
97         * <pre>
98         * DS1 < DS2   if   DS1.seg is left of DS2.seg
99         * DS1 > DS2   if   DS1.seg is right of DS2.seg
100         * </pre>
101         *
102         * @param obj
103         * @return
104         */
105        int compareTo(const DepthSegment& other) const
106        {
107                /**
108                 * try and compute a determinate orientation for the segments.
109                 * Test returns 1 if other is left of this (i.e. this > other)
110                 */
111                int orientIndex=upwardSeg.orientationIndex(&(other.upwardSeg));
112
113                /**
114                 * If comparison between this and other is indeterminate,
115                 * try the opposite call order.
116                 * orientationIndex value is 1 if this is left of other,
117                 * so have to flip sign to get proper comparison value of
118                 * -1 if this is leftmost
119                 */
120                if (orientIndex==0)
121                        orientIndex=-1 * other.upwardSeg.orientationIndex(&upwardSeg);
122
123                // if orientation is determinate, return it
124                if (orientIndex != 0)
125                        return orientIndex;
126
127                // otherwise, segs must be collinear - sort based on minimum X value
128                return compareX(&upwardSeg, &(other.upwardSeg));
129        }
130};
131
132struct DepthSegmentLessThen {
133        bool operator() (const DepthSegment* first, const DepthSegment* second)
134        {
135                assert(first);
136                assert(second);
137                if (first->compareTo(*second)<0) return true;
138                else return false;
139        }
140};
141
142
143
144/*public*/
145int
146SubgraphDepthLocater::getDepth(const Coordinate& p)
147{
148        vector<DepthSegment*> stabbedSegments;
149        findStabbedSegments(p, stabbedSegments);
150
151        // if no segments on stabbing line subgraph must be outside all others
152        if (stabbedSegments.size()==0) return 0;
153
154        sort(stabbedSegments.begin(), stabbedSegments.end(), DepthSegmentLessThen());
155
156        DepthSegment *ds=stabbedSegments[0];
157        int ret = ds->leftDepth;
158
159#if GEOS_DEBUG
160        cerr<<"SubgraphDepthLocater::getDepth("<<p.toString()<<"): "<<ret<<endl;
161#endif
162
163        for (vector<DepthSegment *>::iterator
164                it=stabbedSegments.begin(), itEnd=stabbedSegments.end();
165                it != itEnd;
166                ++it)
167        {
168                delete *it;
169        }
170
171        return ret;
172}
173
174/*private*/
175void
176SubgraphDepthLocater::findStabbedSegments(const Coordinate &stabbingRayLeftPt,
177                        std::vector<DepthSegment*>& stabbedSegments)
178{
179        size_t size = subgraphs->size();
180        for (size_t i=0; i<size; ++i)
181        {
182                BufferSubgraph *bsg=(*subgraphs)[i];
183
184                // optimization - don't bother checking subgraphs
185                // which the ray does not intersect
186                Envelope *env = bsg->getEnvelope();
187                if ( stabbingRayLeftPt.y < env->getMinY()
188                        || stabbingRayLeftPt.y > env->getMaxY()
189                        || stabbingRayLeftPt.x < env->getMinX()
190                        || stabbingRayLeftPt.x > env->getMaxX())
191                {
192                                continue;
193                }
194
195                findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(),
196                        stabbedSegments);
197        }
198}
199
200/*private*/
201void
202SubgraphDepthLocater::findStabbedSegments(
203        const Coordinate &stabbingRayLeftPt,
204        vector<DirectedEdge*>* dirEdges,
205        vector<DepthSegment*>& stabbedSegments)
206{
207
208        /**
209         * Check all forward DirectedEdges only. This is still general,
210         * because each Edge has a forward DirectedEdge.
211         */
212        for (size_t i=0, n=dirEdges->size(); i<n; ++i)
213        {
214                DirectedEdge *de=(*dirEdges)[i];
215                if (!de->isForward()) continue;
216                findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments);
217        }
218}
219
220/*private*/
221void
222SubgraphDepthLocater::findStabbedSegments(
223        const Coordinate &stabbingRayLeftPt,
224        DirectedEdge *dirEdge,
225        vector<DepthSegment*>& stabbedSegments)
226{
227        const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates();
228
229// It seems that LineSegment is *very* slow... undef this
230// to see yourself
231// LineSegment has been refactored to be mostly inline, still
232// it makes copies of the given coordinates, while the 'non-LineSemgent'
233// based code below uses pointers instead. I'll kip the SKIP_LS
234// defined until LineSegment switches to Coordinate pointers instead.
235//
236#define SKIP_LS 1
237
238        int n = pts->getSize()-1;
239        for (int i=0; i<n; ++i) {
240#ifndef SKIP_LS
241                seg.p0=pts->getAt(i);
242                seg.p1=pts->getAt(i + 1);
243#if GEOS_DEBUG
244                cerr << " SubgraphDepthLocater::findStabbedSegments: segment " << i
245                        << " (" << seg << ") ";
246#endif
247
248#else
249                const Coordinate *low=&(pts->getAt(i));
250                const Coordinate *high=&(pts->getAt(i+1));
251                const Coordinate *swap=NULL;
252
253#endif
254
255#ifndef SKIP_LS
256                // ensure segment always points upwards
257                //if (seg.p0.y > seg.p1.y)
258                {
259                        seg.reverse();
260#if GEOS_DEBUG
261                        cerr << " reverse (" << seg << ") ";
262#endif
263                }
264#else
265                if (low->y > high->y)
266                {
267                        swap=low;
268                        low=high;
269                        high=swap;
270                }
271#endif
272
273                // skip segment if it is left of the stabbing line
274                // skip if segment is above or below stabbing line
275#ifndef SKIP_LS
276                double maxx=max(seg.p0.x, seg.p1.x);
277#else
278                double maxx=max(low->x, high->x);
279#endif
280                if (maxx < stabbingRayLeftPt.x)
281                {
282#if GEOS_DEBUG
283                        cerr<<" segment is left to stabbing line, skipping "<<endl;
284#endif
285                        continue;
286                }
287
288                // skip horizontal segments (there will be a non-horizontal
289                // one carrying the same depth info
290#ifndef SKIP_LS
291                if (seg.isHorizontal())
292#else
293                if (low->y == high->y)
294#endif
295                {
296#if GEOS_DEBUG
297                        cerr<<" segment is horizontal, skipping "<<endl;
298#endif
299                        continue;
300                }
301
302                // skip if segment is above or below stabbing line
303#ifndef SKIP_LS
304                if (stabbingRayLeftPt.y < seg.p0.y ||
305                        stabbingRayLeftPt.y > seg.p1.y)
306#else
307                if (stabbingRayLeftPt.y < low->y ||
308                        stabbingRayLeftPt.y > high->y)
309#endif
310                {
311#if GEOS_DEBUG
312                        cerr<<" segment above or below stabbing line, skipping "<<endl;
313#endif
314                        continue;
315                }
316
317                // skip if stabbing ray is right of the segment
318#ifndef SKIP_LS
319                if (CGAlgorithms::computeOrientation(seg.p0, seg.p1,
320#else
321                if (CGAlgorithms::computeOrientation(*low, *high,
322#endif
323                                stabbingRayLeftPt)==CGAlgorithms::RIGHT)
324                {
325#if GEOS_DEBUG
326                        cerr<<" stabbing ray right of segment, skipping"<<endl;
327#endif
328                        continue;
329                }
330
331#ifndef SKIP_LS
332                // stabbing line cuts this segment, so record it
333                int depth=dirEdge->getDepth(Position::LEFT);
334                // if segment direction was flipped, use RHS depth instead
335                if (! (seg.p0==pts->getAt(i)))
336                        depth=dirEdge->getDepth(Position::RIGHT);
337#else
338                int depth = swap ?
339                        dirEdge->getDepth(Position::RIGHT)
340                        :
341                        dirEdge->getDepth(Position::LEFT);
342#endif
343
344#if GEOS_DEBUG
345        cerr<<" depth: "<<depth<<endl;
346#endif
347
348#ifdef SKIP_LS
349                seg.p0 = *low;
350                seg.p1 = *high;
351#endif
352
353                DepthSegment *ds=new DepthSegment(seg, depth);
354                stabbedSegments.push_back(ds);
355        }
356}
357
358} // namespace geos.operation.buffer
359} // namespace geos.operation
360} // namespace geos
361
362/**********************************************************************
363 * $Log$
364 * Revision 1.29  2006/06/12 11:29:23  strk
365 * unsigned int => size_t
366 *
367 * Revision 1.28  2006/03/20 10:13:15  strk
368 * Bug #71 - Missing <algorithm>
369 *
370 * Revision 1.27  2006/03/17 13:24:59  strk
371 * opOverlay.h header splitted. Reduced header inclusions in operation/overlay implementation files. ElevationMatrixFilter code moved from own file to ElevationMatrix.cpp (ideally a class-private).
372 *
373 * Revision 1.26  2006/03/15 18:57:39  strk
374 * small cleanup
375 *
376 * Revision 1.25  2006/03/15 15:50:12  strk
377 * const correctness, cleanups
378 *
379 * Revision 1.24  2006/03/15 12:52:56  strk
380 * DepthSegment class moved inside SubgraphDepthLocator implementaion
381 * as it was private to this file in JTS. Also, changed to reduce
382 * copies of LineSegment copies.
383 *
384 * Revision 1.23  2006/03/14 00:19:40  strk
385 * opBuffer.h split, streamlined headers in some (not all) files in operation/buffer/
386 *
387 * Revision 1.22  2006/03/09 16:46:49  strk
388 * geos::geom namespace definition, first pass at headers split
389 *
390 * Revision 1.21  2006/03/03 10:46:21  strk
391 * Removed 'using namespace' from headers, added missing headers in .cpp files, removed useless includes in headers (bug#46)
392 *
393 * Revision 1.20  2006/03/02 12:12:01  strk
394 * Renamed DEBUG macros to GEOS_DEBUG, all wrapped in #ifndef block to allow global override (bug#43)
395 *
396 * Revision 1.19  2006/03/02 09:46:04  strk
397 * cleaned up debugging lines
398 *
399 * Revision 1.18  2006/03/01 17:16:39  strk
400 * LineSegment class made final and optionally (compile-time) inlined.
401 * Reduced heap allocations in Centroid{Area,Line,Point} and InteriorPoint{Area,Line,Point}.
402 *
403 * Revision 1.17  2006/02/19 19:46:49  strk
404 * Packages <-> namespaces mapping for most GEOS internal code (uncomplete, but working). Dir-level libs for index/ subdirs.
405 *
406 * Revision 1.16  2006/01/31 19:07:34  strk
407 * - Renamed DefaultCoordinateSequence to CoordinateArraySequence.
408 * - Moved GetNumGeometries() and GetGeometryN() interfaces
409 *   from GeometryCollection to Geometry class.
410 * - Added getAt(int pos, Coordinate &to) funtion to CoordinateSequence class.
411 * - Reworked automake scripts to produce a static lib for each subdir and
412 *   then link all subsystem's libs togheter
413 * - Moved C-API in it's own top-level dir capi/
414 * - Moved source/bigtest and source/test to tests/bigtest and test/xmltester
415 * - Fixed PointLocator handling of LinearRings
416 * - Changed CoordinateArrayFilter to reduce memory copies
417 * - Changed UniqueCoordinateArrayFilter to reduce memory copies
418 * - Added CGAlgorithms::isPointInRing() version working with
419 *   Coordinate::ConstVect type (faster!)
420 * - Ported JTS-1.7 version of ConvexHull with big attention to
421 *   memory usage optimizations.
422 * - Improved XMLTester output and user interface
423 * - geos::geom::util namespace used for geom/util stuff
424 * - Improved memory use in geos::geom::util::PolygonExtractor
425 * - New ShortCircuitedGeometryVisitor class
426 * - New operation/predicate package
427 *
428 * Revision 1.15  2005/11/08 20:12:44  strk
429 * Memory overhead reductions in buffer operations.
430 *
431 * Revision 1.14  2005/07/11 10:27:14  strk
432 * Fixed initializzazion lists
433 *
434 * Revision 1.13  2005/06/30 18:31:48  strk
435 * Ported SubgraphDepthLocator optimizations from JTS code
436 *
437 * Revision 1.12  2005/06/28 21:13:43  strk
438 * Fixed a bug introduced by LineSegment skip - made LineSegment skip a compile-time optione
439 *
440 * Revision 1.11  2005/06/27 21:58:31  strk
441 * Bugfix in DepthSegmentLT as suggested by Graeme Hiebert
442 *
443 * Revision 1.10  2005/06/27 21:24:54  strk
444 * Fixed bug just-introduced with optimization.
445 *
446 * Revision 1.9  2005/06/27 21:21:21  strk
447 * Reduced Coordinate copies due to LineSegment overuse
448 *
449 * Revision 1.8  2005/05/23 15:13:00  strk
450 * Added debugging output
451 *
452 * Revision 1.7  2005/05/20 16:15:41  strk
453 * Code cleanups
454 *
455 * Revision 1.6  2005/05/19 10:29:28  strk
456 * Removed some CGAlgorithms instances substituting them with direct calls
457 * to the static functions. Interfaces accepting CGAlgorithms pointers kept
458 * for backward compatibility but modified to make the argument optional.
459 * Fixed a small memory leak in OffsetCurveBuilder::getRingCurve.
460 * Inlined some smaller functions encountered during bug hunting.
461 * Updated Copyright notices in the touched files.
462 *
463 * Revision 1.5  2004/07/08 19:34:49  strk
464 * Mirrored JTS interface of CoordinateSequence, factory and
465 * default implementations.
466 * Added CoordinateArraySequenceFactory::instance() function.
467 *
468 * Revision 1.4  2004/07/02 13:28:28  strk
469 * Fixed all #include lines to reflect headers layout change.
470 * Added client application build tips in README.
471 *
472 * Revision 1.3  2004/05/05 12:29:44  strk
473 * memleak fixed in ::getDepth
474 *
475 * Revision 1.2  2004/05/03 22:56:44  strk
476 * leaks fixed, exception specification omitted.
477 *
478 * Revision 1.1  2004/04/10 08:40:01  ybychkov
479 * "operation/buffer" upgraded to JTS 1.4
480 *
481 *
482 **********************************************************************/
483
Note: See TracBrowser for help on using the browser.