List of usage examples for org.apache.commons.math3.geometry.partitioning RegionFactory RegionFactory
public RegionFactory()
From source file:org.orekit.models.earth.tessellation.EllipsoidTessellator.java
/** Tessellate a zone of interest into tiles. * <p>/*from w w w . j a va 2 s .c om*/ * The created tiles will completely cover the zone of interest. * </p> * <p> * The distance between a vertex at a tile corner and the vertex at the same corner * in the next vertex are computed by subtracting the overlap width (resp. overlap length) * from the full width (resp. full length). If for example the full width is specified to * be 55 km and the overlap in width is specified to be +5 km, successive tiles would span * as follows: * </p> * <ul> * <li>tile 1 covering from 0 km to 55 km</li> * <li>tile 2 covering from 50 km to 105 km</li> * <li>tile 3 covering from 100 km to 155 km</li> * <li>...</li> * </ul> * <p> * In order to achieve the same 50 km step but using a 5 km gap instead of an overlap, one would * need to specify the full width to be 45 km and the overlap to be -5 km. With these settings, * successive tiles would span as follows: * </p> * <ul> * <li>tile 1 covering from 0 km to 45 km</li> * <li>tile 2 covering from 50 km to 95 km</li> * <li>tile 3 covering from 100 km to 155 km</li> * <li>...</li> * </ul> * @param zone zone of interest to tessellate * @param fullWidth full tiles width as a distance on surface, including overlap (in meters) * @param fullLength full tiles length as a distance on surface, including overlap (in meters) * @param widthOverlap overlap between adjacent tiles (in meters), if negative the tiles * will have a gap between each other instead of an overlap * @param lengthOverlap overlap between adjacent tiles (in meters), if negative the tiles * will have a gap between each other instead of an overlap * @param truncateLastWidth if true, the first tiles strip will be started as close as * possible to the zone of interest, and the last tiles strip will have its width reduced * to also remain close to the zone of interest; if false all tiles strip will have the * same {@code fullWidth} and they will be balanced around zone of interest * @param truncateLastLength if true, the first tile in each strip will be started as close as * possible to the zone of interest, and the last tile in each strip will have its length reduced * to also remain close to the zone of interest; if false all tiles in each strip will have the * same {@code fullLength} and they will be balanced around zone of interest * @return a list of lists of tiles covering the zone of interest, * each sub-list corresponding to a part not connected to the other * parts (for example for islands) * @exception OrekitException if the zone cannot be tessellated */ public List<List<Tile>> tessellate(final SphericalPolygonsSet zone, final double fullWidth, final double fullLength, final double widthOverlap, final double lengthOverlap, final boolean truncateLastWidth, final boolean truncateLastLength) throws OrekitException { final double splitWidth = (fullWidth - widthOverlap) / quantization; final double splitLength = (fullLength - lengthOverlap) / quantization; final Map<Mesh, List<Tile>> map = new IdentityHashMap<Mesh, List<Tile>>(); final RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>(); SphericalPolygonsSet remaining = (SphericalPolygonsSet) zone.copySelf(); S2Point inside = getInsidePoint(remaining); while (inside != null) { // find a mesh covering at least one connected part of the zone final List<Mesh.Node> mergingSeeds = new ArrayList<Mesh.Node>(); Mesh mesh = new Mesh(ellipsoid, zone, aiming, splitLength, splitWidth, inside); mergingSeeds.add(mesh.getNode(0, 0)); List<Tile> tiles = null; while (!mergingSeeds.isEmpty()) { // expand the mesh around the seed neighborExpandMesh(mesh, mergingSeeds, zone); // extract the tiles from the mesh // this further expands the mesh so tiles dimensions are multiples of quantization, // hence it must be performed here before checking meshes independence tiles = extractTiles(mesh, zone, lengthOverlap, widthOverlap, truncateLastWidth, truncateLastLength); // check the mesh is independent from existing meshes mergingSeeds.clear(); for (final Map.Entry<Mesh, List<Tile>> entry : map.entrySet()) { if (!factory.intersection(mesh.getCoverage(), entry.getKey().getCoverage()).isEmpty()) { // the meshes are not independent, they intersect each other! // merge the two meshes together mesh = mergeMeshes(mesh, entry.getKey(), mergingSeeds); map.remove(entry.getKey()); break; } } } // remove the part of the zone covered by the mesh remaining = (SphericalPolygonsSet) factory.difference(remaining, mesh.getCoverage()); inside = getInsidePoint(remaining); map.put(mesh, tiles); } // concatenate the lists from the independent meshes final List<List<Tile>> tilesLists = new ArrayList<List<Tile>>(map.size()); for (final Map.Entry<Mesh, List<Tile>> entry : map.entrySet()) { tilesLists.add(entry.getValue()); } return tilesLists; }
From source file:org.orekit.models.earth.tessellation.EllipsoidTessellator.java
/** Sample a zone of interest into a grid sample of {@link GeodeticPoint geodetic points}. * <p>//from w ww. ja v a 2s . c o m * The created points will be entirely within the zone of interest. * </p> * @param zone zone of interest to sample * @param width grid sample cells width as a distance on surface (in meters) * @param length grid sample cells length as a distance on surface (in meters) * @return a list of lists of points sampling the zone of interest, * each sub-list corresponding to a part not connected to the other * parts (for example for islands) * @exception OrekitException if the zone cannot be sampled */ public List<List<GeodeticPoint>> sample(final SphericalPolygonsSet zone, final double width, final double length) throws OrekitException { final double splitWidth = width / quantization; final double splitLength = length / quantization; final Map<Mesh, List<GeodeticPoint>> map = new IdentityHashMap<Mesh, List<GeodeticPoint>>(); final RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>(); SphericalPolygonsSet remaining = (SphericalPolygonsSet) zone.copySelf(); S2Point inside = getInsidePoint(remaining); while (inside != null) { // find a mesh covering at least one connected part of the zone final List<Mesh.Node> mergingSeeds = new ArrayList<Mesh.Node>(); Mesh mesh = new Mesh(ellipsoid, zone, aiming, splitLength, splitWidth, inside); mergingSeeds.add(mesh.getNode(0, 0)); List<GeodeticPoint> sample = null; while (!mergingSeeds.isEmpty()) { // expand the mesh around the seed neighborExpandMesh(mesh, mergingSeeds, zone); // extract the sample from the mesh // this further expands the mesh so sample cells dimensions are multiples of quantization, // hence it must be performed here before checking meshes independence sample = extractSample(mesh, zone); // check the mesh is independent from existing meshes mergingSeeds.clear(); for (final Map.Entry<Mesh, List<GeodeticPoint>> entry : map.entrySet()) { if (!factory.intersection(mesh.getCoverage(), entry.getKey().getCoverage()).isEmpty()) { // the meshes are not independent, they intersect each other! // merge the two meshes together mesh = mergeMeshes(mesh, entry.getKey(), mergingSeeds); map.remove(entry.getKey()); break; } } } // remove the part of the zone covered by the mesh remaining = (SphericalPolygonsSet) factory.difference(remaining, mesh.getCoverage()); inside = getInsidePoint(remaining); map.put(mesh, sample); } // concatenate the lists from the independent meshes final List<List<GeodeticPoint>> sampleLists = new ArrayList<List<GeodeticPoint>>(map.size()); for (final Map.Entry<Mesh, List<GeodeticPoint>> entry : map.entrySet()) { sampleLists.add(entry.getValue()); } return sampleLists; }
From source file:org.orekit.models.earth.tessellation.EllipsoidTessellator.java
/** Extract tiles from a mesh. * @param mesh mesh from which tiles should be extracted * @param zone zone covered by the mesh/*from w w w. j ava2 s .com*/ * @param lengthOverlap overlap between adjacent tiles * @param widthOverlap overlap between adjacent tiles * @param truncateLastWidth true if we can reduce last tile width * @param truncateLastLength true if we can reduce last tile length * @return extracted tiles * @exception OrekitException if tile direction cannot be computed */ private List<Tile> extractTiles(final Mesh mesh, final SphericalPolygonsSet zone, final double lengthOverlap, final double widthOverlap, final boolean truncateLastWidth, final boolean truncateLastLength) throws OrekitException { final List<Tile> tiles = new ArrayList<Tile>(); final List<RangePair> rangePairs = new ArrayList<RangePair>(); final int minAcross = mesh.getMinAcrossIndex(); final int maxAcross = mesh.getMaxAcrossIndex(); for (Range acrossPair : nodesIndices(minAcross, maxAcross, truncateLastWidth)) { int minAlong = mesh.getMaxAlongIndex() + 1; int maxAlong = mesh.getMinAlongIndex() - 1; for (int c = acrossPair.lower; c <= acrossPair.upper; ++c) { minAlong = FastMath.min(minAlong, mesh.getMinAlongIndex(c)); maxAlong = FastMath.max(maxAlong, mesh.getMaxAlongIndex(c)); } for (Range alongPair : nodesIndices(minAlong, maxAlong, truncateLastLength)) { // get the base vertex nodes final Mesh.Node node0 = mesh.addNode(alongPair.lower, acrossPair.lower); final Mesh.Node node1 = mesh.addNode(alongPair.upper, acrossPair.lower); final Mesh.Node node2 = mesh.addNode(alongPair.upper, acrossPair.upper); final Mesh.Node node3 = mesh.addNode(alongPair.lower, acrossPair.upper); // apply tile overlap final S2Point s2p0 = node0.move(new Vector3D(-0.5 * lengthOverlap, node0.getAlong(), -0.5 * widthOverlap, node0.getAcross())); final S2Point s2p1 = node1.move(new Vector3D(+0.5 * lengthOverlap, node1.getAlong(), -0.5 * widthOverlap, node1.getAcross())); final S2Point s2p2 = node2.move(new Vector3D(+0.5 * lengthOverlap, node2.getAlong(), +0.5 * widthOverlap, node2.getAcross())); final S2Point s2p3 = node3.move(new Vector3D(-0.5 * lengthOverlap, node2.getAlong(), +0.5 * widthOverlap, node2.getAcross())); // create a quadrilateral region corresponding to the candidate tile final SphericalPolygonsSet quadrilateral = new SphericalPolygonsSet(zone.getTolerance(), s2p0, s2p1, s2p2, s2p3); if (!new RegionFactory<Sphere2D>().intersection(zone.copySelf(), quadrilateral).isEmpty()) { // the tile does cover part of the zone, it contributes to the tessellation tiles.add(new Tile(toGeodetic(s2p0), toGeodetic(s2p1), toGeodetic(s2p2), toGeodetic(s2p3))); rangePairs.add(new RangePair(acrossPair, alongPair)); } } } // ensure the taxicab boundary follows the built tile sides // this is done outside of the previous loop because in order // to avoid one tile changing the min/max indices of the // neighboring tile as they share some nodes that will be enabled here for (final RangePair rangePair : rangePairs) { for (int c = rangePair.across.lower; c < rangePair.across.upper; ++c) { mesh.addNode(rangePair.along.lower, c + 1).setEnabled(); mesh.addNode(rangePair.along.upper, c).setEnabled(); } for (int l = rangePair.along.lower; l < rangePair.along.upper; ++l) { mesh.addNode(l, rangePair.across.lower).setEnabled(); mesh.addNode(l + 1, rangePair.across.upper).setEnabled(); } } return tiles; }
From source file:org.orekit.models.earth.tessellation.EllipsoidTessellatorTest.java
private SphericalPolygonsSet buildFrance() { final SphericalPolygonsSet continental = buildSimpleZone(1.0e-10, new double[][] { { 51.14850, 2.51357 }, { 50.94660, 1.63900 }, { 50.12717, 1.33876 }, { 49.34737, -0.98946 }, { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 }, { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 }, { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338, 1.82679 }, { 42.47301, 2.98599 }, { 43.07520, 3.10041 }, { 43.39965, 4.55696 }, { 43.12889, 6.52924 }, { 43.69384, 7.43518 }, { 44.12790, 7.54959 }, { 45.02851, 6.74995 }, { 45.33309, 7.09665 }, { 46.42967, 6.50009 }, { 46.27298, 6.02260 }, { 46.72577, 6.03738 }, { 47.62058, 7.46675 }, { 49.01778, 8.09927 }, { 49.20195, 6.65822 }, { 49.44266, 5.89775 }, { 49.98537, 4.79922 } }); final SphericalPolygonsSet corsica = EllipsoidTessellator.buildSimpleZone(1.0e-10, new GeodeticPoint(FastMath.toRadians(42.15249), FastMath.toRadians(9.56001), 0.0), new GeodeticPoint(FastMath.toRadians(43.00998), FastMath.toRadians(9.39000), 0.0), new GeodeticPoint(FastMath.toRadians(42.62812), FastMath.toRadians(8.74600), 0.0), new GeodeticPoint(FastMath.toRadians(42.25651), FastMath.toRadians(8.54421), 0.0), new GeodeticPoint(FastMath.toRadians(41.58361), FastMath.toRadians(8.77572), 0.0), new GeodeticPoint(FastMath.toRadians(41.38000), FastMath.toRadians(9.22975), 0.0)); return (SphericalPolygonsSet) new RegionFactory<Sphere2D>().union(continental, corsica); }
From source file:org.orekit.propagation.events.GeographicZoneDetectorTest.java
@Test public void testSerialization() throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, OrekitException { final double r = Constants.WGS84_EARTH_EQUATORIAL_RADIUS; final BodyShape earth = new OneAxisEllipsoid(r, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, true)); GeographicZoneDetector d = new GeographicZoneDetector(20.0, 1.e-3, earth, buildFrance(), FastMath.toRadians(0.5)).withMargin(FastMath.toRadians(0.75)) .withHandler(new ContinueOnEvent<GeographicZoneDetector>()); Assert.assertEquals(r, ((OneAxisEllipsoid) d.getBody()).getEquatorialRadius(), 1.0e-12); Assert.assertEquals(0.75, FastMath.toDegrees(d.getMargin()), 1.0e-12); Assert.assertEquals(5.6807e11, d.getZone().getSize() * r * r, 1.0e9); Assert.assertEquals(4.0289e6, d.getZone().getBoundarySize() * r, 1.0e3); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(d);// www . j ava2 s. c o m Assert.assertTrue(bos.size() > 1950); Assert.assertTrue(bos.size() < 2050); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); GeographicZoneDetector deserialized = (GeographicZoneDetector) ois.readObject(); Assert.assertEquals(d.getZone().getSize(), deserialized.getZone().getSize(), 1.0e-3); Assert.assertEquals(d.getZone().getBoundarySize(), deserialized.getZone().getBoundarySize(), 1.0e-3); Assert.assertEquals(d.getZone().getTolerance(), deserialized.getZone().getTolerance(), 1.0e-15); Assert.assertEquals(d.getMaxCheckInterval(), deserialized.getMaxCheckInterval(), 1.0e-15); Assert.assertEquals(d.getThreshold(), deserialized.getThreshold(), 1.0e-15); Assert.assertEquals(d.getMaxIterationCount(), deserialized.getMaxIterationCount()); Assert.assertTrue(new RegionFactory<Sphere2D>().difference(d.getZone(), deserialized.getZone()).isEmpty()); }
From source file:org.orekit.propagation.events.GeographicZoneDetectorTest.java
private SphericalPolygonsSet buildFrance() { final SphericalPolygonsSet continental = buildSimpleZone(new double[][] { { 51.14850, 2.51357 }, { 50.94660, 1.63900 }, { 50.12717, 1.33876 }, { 49.34737, -0.98946 }, { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 }, { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 }, { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338, 1.82679 }, { 42.47301, 2.98599 }, { 43.07520, 3.10041 }, { 43.39965, 4.55696 }, { 43.12889, 6.52924 }, { 43.69384, 7.43518 }, { 44.12790, 7.54959 }, { 45.02851, 6.74995 }, { 45.33309, 7.09665 }, { 46.42967, 6.50009 }, { 46.27298, 6.02260 }, { 46.72577, 6.03738 }, { 47.62058, 7.46675 }, { 49.01778, 8.09927 }, { 49.20195, 6.65822 }, { 49.44266, 5.89775 }, { 49.98537, 4.79922 } }); final SphericalPolygonsSet corsica = buildSimpleZone( new double[][] { { 42.15249, 9.56001 }, { 43.00998, 9.39000 }, { 42.62812, 8.74600 }, { 42.25651, 8.54421 }, { 41.58361, 8.77572 }, { 41.38000, 9.22975 } }); return (SphericalPolygonsSet) new RegionFactory<Sphere2D>().union(continental, corsica); }