Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

package org.locationtech.jts.shape.random;

import java.util.Random;

import org.locationtech.jts.algorithm.locate.IndexedPointInAreaLocator;
import org.locationtech.jts.algorithm.locate.PointOnGeometryLocator;
import org.locationtech.jts.geom.Coordinate;
Expand All @@ -34,6 +36,7 @@ public class RandomPointsBuilder
{
protected Geometry maskPoly = null;
private PointOnGeometryLocator extentLocator;
private Random random = new Random();

/**
* Create a shape factory which will create shapes using the default
Expand All @@ -55,6 +58,18 @@ public RandomPointsBuilder(GeometryFactory geomFact)
super(geomFact);
}

/**
* Sets the random number generator used to generate point coordinates.
* This enables reproducible results by providing a {@link Random}
* with a fixed seed.
*
* @param random the random number generator to use
*/
public void setRandom(Random random)
{
this.random = random;
}

/**
* Sets a polygonal mask.
*
Expand Down Expand Up @@ -99,8 +114,8 @@ protected Coordinate createCoord(double x, double y)

protected Coordinate createRandomCoord(Envelope env)
{
double x = env.getMinX() + env.getWidth() * Math.random();
double y = env.getMinY() + env.getHeight() * Math.random();
double x = env.getMinX() + env.getWidth() * random.nextDouble();
double y = env.getMinY() + env.getHeight() * random.nextDouble();
return createCoord(x, y);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

package org.locationtech.jts.shape.random;

import java.util.Random;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
Expand All @@ -32,6 +34,7 @@ public class RandomPointsInGridBuilder
{
private boolean isConstrainedToCircle = false;
private double gutterFraction = 0;
private Random random = new Random();

/**
* Create a builder which will create shapes using the default
Expand All @@ -53,6 +56,18 @@ public RandomPointsInGridBuilder(GeometryFactory geomFact)
super(geomFact);
}

/**
* Sets the random number generator used to generate point coordinates.
* This enables reproducible results by providing a {@link Random}
* with a fixed seed.
*
* @param random the random number generator to use
*/
public void setRandom(Random random)
{
this.random = random;
}

/**
* Sets whether generated points are constrained to lie
* within a circle contained within each grid cell.
Expand Down Expand Up @@ -126,18 +141,18 @@ private Coordinate randomPointInCell(double orgX, double orgY, double xLen, doub

private Coordinate randomPointInGridCell(double orgX, double orgY, double xLen, double yLen)
{
double x = orgX + xLen * Math.random();
double y = orgY + yLen * Math.random();
double x = orgX + xLen * random.nextDouble();
double y = orgY + yLen * random.nextDouble();
return createCoord(x, y);
}

private static Coordinate randomPointInCircle(double orgX, double orgY, double width, double height)
private Coordinate randomPointInCircle(double orgX, double orgY, double width, double height)
{
double centreX = orgX + width/2;
double centreY = orgY + height/2;
double rndAng = 2 * Math.PI * Math.random();
double rndRadius = Math.random();

double rndAng = 2 * Math.PI * random.nextDouble();
double rndRadius = random.nextDouble();
// use square root of radius, since area is proportional to square of radius
double rndRadius2 = Math.sqrt(rndRadius);
double rndX = width/2 * rndRadius2 * Math.cos(rndAng);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2026 woogi-kim.
*
* 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.shape.random;

import java.util.Random;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;

import junit.textui.TestRunner;
import test.jts.GeometryTestCase;

/**
* Tests {@link RandomPointsBuilder}.
*
* @author woogi-kim
*
*/
public class RandomPointsBuilderTest
extends GeometryTestCase {
public static void main(String args[]) {
TestRunner.run(RandomPointsBuilderTest.class);
}

public RandomPointsBuilderTest(String name)
{
super(name);
}

public void testDefault() {
RandomPointsBuilder builder = new RandomPointsBuilder(getGeometryFactory());
builder.setExtent(new Envelope(0, 10, 0, 10));
builder.setNumPoints(10);
Geometry result = builder.getGeometry();
assertEquals(10, result.getNumGeometries());
}

public void testReproducibleWithSameSeed() {
Geometry result1 = createPoints(42, 100);
Geometry result2 = createPoints(42, 100);
assertTrue(result1.equalsExact(result2));
}

public void testDifferentSeedProducesDifferentResult() {
Geometry result1 = createPoints(42, 100);
Geometry result2 = createPoints(99, 100);
assertFalse(result1.equalsExact(result2));
}

public void testReproducibleWithPolygonalExtent() {
Geometry mask = read("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
Geometry result1 = createPointsInPolygon(mask, 42, 50);
Geometry result2 = createPointsInPolygon(mask, 42, 50);
assertTrue(result1.equalsExact(result2));
}

private Geometry createPoints(long seed, int numPts) {
RandomPointsBuilder builder = new RandomPointsBuilder(getGeometryFactory());
builder.setExtent(new Envelope(0, 10, 0, 10));
builder.setNumPoints(numPts);
builder.setRandom(new Random(seed));
return builder.getGeometry();
}

private Geometry createPointsInPolygon(Geometry mask, long seed, int numPts) {
RandomPointsBuilder builder = new RandomPointsBuilder(getGeometryFactory());
builder.setExtent(mask);
builder.setNumPoints(numPts);
builder.setRandom(new Random(seed));
return builder.getGeometry();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2026 woogi-kim.
*
* 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.shape.random;

import java.util.Random;

import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;

import junit.textui.TestRunner;
import test.jts.GeometryTestCase;

/**
* Tests {@link RandomPointsInGridBuilder}.
*
* @author woogi-kim
*
*/
public class RandomPointsInGridBuilderTest
extends GeometryTestCase {
public static void main(String args[]) {
TestRunner.run(RandomPointsInGridBuilderTest.class);
}

public RandomPointsInGridBuilderTest(String name)
{
super(name);
}

public void testDefault() {
RandomPointsInGridBuilder builder = new RandomPointsInGridBuilder(getGeometryFactory());
builder.setExtent(new Envelope(0, 10, 0, 10));
builder.setNumPoints(9);
Geometry result = builder.getGeometry();
assertEquals(9, result.getNumGeometries());
}

public void testReproducibleWithSameSeed() {
Geometry result1 = createGridPoints(42, 25);
Geometry result2 = createGridPoints(42, 25);
assertTrue(result1.equalsExact(result2));
}

public void testDifferentSeedProducesDifferentResult() {
Geometry result1 = createGridPoints(42, 25);
Geometry result2 = createGridPoints(99, 25);
assertFalse(result1.equalsExact(result2));
}

public void testReproducibleWithConstrainedToCircle() {
Geometry result1 = createGridPointsInCircle(42, 25);
Geometry result2 = createGridPointsInCircle(42, 25);
assertTrue(result1.equalsExact(result2));
}

private Geometry createGridPoints(long seed, int numPts) {
RandomPointsInGridBuilder builder = new RandomPointsInGridBuilder(getGeometryFactory());
builder.setExtent(new Envelope(0, 10, 0, 10));
builder.setNumPoints(numPts);
builder.setRandom(new Random(seed));
return builder.getGeometry();
}

private Geometry createGridPointsInCircle(long seed, int numPts) {
RandomPointsInGridBuilder builder = new RandomPointsInGridBuilder(getGeometryFactory());
builder.setExtent(new Envelope(0, 10, 0, 10));
builder.setNumPoints(numPts);
builder.setConstrainedToCircle(true);
builder.setRandom(new Random(seed));
return builder.getGeometry();
}
}