Skip to content

Commit

Permalink
GeometryCollection: Cache properties to avoid O(n) lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
dbaston committed Jan 4, 2025
1 parent 6b413f1 commit d3743ed
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 32 deletions.
12 changes: 12 additions & 0 deletions include/geos/geom/GeometryCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@ class GEOS_DLL GeometryCollection : public Geometry {

protected:

struct CollectionFlags {
bool flagsCalculated;
bool hasPoints;
bool hasLines;
bool hasPolygons;
bool hasM;
bool hasZ;
bool hasCurves;
};

GeometryCollection(const GeometryCollection& gc);
GeometryCollection& operator=(const GeometryCollection& gc);

Expand Down Expand Up @@ -236,6 +246,7 @@ class GEOS_DLL GeometryCollection : public Geometry {
};

std::vector<std::unique_ptr<Geometry>> geometries;
mutable CollectionFlags flags;
mutable Envelope envelope;

Envelope computeEnvelopeInternal() const;
Expand All @@ -248,6 +259,7 @@ class GEOS_DLL GeometryCollection : public Geometry {

bool hasCurvedComponents() const override;

void setFlags() const;

};

Expand Down
95 changes: 63 additions & 32 deletions src/geom/GeometryCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ GeometryCollection::GeometryCollection(const GeometryCollection& gc)
:
Geometry(gc),
geometries(gc.geometries.size()),
flags{}, // set all flags to zero
envelope(gc.envelope)
{
for(std::size_t i = 0; i < geometries.size(); ++i) {
Expand All @@ -51,6 +52,7 @@ GeometryCollection::operator=(const GeometryCollection& gc)
{
geometries.resize(gc.geometries.size());
envelope = gc.envelope;
flags = gc.flags;

for (std::size_t i = 0; i < geometries.size(); i++) {
geometries[i] = gc.geometries[i]->clone();
Expand All @@ -62,7 +64,9 @@ GeometryCollection::operator=(const GeometryCollection& gc)
GeometryCollection::GeometryCollection(std::vector<std::unique_ptr<Geometry>> && newGeoms, const GeometryFactory& factory) :
Geometry(&factory),
geometries(std::move(newGeoms)),
envelope(computeEnvelopeInternal()) {
flags{}, // set all flags to zero
envelope(computeEnvelopeInternal())
{

if (hasNullElements(&geometries)) {
throw util::IllegalArgumentException("geometries must not contain null elements\n");
Expand Down Expand Up @@ -114,31 +118,69 @@ GeometryCollection::isEmpty() const
return true;
}

void
GeometryCollection::setFlags() const {
if (flags.flagsCalculated) {
return;
}

for (const auto& geom : geometries) {
flags.hasPoints |= geom->hasDimension(Dimension::P);
flags.hasLines |= geom->hasDimension(Dimension::L);
flags.hasPolygons |= geom->hasDimension(Dimension::A);
flags.hasM |= geom->hasM();
flags.hasZ |= geom->hasZ();
flags.hasCurves |= geom->hasCurvedComponents();
}

flags.flagsCalculated = true;
}

Dimension::DimensionType
GeometryCollection::getDimension() const
{
Dimension::DimensionType dimension = Dimension::False;
for(const auto& g : geometries) {
dimension = std::max(dimension, g->getDimension());
setFlags();

if (flags.hasPolygons) {
return Dimension::A;
}
return dimension;
if (flags.hasLines) {
return Dimension::L;
}
if (flags.hasPoints) {
return Dimension::P;
}
return Dimension::False;
}

bool
GeometryCollection::isDimensionStrict(Dimension::DimensionType d) const {
return std::all_of(geometries.begin(), geometries.end(),
[&d](const std::unique_ptr<Geometry> & g) {
return g->getDimension() == d;
});
setFlags();

if (isEmpty()) {
return true;
}

switch(d) {
case Dimension::A: return flags.hasPolygons && !flags.hasLines && !flags.hasPoints;
case Dimension::L: return !flags.hasPolygons && flags.hasLines && !flags.hasPoints;
case Dimension::P: return !flags.hasPolygons && !flags.hasLines && flags.hasPoints;
default:
return false;
}
}

bool
GeometryCollection::hasDimension(Dimension::DimensionType d) const {
return std::any_of(geometries.begin(),
geometries.end(),
[&d](const std::unique_ptr<Geometry>& g) {
return g->hasDimension(d);
});
setFlags();

switch (d) {
case Dimension:: A: return flags.hasPolygons;
case Dimension:: L: return flags.hasLines;
case Dimension:: P: return flags.hasPoints;
default:
return false;
}
}

int
Expand All @@ -165,23 +207,15 @@ GeometryCollection::getCoordinateDimension() const
bool
GeometryCollection::hasM() const
{
for (const auto& g : geometries) {
if (g->hasM()) {
return true;
}
}
return false;
setFlags();
return flags.hasM;
}

bool
GeometryCollection::hasZ() const
{
for (const auto& g : geometries) {
if (g->hasZ()) {
return true;
}
}
return false;
setFlags();
return flags.hasZ;
}

size_t
Expand All @@ -201,6 +235,7 @@ GeometryCollection::releaseGeometries()
{
auto ret = std::move(geometries);
geometryChanged();
flags.flagsCalculated = false;
return ret;
}

Expand Down Expand Up @@ -334,12 +369,8 @@ GeometryCollection::compareToSameClass(const Geometry* g) const
}

bool GeometryCollection::hasCurvedComponents() const {
for (const auto& g : geometries) {
if (g->hasCurvedComponents()) {
return true;
}
}
return false;
setFlags();
return flags.hasCurves;
}

const CoordinateXY*
Expand Down

0 comments on commit d3743ed

Please sign in to comment.