-
Notifications
You must be signed in to change notification settings - Fork 475
Add setRandom(Random) to RandomPointsBuilder #1214
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -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 | ||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
Comment on lines
+68
to
+72
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the setter Martin asked for on #1191.
Worth one javadoc sentence that a second |
||
| /** | ||
| * Sets a polygonal mask. | ||
| * | ||
|
|
@@ -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); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -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 | ||
|
|
@@ -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. | ||
|
|
@@ -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(); | ||
|
Comment on lines
+149
to
+155
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Making this an instance method is the right cut so the circle path uses the same generator. Do not lift Pre-existing, leave it: this still returns |
||
| // 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); | ||
|
|
||
| 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)); | ||
| } | ||
|
Comment on lines
+47
to
+57
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same-seed / different-seed plus the polygonal-mask case below is enough to lock #1191. Unseeded default is still non-reproducible. The stream is no longer the process-global |
||
|
|
||
| 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)); | ||
| } | ||
|
Comment on lines
+59
to
+63
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good that constrained-to-circle is pinned. That is the path that used to call |
||
|
|
||
| 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(); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both builders needed this (micycle1 had already forked the grid one on #1191). License headers and DCO are present. Ship it.