HausdorffDistancePerfTest.java
/*
* Copyright (c) 2026 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.operation.distance;
import java.util.ArrayList;
import java.util.List;
import org.locationtech.jts.algorithm.distance.DirectedHausdorffDistance;
import org.locationtech.jts.algorithm.distance.DiscreteHausdorffDistance;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.util.SineStarFactory;
import org.locationtech.jts.util.Debug;
import test.jts.perf.PerformanceTestCase;
import test.jts.perf.PerformanceTestRunner;
public class HausdorffDistancePerfTest extends PerformanceTestCase {
static final int MAX_ITER = 10000;
static final boolean VERBOSE = false;
static GeometryFactory geomFact = new GeometryFactory();
public static void main(String[] args) {
PerformanceTestRunner.run(HausdorffDistancePerfTest.class);
}
private Geometry b;
private List<Geometry> grid;
private int distance;
private DirectedHausdorffDistance dhd;
public HausdorffDistancePerfTest(String name) {
super(name);
setRunSize(new int[] { 100, 10_000, 40_000, 160_000, 1_000_000 });
setRunIterations(1);
}
public void startRun(int npts)
{
int nCircles = (int) Math.sqrt(npts);
System.out.println("\n------- Running with # circles = " + nCircles * nCircles);
b = createSineStar(1000, 300, 50);
dhd = new DirectedHausdorffDistance(b);
grid = createCircleGrid(2000, nCircles);
distance = 2000 / nCircles;
}
public void runFullyWithin() {
Debug.println(b);
int iter = 0;
for (Geometry g : grid) {
iter++;
Debug.println(iter + " ----------------");
Debug.println(g);
checkHausdorff(g, b);
//boolean isWithin = DirectedHausdorffDistance.isFullyWithinDistance(g, b, 4 * distance, 0.1);
boolean isWithin = dhd.isFullyWithinDistance(g, 4 * distance);
//if (iter > 10) break;
}
}
private void checkHausdorff(Geometry g, Geometry b) {
double distDHD = DiscreteHausdorffDistance.distance(g, b, 0.01);
double distHD = DirectedHausdorffDistance.hausdorffDistance(g, b);
//-- performance testing only
//double distDHD = distHD;
double err = Math.abs(distDHD - distHD) / (distDHD + distHD);
Debug.println(distDHD + " " + distHD + " err = " + err);
if (err > .01) {
System.out.println("<<<<<<<<<<< ERROR!");
}
checkFullyWithinDistance(g, b);
}
private void checkFullyWithinDistance(Geometry g, Geometry b) {
double distDHD = DirectedHausdorffDistance.distance(g, b, 0.01);
double tol = distDHD / 1000;
boolean isWithin = DirectedHausdorffDistance.isFullyWithinDistance(g, b, 1.05 * distDHD, tol);
boolean isBeyond = ! DirectedHausdorffDistance.isFullyWithinDistance(g, b, 0.95 * distDHD, tol);
if (! (isWithin && isBeyond)) {
System.out.format("ioWithin = %b isBeyond = %b\n", isWithin, isBeyond);
System.out.println("<<<<<<<<<<< ERROR!");
DirectedHausdorffDistance.isFullyWithinDistance(g, b, 0.75 * distDHD,tol);
}
}
private List<Geometry> createCircleGrid(double size, int nSide) {
List<Geometry> geoms = new ArrayList<Geometry>();
double inc = size / nSide;
for (int i = 0; i < nSide; i++) {
for (int j = 0; j < nSide; j++) {
Coordinate p = new Coordinate(i * inc, j * inc);
Point pt = geomFact.createPoint(p);
Geometry buf = pt.buffer(inc);
geoms.add(buf);
}
}
return geoms;
}
private Geometry createSineStar(double loc, double size, int nPts)
{
SineStarFactory gsf = new SineStarFactory(geomFact);
gsf.setCentre(new Coordinate(loc, loc));
gsf.setSize(size);
gsf.setNumPoints(nPts);
Geometry g = gsf.createSineStar().getBoundary();
return g;
}
}