Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add classes for curved geometry types #1046

Merged
merged 10 commits into from
Apr 30, 2024
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

- New things:
- Add Angle::sinCosSnap to avoid small errors, e.g. with buffer operations (GH-978, Mike Taves)
- Add classes for curved geometry types: CircularString, CompoundCurve, CurvedPolygon, MultiCurve,
MultiSurface (GH-1046, Dan Baston)

- Breaking Changes

Expand Down
7 changes: 6 additions & 1 deletion capi/geos_c.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ enum GEOSGeomTypes {
/** Multipolygon, a homogeneous collection of polygons */
GEOS_MULTIPOLYGON,
/** Geometry collection, a heterogeneous collection of geometry */
GEOS_GEOMETRYCOLLECTION
GEOS_GEOMETRYCOLLECTION,
GEOS_CIRCULARSTRING,
GEOS_COMPOUNDCURVE,
GEOS_CURVEPOLYGON,
GEOS_MULTICURVE,
GEOS_MULTISURFACE,
};

/**
Expand Down
39 changes: 26 additions & 13 deletions capi/geos_ts_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <geos/coverage/CoverageUnion.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Curve.h>
#include <geos/geom/Envelope.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryCollection.h>
Expand All @@ -41,12 +42,14 @@
#include <geos/geom/LinearRing.h>
#include <geos/geom/LineSegment.h>
#include <geos/geom/LineString.h>
#include <geos/geom/MultiCurve.h>
#include <geos/geom/MultiLineString.h>
#include <geos/geom/MultiPoint.h>
#include <geos/geom/MultiPolygon.h>
#include <geos/geom/Point.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/SimpleCurve.h>
#include <geos/geom/prep/PreparedGeometry.h>
#include <geos/geom/prep/PreparedGeometryFactory.h>
#include <geos/geom/util/Densifier.h>
Expand Down Expand Up @@ -162,17 +165,21 @@ using geos::geom::CoordinateXY;
using geos::geom::CoordinateXYM;
using geos::geom::CoordinateXYZM;
using geos::geom::CoordinateSequence;
using geos::geom::Curve;
using geos::geom::Envelope;
using geos::geom::Geometry;
using geos::geom::GeometryCollection;
using geos::geom::GeometryFactory;
using geos::geom::LineString;
using geos::geom::LinearRing;
using geos::geom::MultiCurve;
using geos::geom::MultiLineString;
using geos::geom::MultiPolygon;
using geos::geom::Point;
using geos::geom::Polygon;
using geos::geom::PrecisionModel;
using geos::geom::SimpleCurve;
using geos::geom::Surface;

using geos::io::WKTReader;
using geos::io::WKTWriter;
Expand Down Expand Up @@ -1048,8 +1055,7 @@ extern "C" {
GEOSisRing_r(GEOSContextHandle_t extHandle, const Geometry* g)
{
return execute(extHandle, 2, [&]() {
// both LineString* and LinearRing* can cast to LineString*
const LineString* ls = dynamic_cast<const LineString*>(g);
const Curve* ls = dynamic_cast<const Curve*>(g);
if(ls) {
return ls->isRing();
}
Expand Down Expand Up @@ -1692,6 +1698,8 @@ extern "C" {
if (g->getGeometryTypeId() == geos::geom::GeometryTypeId::GEOS_POLYGON) {
auto p = geos::detail::down_cast<Polygon*>(g);
p->orientRings(exteriorCW);
} else if (g->getGeometryTypeId() == geos::geom::GeometryTypeId::GEOS_CURVEPOLYGON) {
throw geos::util::UnsupportedOperationException("Curved geometries not supported.");
}
}

Expand All @@ -1710,9 +1718,9 @@ extern "C" {
GEOSGetNumInteriorRings_r(GEOSContextHandle_t extHandle, const Geometry* g1)
{
return execute(extHandle, -1, [&]() {
const Polygon* p = dynamic_cast<const Polygon*>(g1);
const Surface* p = dynamic_cast<const Surface*>(g1);
if(!p) {
throw IllegalArgumentException("Argument is not a Polygon");
throw IllegalArgumentException("Argument is not a Surface");
}
return static_cast<int>(p->getNumInteriorRing());
});
Expand Down Expand Up @@ -1802,7 +1810,7 @@ extern "C" {
GEOSisClosed_r(GEOSContextHandle_t extHandle, const Geometry* g1)
{
return execute(extHandle, 2, [&]() {
const LineString* ls = dynamic_cast<const LineString*>(g1);
const Curve* ls = dynamic_cast<const Curve*>(g1);
if(ls) {
return ls->isClosed();
}
Expand All @@ -1812,7 +1820,12 @@ extern "C" {
return mls->isClosed();
}

throw IllegalArgumentException("Argument is not a LineString or MultiLineString");
const MultiCurve* mc = dynamic_cast<const MultiCurve*>(g1);
if(mc) {
return mc->isClosed();
}

throw IllegalArgumentException("Argument is not a Curve, MultiLineString, or MultiCurve");
});
}

Expand Down Expand Up @@ -1840,9 +1853,9 @@ extern "C" {
GEOSGeomGetNumPoints_r(GEOSContextHandle_t extHandle, const Geometry* g1)
{
return execute(extHandle, -1, [&]() {
const LineString* ls = dynamic_cast<const LineString*>(g1);
const SimpleCurve* ls = dynamic_cast<const SimpleCurve*>(g1);
if(!ls) {
throw IllegalArgumentException("Argument is not a LineString");
throw IllegalArgumentException("Argument is not a SimpleCurve");
}
return static_cast<int>(ls->getNumPoints());
});
Expand Down Expand Up @@ -1926,9 +1939,9 @@ extern "C" {
GEOSGetExteriorRing_r(GEOSContextHandle_t extHandle, const Geometry* g1)
{
return execute(extHandle, [&]() {
const Polygon* p = dynamic_cast<const Polygon*>(g1);
const Surface* p = dynamic_cast<const Surface*>(g1);
if(!p) {
throw IllegalArgumentException("Invalid argument (must be a Polygon)");
throw IllegalArgumentException("Invalid argument (must be a Surface)");
}
return p->getExteriorRing();
});
Expand All @@ -1942,9 +1955,9 @@ extern "C" {
GEOSGetInteriorRingN_r(GEOSContextHandle_t extHandle, const Geometry* g1, int n)
{
return execute(extHandle, [&]() {
const Polygon* p = dynamic_cast<const Polygon*>(g1);
const Surface* p = dynamic_cast<const Surface*>(g1);
if(!p) {
throw IllegalArgumentException("Invalid argument (must be a Polygon)");
throw IllegalArgumentException("Invalid argument (must be a Surface)");
}
if(n < 0) {
throw IllegalArgumentException("Index must be non-negative.");
Expand Down Expand Up @@ -2813,7 +2826,7 @@ extern "C" {
GEOSGeom_getCoordSeq_r(GEOSContextHandle_t extHandle, const Geometry* g)
{
return execute(extHandle, [&]() {
const LineString* ls = dynamic_cast<const LineString*>(g);
const SimpleCurve* ls = dynamic_cast<const SimpleCurve*>(g);
if(ls) {
return ls->getCoordinatesRO();
}
Expand Down
37 changes: 37 additions & 0 deletions include/geos/algorithm/CircularArcs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2024 ISciences, LLC
*
* 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.
*
**********************************************************************/

