1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2013 Sandro Santilli <strk@keybit.net>
7 * Copyright (C) 2005-2006 Refractions Research Inc.
8 * Copyright (C) 2001-2002 Vivid Solutions 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: algorithm/InteriorPointArea.java r728 (JTS-1.13+)
19 **********************************************************************/
21 #include <geos/algorithm/InteriorPointArea.h>
22 #include <geos/geom/Coordinate.h>
23 #include <geos/geom/Geometry.h>
24 #include <geos/geom/GeometryCollection.h>
25 #include <geos/geom/Polygon.h>
26 #include <geos/geom/LineString.h>
27 #include <geos/geom/Envelope.h>
28 #include <geos/geom/GeometryFactory.h>
29 #include <geos/geom/CoordinateSequenceFactory.h>
33 #include <memory> // for auto_ptr
36 using namespace geos::geom
;
39 namespace algorithm
{ // geos.algorithm
44 double avg(double a
, double b
){return (a
+b
)/2.0;}
47 * Finds a safe bisector Y ordinate
48 * by projecting to the Y axis
49 * and finding the Y-ordinate interval
50 * which contains the centre of the Y extent.
51 * The centre of this interval is returned as the bisector Y-ordinate.
56 class SafeBisectorFinder
59 static double getBisectorY(const Polygon
& poly
)
61 SafeBisectorFinder
finder(poly
);
62 return finder
.getBisectorY();
64 SafeBisectorFinder(const Polygon
& nPoly
)
67 // initialize using extremal values
68 hiY
= poly
.getEnvelopeInternal()->getMaxY();
69 loY
= poly
.getEnvelopeInternal()->getMinY();
70 centreY
= avg(loY
, hiY
);
75 process(*poly
.getExteriorRing());
76 for (size_t i
= 0; i
< poly
.getNumInteriorRing(); i
++) {
77 process(*poly
.getInteriorRingN(i
));
79 double bisectY
= avg(hiY
, loY
);
91 void process(const LineString
& line
) {
92 const CoordinateSequence
* seq
= line
.getCoordinatesRO();
93 for (std::size_t i
= 0, s
= seq
->size(); i
< s
; i
++) {
94 double y
= seq
->getY(i
);
99 void updateInterval(double y
) {
104 else if (y
> centreY
) {
111 SafeBisectorFinder(SafeBisectorFinder
const&); /*= delete*/
112 SafeBisectorFinder
& operator=(SafeBisectorFinder
const&); /*= delete*/
115 } // anonymous namespace
119 InteriorPointArea::InteriorPointArea(const Geometry
*g
)
123 factory
=g
->getFactory();
128 InteriorPointArea::~InteriorPointArea()
134 InteriorPointArea::getInteriorPoint(Coordinate
& ret
) const
136 if ( ! foundInterior
) return false;
144 InteriorPointArea::add(const Geometry
*geom
)
146 const Polygon
*poly
= dynamic_cast<const Polygon
*>(geom
);
152 const GeometryCollection
*gc
= dynamic_cast<const GeometryCollection
*>(geom
);
155 for(std::size_t i
=0, n
=gc
->getNumGeometries(); i
<n
; i
++) {
156 add(gc
->getGeometryN(i
));
163 InteriorPointArea::addPolygon(const Geometry
*geometry
)
165 if (geometry
->isEmpty()) return;
170 auto_ptr
<LineString
> bisector ( horizontalBisector(geometry
) );
171 if ( bisector
->getLength() == 0.0 ) {
173 intPt
= bisector
->getCoordinateN(0);
176 auto_ptr
<Geometry
> intersections ( bisector
->intersection(geometry
) );
177 const Geometry
*widestIntersection
= widestGeometry(intersections
.get());
178 const Envelope
*env
= widestIntersection
->getEnvelopeInternal();
179 width
=env
->getWidth();
182 if (!foundInterior
|| width
>maxWidth
) {
183 interiorPoint
= intPt
;
189 //@return if geometry is a collection, the widest sub-geometry; otherwise,
190 //the geometry itself
192 InteriorPointArea::widestGeometry(const Geometry
*geometry
)
194 const GeometryCollection
*gc
= dynamic_cast<const GeometryCollection
*>(geometry
);
196 return widestGeometry(gc
);
203 InteriorPointArea::widestGeometry(const GeometryCollection
* gc
) {
207 const Geometry
* widestGeometry
=gc
->getGeometryN(0);
209 // scan remaining geom components to see if any are wider
210 for(std::size_t i
=1, n
=gc
->getNumGeometries(); i
<n
; i
++) // start at 1
212 const Envelope
*env1(gc
->getGeometryN(i
)->getEnvelopeInternal());
213 const Envelope
*env2(widestGeometry
->getEnvelopeInternal());
214 if (env1
->getWidth()>env2
->getWidth()) {
215 widestGeometry
=gc
->getGeometryN(i
);
218 return widestGeometry
;
223 InteriorPointArea::horizontalBisector(const Geometry
*geometry
)
225 const Envelope
*envelope
=geometry
->getEnvelopeInternal();
228 * Original algorithm. Fails when geometry contains a horizontal
229 * segment at the Y midpoint.
231 // Assert: for areas, minx <> maxx
232 //double avgY=avg(envelope->getMinY(),envelope->getMaxY());
234 double bisectY
= SafeBisectorFinder::getBisectorY(*dynamic_cast<const Polygon
*>(geometry
));
235 vector
<Coordinate
>*cv
=new vector
<Coordinate
>(2);
236 (*cv
)[0].x
= envelope
->getMinX();
237 (*cv
)[0].y
= bisectY
;
238 (*cv
)[1].x
= envelope
->getMaxX();
239 (*cv
)[1].y
= bisectY
;
241 CoordinateSequence
*cl
= factory
->getCoordinateSequenceFactory()->create(cv
);
243 LineString
*ret
= factory
->createLineString(cl
);
247 } // namespace geos.algorithm