Skip to content

Commit

Permalink
Add GeometryCollection dimension cache (#1103)
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts authored Dec 19, 2024
1 parent 647ac70 commit 47b52bd
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class GeometryCollection extends Geometry {
* Internal representation of this <code>GeometryCollection</code>.
*/
protected Geometry[] geometries;
private GeometryCollectionDimension geomCollDim;

/** @deprecated Use GeometryFactory instead */
public GeometryCollection(Geometry[] geometries, PrecisionModel precisionModel, int SRID) {
Expand Down Expand Up @@ -97,19 +98,26 @@ public boolean isEmpty() {
}

public int getDimension() {
/*
int dimension = Dimension.FALSE;
for (int i = 0; i < geometries.length; i++) {
dimension = Math.max(dimension, geometries[i].getDimension());
}
return dimension;
//*/
//*
if (geomCollDim == null) {
geomCollDim = new GeometryCollectionDimension(this);
}
return geomCollDim.getDimension();
//*/
}

public boolean hasDimension(int dim) {
for (int i = 0; i < geometries.length; i++) {
if (geometries[i].hasDimension(dim))
return true;
if (geomCollDim == null) {
geomCollDim = new GeometryCollectionDimension(this);
}
return false;
return geomCollDim.hasDimension(dim);
}

public int getBoundaryDimension() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Martin Davis.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.geom;

import java.util.Iterator;

/**
* Computes and caches dimension information for {@link GeometryCollection}s.
* Optimizes performance of dimension reporting for heterogeneous collections.
*
* @author mdavis
*/
class GeometryCollectionDimension {
private int dimension = Dimension.FALSE;
private boolean hasP = false;
private boolean hasL = false;
private boolean hasA = false;

public GeometryCollectionDimension(GeometryCollection coll) {
init(coll);
}

private void init(GeometryCollection coll) {
Iterator geomi = new GeometryCollectionIterator(coll);
while (geomi.hasNext()) {
Geometry elem = (Geometry) geomi.next();
//-- empty elements still determine dimension, to match previous semantics
if (elem instanceof Point) {
hasP = true;
if (dimension < Dimension.P) dimension = Dimension.P;
}
if (elem instanceof LineString) {
hasL = true;
if (dimension < Dimension.L) dimension = Dimension.L;
}
if (elem instanceof Polygon) {
hasA = true;
if (dimension < Dimension.A) dimension = Dimension.A;
}
}
}

public boolean hasDimension(int dim) {
if (dim == Dimension.A && hasA) return true;
if (dim == Dimension.L && hasL) return true;
if (dim == Dimension.P && hasP) return true;
return false;
}

public int getDimension() {
return dimension;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2024 Martin Davis.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package test.jts.perf.coverage;

import java.util.ArrayList;
import java.util.List;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.operation.overlayng.CoverageUnion;

import test.jts.perf.PerformanceTestCase;
import test.jts.perf.PerformanceTestRunner;

/**
* Shows how linear performance of {@link GeometryCollection#getDimension()}
* affects performance.
* (See https://github.com/locationtech/jts/issues/1100)
*
* @author mdavis
*
*/
public class CoverageUnionPerfTest extends PerformanceTestCase
{
public static void main(String[] args) {
PerformanceTestRunner.run(CoverageUnionPerfTest.class);
}

private Geometry grid;

public CoverageUnionPerfTest(String name) {
super(name);
setRunSize(new int[] { 10_000, 20_000, 40_000, 100_000, 200_000, 400_000 });
}

public void startRun(int nCells)
{
grid = createGrid(100.0, nCells, new GeometryFactory());
System.out.println("\n------- Running with cells = " + nCells);
}

private static Geometry createGrid(double size, int nCells, GeometryFactory geomFact) {

int nCellsOnSideY = (int) Math.sqrt(nCells);
int nCellsOnSideX = nCells / nCellsOnSideY;

double cellSizeX = size / nCellsOnSideX;
double cellSizeY = size / nCellsOnSideY;

List<Geometry> geoms = new ArrayList<Geometry>();

for (int i = 0; i < nCellsOnSideX; i++) {
for (int j = 0; j < nCellsOnSideY; j++) {
double x = 0 + i * cellSizeX;
double y = 0 + j * cellSizeY;
double x2 = 0 + (i + 1) * cellSizeX;
double y2 = 0 + (j + 1) * cellSizeY;

Envelope cellEnv = new Envelope(x, x2, y, y2);
geoms.add(geomFact.toGeometry(cellEnv));
}
}
return geomFact.createGeometryCollection(
GeometryFactory.toGeometryArray(geoms));
}

public void runUnion() {
CoverageUnion.union(grid);
}
}

0 comments on commit 47b52bd

Please sign in to comment.