#pragma once

#include <geos/export.h>
#include <geos/geom/Coordinate.h>

#include "geos/geom/Envelope.h"

namespace geos {
namespace algorithm {

class GEOS_DLL CircularArcs {
public:
/// Return the circle center of an arc defined by three points
static geom::CoordinateXY getCenter(const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
const geom::CoordinateXY& p2);

/// Expand an envelope to include an arc defined by three points
static void expandEnvelope(geom::Envelope& e, const geom::CoordinateXY& p0, const geom::CoordinateXY& p1,
const geom::CoordinateXY& p2);
};

}
}
6 changes: 5 additions & 1 deletion include/geos/algorithm/ConvexHull.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include <geos/util/UniqueCoordinateArrayFilter.h>
#include <geos/util/CoordinateArrayFilter.h>

#include "geos/util.h"

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
Expand Down Expand Up @@ -178,7 +180,9 @@ class GEOS_DLL ConvexHull {
ConvexHull(const geom::Geometry* newGeometry)
: inputGeom(newGeometry)
, geomFactory(newGeometry->getFactory())
{};
{
util::ensureNoCurvedComponents(inputGeom);
};

~ConvexHull() {};

Expand Down
10 changes: 1 addition & 9 deletions include/geos/algorithm/hull/ConcaveHull.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,7 @@ class GEOS_DLL ConcaveHull {

public:

ConcaveHull(const Geometry* geom)
: inputGeometry(geom)
, maxEdgeLengthRatio(-1.0)
, alpha(-1)
, isHolesAllowed(false)
, criteriaType(PARAM_EDGE_LENGTH)
, maxSizeInHull(0.0)
, geomFactory(geom->getFactory())
{};
ConcaveHull(const Geometry* geom);

/**
* Computes the approximate edge length of
Expand Down
85 changes: 85 additions & 0 deletions include/geos/geom/CircularString.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2024 ISciences, LLC
*
* 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.
*
**********************************************************************/

#pragma once

#include <geos/geom/SimpleCurve.h>
#include <geos/util/UnsupportedOperationException.h>

namespace geos {
namespace geom {

class GEOS_DLL CircularString : public SimpleCurve {

public:
using SimpleCurve::SimpleCurve;

friend class GeometryFactory;

~CircularString() override;

std::unique_ptr<CircularString> clone() const;

std::string getGeometryType() const override;

GeometryTypeId getGeometryTypeId() const override;

double getLength() const override
{
throw util::UnsupportedOperationException("Cannot calculate length of CircularString");
}

bool hasCurvedComponents() const override
{
return true;
}

std::unique_ptr<CircularString> reverse() const
{
return std::unique_ptr<CircularString>(reverseImpl());
}

protected:

/// \brief
/// Constructs a CircularString taking ownership the
/// given CoordinateSequence.
CircularString(std::unique_ptr<CoordinateSequence>&& pts,
const GeometryFactory& newFactory);

CircularString* cloneImpl() const override
{
return new CircularString(*this);
}

void geometryChangedAction() override
{
envelope = computeEnvelopeInternal(false);
}

int
getSortIndex() const override
{
return SORTINDEX_LINESTRING;
};

CircularString* reverseImpl() const override;

void validateConstruction();

};


}
}
Loading
Loading