[geos-commits] r3195 - in trunk: include/geos/operation/union
src/operation/union
svn_geos at osgeo.org
svn_geos at osgeo.org
Thu Feb 10 09:14:30 EST 2011
Author: strk
Date: 2011-02-10 06:14:30 -0800 (Thu, 10 Feb 2011)
New Revision: 3195
Added:
trunk/include/geos/operation/union/UnaryUnionOp.h
trunk/src/operation/union/UnaryUnionOp.cpp
Modified:
trunk/include/geos/operation/union/Makefile.am
trunk/src/operation/union/Makefile.am
Log:
UnaryUnionOp port from JTS-1.12
Modified: trunk/include/geos/operation/union/Makefile.am
===================================================================
--- trunk/include/geos/operation/union/Makefile.am 2011-02-10 14:10:17 UTC (rev 3194)
+++ trunk/include/geos/operation/union/Makefile.am 2011-02-10 14:14:30 UTC (rev 3195)
@@ -10,4 +10,5 @@
geos_HEADERS = \
CascadedPolygonUnion.h \
- PointGeometryUnion.h
+ PointGeometryUnion.h \
+ UnaryUnionOp.h
Added: trunk/include/geos/operation/union/UnaryUnionOp.h
===================================================================
--- trunk/include/geos/operation/union/UnaryUnionOp.h (rev 0)
+++ trunk/include/geos/operation/union/UnaryUnionOp.h 2011-02-10 14:14:30 UTC (rev 3195)
@@ -0,0 +1,215 @@
+/**********************************************************************
+ * $Id$
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.refractions.net
+ *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation.
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * Last port: operation/union/UnaryUnionOp.java r320 (JTS-1.12)
+ *
+ **********************************************************************/
+
+#ifndef GEOS_OP_UNION_UNARYUNION_H
+#define GEOS_OP_UNION_UNARYUNION_H
+
+#include <memory>
+#include <vector>
+
+#include <geos/export.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/LineString.h>
+#include <geos/geom/Polygon.h>
+#include <geos/geom/util/GeometryExtracter.h>
+#include <geos/operation/overlay/snap/SnapIfNeededOverlayOp.h>
+
+// Forward declarations
+namespace geos {
+ namespace geom {
+ class GeometryFactory;
+ class Geometry;
+ }
+}
+
+namespace geos {
+namespace operation { // geos::operation
+namespace geounion { // geos::operation::geounion
+
+/**
+ * Unions a collection of Geometry or a single Geometry
+ * (which may be a collection) together.
+ * By using this special-purpose operation over a collection of
+ * geometries it is possible to take advantage of various optimizations
+ * to improve performance.
+ * Heterogeneous {@link GeometryCollection}s are fully supported.
+ *
+ * The result obeys the following contract:
+ *
+ * - Unioning a set of overlapping {@link Polygons}s has the effect of
+ * merging the areas (i.e. the same effect as
+ * iteratively unioning all individual polygons together).
+ * - Unioning a set of {@link LineString}s has the effect of
+ * <b>fully noding</b> and <b>dissolving</b> the input linework.
+ * In this context "fully noded" means that there will be a node or
+ * endpoint in the output for every endpoint or line segment crossing
+ * in the input.
+ * "Dissolved" means that any duplicate (e.g. coincident) line segments
+ * or portions of line segments will be reduced to a single line segment
+ * in the output. * This is consistent with the semantics of the
+ * {@link Geometry#union(Geometry)} operation.
+ * If <b>merged</b> linework is required, the {@link LineMerger} class
+ * can be used.
+ * - Unioning a set of {@link Points}s has the effect of merging
+ * al identical points (producing a set with no duplicates).
+ *
+ * <tt>UnaryUnion</tt> always operates on the individual components of
+ * MultiGeometries.
+ * So it is possible to use it to "clean" invalid self-intersecting
+ * MultiPolygons (although the polygon components must all still be
+ * individually valid.)
+ */
+class GEOS_DLL UnaryUnionOp
+{
+public:
+
+ template <typename T>
+ static std::auto_ptr<geom::Geometry> Union(const T& geoms)
+ {
+ UnaryUnionOp op(geoms);
+ return op.Union();
+ }
+
+ template <class T>
+ static std::auto_ptr<geom::Geometry> Union(const T& geoms,
+ geom::GeometryFactory& geomFact)
+ {
+ UnaryUnionOp op(geoms, geomFact);
+ return op.Union();
+ }
+
+ static std::auto_ptr<geom::Geometry> Union(const geom::Geometry& geom)
+ {
+ UnaryUnionOp op(geom);
+ return op.Union();
+ }
+
+ template <class T>
+ UnaryUnionOp(const T& geoms, geom::GeometryFactory& geomFactIn)
+ :
+ geomFact(&geomFactIn)
+ {
+ extractAll(geoms);
+ }
+
+ template <class T>
+ UnaryUnionOp(const T& geoms)
+ :
+ geomFact(0)
+ {
+ extractAll(geoms);
+ }
+
+ UnaryUnionOp(const geom::Geometry& geom)
+ :
+ geomFact(geom.getFactory())
+ {
+ extract(geom);
+ }
+
+ /**
+ * \brief
+ * Gets the union of the input geometries.
+ *
+ * If no input geometries were provided, a POINT EMPTY is returned.
+ *
+ * @return a Geometry containing the union
+ * @return an empty GEOMETRYCOLLECTION if no geometries were provided
+ * in the input
+ */
+ std::auto_ptr<geom::Geometry> Union();
+
+private:
+
+ template <typename T>
+ void extractGeoms(const T& geoms)
+ {
+ for (typename T::const_iterator
+ i=geoms.begin(),
+ e=geoms.end();
+ i!=e;
+ ++i)
+ {
+ const geom::Geometry* geom = *i;
+ extract(*geom);
+ }
+ }
+
+ void extract(const geom::Geometry& geom)
+ {
+ using namespace geom::util;
+
+ if ( ! geomFact ) geomFact = geom.getFactory();
+
+ GeometryExtracter::extract<geom::Polygon>(geom, polygons);
+ GeometryExtracter::extract<geom::LineString>(geom, lines);
+ GeometryExtracter::extract<geom::Point>(geom, points);
+ }
+
+ /**
+ * Computes a unary union with no extra optimization,
+ * and no short-circuiting.
+ * Due to the way the overlay operations
+ * are implemented, this is still efficient in the case of linear
+ * and puntal geometries.
+ * Uses robust version of overlay operation
+ * to ensure identical behaviour to the <tt>union(Geometry)</tt> operation.
+ *
+ * @param g0 a geometry
+ * @return the union of the input geometry
+ */
+ std::auto_ptr<geom::Geometry> unionNoOpt(const geom::Geometry& g0)
+ {
+ using geos::operation::overlay::OverlayOp;
+ using geos::operation::overlay::snap::SnapIfNeededOverlayOp;
+
+ if ( ! empty.get() ) {
+ empty.reset( geomFact->createEmptyGeometry() );
+ }
+ return SnapIfNeededOverlayOp::overlayOp(g0, *empty, OverlayOp::opUNION);
+ }
+
+ /**
+ * Computes the union of two geometries,
+ * either of both of which may be null.
+ *
+ * @param g0 a Geometry (ownership transferred)
+ * @param g1 a Geometry (ownership transferred)
+ * @return the union of the input(s)
+ * @return null if both inputs are null
+ */
+ std::auto_ptr<geom::Geometry> unionWithNull(std::auto_ptr<geom::Geometry> g0,
+ std::auto_ptr<geom::Geometry> g1);
+
+ std::vector<const geom::Polygon*> polygons;
+ std::vector<const geom::LineString*> lines;
+ std::vector<const geom::Point*> points;
+
+ const geom::GeometryFactory* geomFact;
+
+ std::auto_ptr<geom::Geometry> empty;
+};
+
+
+} // namespace geos::operation::union
+} // namespace geos::operation
+} // namespace geos
+
+#endif
Modified: trunk/src/operation/union/Makefile.am
===================================================================
--- trunk/src/operation/union/Makefile.am 2011-02-10 14:10:17 UTC (rev 3194)
+++ trunk/src/operation/union/Makefile.am 2011-02-10 14:14:30 UTC (rev 3195)
@@ -10,6 +10,7 @@
libopunion_la_SOURCES = \
CascadedPolygonUnion.cpp \
- PointGeometryUnion.cpp
+ PointGeometryUnion.cpp \
+ UnaryUnionOp.cpp
libopunion_la_LIBADD =
Added: trunk/src/operation/union/UnaryUnionOp.cpp
===================================================================
--- trunk/src/operation/union/UnaryUnionOp.cpp (rev 0)
+++ trunk/src/operation/union/UnaryUnionOp.cpp 2011-02-10 14:14:30 UTC (rev 3195)
@@ -0,0 +1,127 @@
+/**********************************************************************
+ * $Id$
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.refractions.net
+ *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation.
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * Last port: operation/union/UnaryUnionOp.java r320 (JTS-1.12)
+ *
+ **********************************************************************/
+
+#include <memory> // for auto_ptr
+#include <cassert> // for assert
+#include <algorithm> // for copy
+
+#include <geos/operation/union/UnaryUnionOp.h>
+#include <geos/operation/union/CascadedPolygonUnion.h>
+#include <geos/operation/union/PointGeometryUnion.h>
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/Puntal.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/MultiPoint.h>
+#include <geos/geom/MultiLineString.h>
+#include <geos/geom/MultiPolygon.h>
+#include <geos/geom/GeometryCollection.h>
+#include <geos/geom/Geometry.h>
+#include <geos/geom/Location.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/util/GeometryCombiner.h>
+#include <geos/algorithm/PointLocator.h>
+
+namespace geos {
+namespace operation { // geos::operation
+namespace geounion { // geos::operation::geounion
+
+/*private*/
+std::auto_ptr<geom::Geometry>
+UnaryUnionOp::unionWithNull(std::auto_ptr<geom::Geometry> g0,
+ std::auto_ptr<geom::Geometry> g1)
+{
+ std::auto_ptr<geom::Geometry> ret;
+ if ( ( ! g0.get() ) && ( ! g1.get() ) ) return ret;
+
+ if ( ! g0.get() ) return g1;
+ if ( ! g1.get() ) return g0;
+
+ ret.reset( g0->Union(g1.get()) );
+ return ret;
+}
+
+/*public*/
+std::auto_ptr<geom::Geometry>
+UnaryUnionOp::Union()
+{
+ using geom::Puntal;
+ typedef std::auto_ptr<geom::Geometry> GeomAutoPtr;
+
+ GeomAutoPtr ret;
+ if ( ! geomFact ) return ret;
+
+ /**
+ * For points and lines, only a single union operation is
+ * required, since the OGC model allowings self-intersecting
+ * MultiPoint and MultiLineStrings.
+ * This is not the case for polygons, so Cascaded Union is required.
+ */
+
+ GeomAutoPtr unionPoints;
+ if (!points.empty()) {
+ GeomAutoPtr ptGeom = geomFact->buildGeometry( points.begin(),
+ points.end() );
+ unionPoints = unionNoOpt(*ptGeom);
+ }
+
+ GeomAutoPtr unionLines;
+ if (!lines.empty()) {
+ GeomAutoPtr lineGeom = geomFact->buildGeometry( lines.begin(),
+ lines.end() );
+ unionLines = unionNoOpt(*lineGeom);
+ }
+
+ GeomAutoPtr unionPolygons;
+ if (!polygons.empty()) {
+ unionPolygons.reset( CascadedPolygonUnion::Union( polygons.begin(),
+ polygons.end() ) );
+ }
+
+ /**
+ * Performing two unions is somewhat inefficient,
+ * but is mitigated by unioning lines and points first
+ */
+
+ GeomAutoPtr unionLA = unionWithNull(unionLines, unionPolygons);
+ assert(!unionLines.get()); assert(!unionPolygons.get());
+
+ if ( ! unionPoints.get() ) {
+ ret = unionLA;
+ assert(!unionLA.get());
+ }
+ else if ( ! unionLA.get() ) {
+ ret = unionPoints;
+ assert(!unionPoints.get());
+ }
+ else {
+ Puntal& up = dynamic_cast<Puntal&>(*unionPoints);
+ ret = PointGeometryUnion::Union(up, *unionLA);
+ }
+
+ if ( ! ret.get() ) {
+ ret.reset( geomFact->createGeometryCollection() );
+ }
+
+ return ret;
+
+}
+
+} // namespace geos::operation::union
+} // namespace geos::operation
+} // namespace geos
More information about the geos-commits
mailing list