Search in sources :

Example 1 with Sphere2D

use of org.hipparchus.geometry.spherical.twod.Sphere2D in project Orekit by CS-SI.

the class EllipsoidTessellator method extractTiles.

/**
 * Extract tiles from a mesh.
 * @param mesh mesh from which tiles should be extracted
 * @param zone zone covered by the mesh
 * @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));
            }
        }
    }
    // 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;
}
Also used : S2Point(org.hipparchus.geometry.spherical.twod.S2Point) Sphere2D(org.hipparchus.geometry.spherical.twod.Sphere2D) ArrayList(java.util.ArrayList) SphericalPolygonsSet(org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet) S2Point(org.hipparchus.geometry.spherical.twod.S2Point) GeodeticPoint(org.orekit.bodies.GeodeticPoint) Vector3D(org.hipparchus.geometry.euclidean.threed.Vector3D)

Example 2 with Sphere2D

use of org.hipparchus.geometry.spherical.twod.Sphere2D in project Orekit by CS-SI.

the class EllipsoidTessellator method tessellate.

/**
 * Tessellate a zone of interest into tiles.
 * <p>
 * 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;
}
Also used : S2Point(org.hipparchus.geometry.spherical.twod.S2Point) IdentityHashMap(java.util.IdentityHashMap) Sphere2D(org.hipparchus.geometry.spherical.twod.Sphere2D) ArrayList(java.util.ArrayList) SphericalPolygonsSet(org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet) RegionFactory(org.hipparchus.geometry.partitioning.RegionFactory) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap)

Example 3 with Sphere2D

use of org.hipparchus.geometry.spherical.twod.Sphere2D in project Orekit by CS-SI.

the class EllipsoidTessellator method sample.

/**
 * Sample a zone of interest into a grid sample of {@link GeodeticPoint geodetic points}.
 * <p>
 * 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;
}
Also used : S2Point(org.hipparchus.geometry.spherical.twod.S2Point) IdentityHashMap(java.util.IdentityHashMap) Sphere2D(org.hipparchus.geometry.spherical.twod.Sphere2D) ArrayList(java.util.ArrayList) SphericalPolygonsSet(org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet) RegionFactory(org.hipparchus.geometry.partitioning.RegionFactory) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) GeodeticPoint(org.orekit.bodies.GeodeticPoint) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap)

Example 4 with Sphere2D

use of org.hipparchus.geometry.spherical.twod.Sphere2D in project Orekit by CS-SI.

the class FootprintOverlapDetectorTest method testSerialization.

@Test
public void testSerialization() throws IOException, ClassNotFoundException, OrekitException {
    // observe continental France plus Corsica
    final SphericalPolygonsSet france = buildFrance();
    // square field of view along Z axis (which is pointing sideways),
    // aperture 5° (hence half-aperture 2.5°), 0.001 radians margin
    final double alpha = FastMath.toRadians(2.5);
    final FieldOfView fov = new FieldOfView(Vector3D.PLUS_K, Vector3D.PLUS_I, alpha, 4, 0.001);
    double eta = FastMath.acos(FastMath.sin(alpha) * FastMath.sin(alpha));
    double theoreticalArea = MathUtils.TWO_PI - 4 * eta;
    final FootprintOverlapDetector detector = new FootprintOverlapDetector(fov, earth, france, 50000.0).withMaxCheck(1.0).withThreshold(1.0e-6).withHandler(new ContinueOnEvent<FootprintOverlapDetector>());
    Assert.assertEquals(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, ((OneAxisEllipsoid) detector.getBody()).getEquatorialRadius(), 1.0e-12);
    Assert.assertEquals(0.001, detector.getFieldOfView().getMargin(), 1.0e-12);
    Assert.assertEquals(theoreticalArea, detector.getFieldOfView().getZone().getSize(), 1.0e-12);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(detector);
    Assert.assertTrue(bos.size() > 2400);
    Assert.assertTrue(bos.size() < 2500);
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bis);
    FootprintOverlapDetector deserialized = (FootprintOverlapDetector) ois.readObject();
    Assert.assertEquals(detector.getZone().getSize(), deserialized.getZone().getSize(), 1.0e-14);
    Assert.assertEquals(detector.getZone().getBoundarySize(), deserialized.getZone().getBoundarySize(), 1.0e-14);
    Assert.assertEquals(detector.getZone().getTolerance(), deserialized.getZone().getTolerance(), 1.0e-15);
    Assert.assertEquals(detector.getMaxCheckInterval(), deserialized.getMaxCheckInterval(), 1.0e-15);
    Assert.assertEquals(detector.getThreshold(), deserialized.getThreshold(), 1.0e-15);
    Assert.assertEquals(detector.getMaxIterationCount(), deserialized.getMaxIterationCount());
    Assert.assertTrue(new RegionFactory<Sphere2D>().difference(detector.getZone(), deserialized.getZone()).isEmpty());
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) Sphere2D(org.hipparchus.geometry.spherical.twod.Sphere2D) SphericalPolygonsSet(org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ObjectOutputStream(java.io.ObjectOutputStream) ObjectInputStream(java.io.ObjectInputStream) Test(org.junit.Test)

Example 5 with Sphere2D

use of org.hipparchus.geometry.spherical.twod.Sphere2D in project Orekit by CS-SI.

the class GeographicZoneDetectorTest method testSerialization.

@Test
public void testSerialization() throws IOException, ClassNotFoundException, 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);
    Assert.assertTrue(bos.size() > 2100);
    Assert.assertTrue(bos.size() < 2200);
    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());
}
Also used : OneAxisEllipsoid(org.orekit.bodies.OneAxisEllipsoid) ByteArrayInputStream(java.io.ByteArrayInputStream) Sphere2D(org.hipparchus.geometry.spherical.twod.Sphere2D) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ObjectOutputStream(java.io.ObjectOutputStream) BodyShape(org.orekit.bodies.BodyShape) ObjectInputStream(java.io.ObjectInputStream) Test(org.junit.Test)

Aggregations

Sphere2D (org.hipparchus.geometry.spherical.twod.Sphere2D)6 SphericalPolygonsSet (org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet)5 ArrayList (java.util.ArrayList)3 S2Point (org.hipparchus.geometry.spherical.twod.S2Point)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 ObjectInputStream (java.io.ObjectInputStream)2 ObjectOutputStream (java.io.ObjectOutputStream)2 IdentityHashMap (java.util.IdentityHashMap)2 LinkedList (java.util.LinkedList)2 List (java.util.List)2 Map (java.util.Map)2 Vector3D (org.hipparchus.geometry.euclidean.threed.Vector3D)2 RegionFactory (org.hipparchus.geometry.partitioning.RegionFactory)2 Test (org.junit.Test)2 GeodeticPoint (org.orekit.bodies.GeodeticPoint)2 BSPTree (org.hipparchus.geometry.partitioning.BSPTree)1 Circle (org.hipparchus.geometry.spherical.twod.Circle)1 BodyShape (org.orekit.bodies.BodyShape)1 OneAxisEllipsoid (org.orekit.bodies.OneAxisEllipsoid)1