use of org.orekit.bodies.GeodeticPoint in project Orekit by CS-SI.
the class FootprintOverlapDetector method g.
/**
* {@inheritDoc}
* <p>
* The g function value is the minimum offset among the region points
* with respect to the Field Of View boundary. It is positive if all region
* points are outside of the Field Of View, and negative if at least some
* of the region points are inside of the Field Of View. The minimum is
* computed by sampling the region, considering only the points for which
* the spacecraft is above the horizon. The accuracy of the detection
* depends on the linear sampling step set at detector construction. If
* the spacecraft is below horizon for all region points, an arbitrary
* positive value is returned.
* </p>
* <p>
* As per the previous definition, when the region enters the Field Of
* View, a decreasing event is generated, and when the region leaves
* the Field Of View, an increasing event is generated.
* </p>
*/
public double g(final SpacecraftState s) throws OrekitException {
// initial arbitrary positive value
double value = FastMath.PI;
// get spacecraft position in body frame
final Vector3D scBody = s.getPVCoordinates(body.getBodyFrame()).getPosition();
// map the point to a sphere
final GeodeticPoint gp = body.transform(scBody, body.getBodyFrame(), s.getDate());
final S2Point s2p = new S2Point(gp.getLongitude(), 0.5 * FastMath.PI - gp.getLatitude());
// for faster computation, we start using only the surrounding cap, to filter out
// far away points (which correspond to most of the points if the zone is small)
final Vector3D p = s2p.getVector();
final double dot = Vector3D.dotProduct(p, capCenter);
if (dot < capCos) {
// the spacecraft is outside of the cap, look for the closest cap point
final Vector3D t = p.subtract(dot, capCenter).normalize();
final Vector3D close = new Vector3D(capCos, capCenter, capSin, t);
if (Vector3D.dotProduct(p, close) < -0.01) {
// we can return the arbitrary initial positive value without performing further computation
return value;
}
}
// the spacecraft may be visible from some points in the zone, check them all
final Transform bodyToSc = new Transform(s.getDate(), body.getBodyFrame().getTransformTo(s.getFrame(), s.getDate()), s.toTransform());
for (final SamplingPoint point : sampledZone) {
final Vector3D lineOfSightBody = point.getPosition().subtract(scBody);
if (Vector3D.dotProduct(lineOfSightBody, point.getZenith()) <= 0) {
// spacecraft is above this sample point local horizon
// get line of sight in spacecraft frame
final double offset = fov.offsetFromBoundary(bodyToSc.transformVector(lineOfSightBody));
value = FastMath.min(value, offset);
}
}
return value;
}
use of org.orekit.bodies.GeodeticPoint in project Orekit by CS-SI.
the class FootprintOverlapDetector method sample.
/**
* Sample the region.
* @param body body on which the geographic zone is defined
* @param zone geographic zone to consider
* @param samplingStep linear step used for sampling the geographic zone (in meters)
* @return sampling points
* @throws OrekitException if the region cannot be sampled
*/
private static List<SamplingPoint> sample(final OneAxisEllipsoid body, final SphericalPolygonsSet zone, final double samplingStep) throws OrekitException {
final List<SamplingPoint> sampledZone = new ArrayList<SamplingPoint>();
// sample the zone boundary
final List<Vertex> boundary = zone.getBoundaryLoops();
for (final Vertex loopStart : boundary) {
int count = 0;
for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
++count;
final Edge edge = v.getOutgoing();
final int n = (int) FastMath.ceil(edge.getLength() * body.getEquatorialRadius() / samplingStep);
for (int i = 0; i < n; ++i) {
final S2Point intermediate = new S2Point(edge.getPointAt(i * edge.getLength() / n));
final GeodeticPoint gp = new GeodeticPoint(0.5 * FastMath.PI - intermediate.getPhi(), intermediate.getTheta(), 0.0);
sampledZone.add(new SamplingPoint(body.transform(gp), gp.getZenith()));
}
}
}
// sample the zone interior
final EllipsoidTessellator tessellator = new EllipsoidTessellator(body, new ConstantAzimuthAiming(body, 0.0), 4);
final List<List<GeodeticPoint>> gpSample = tessellator.sample(zone, samplingStep, samplingStep);
for (final List<GeodeticPoint> list : gpSample) {
for (final GeodeticPoint gp : list) {
sampledZone.add(new SamplingPoint(body.transform(gp), gp.getZenith()));
}
}
return sampledZone;
}
use of org.orekit.bodies.GeodeticPoint in project Orekit by CS-SI.
the class LongitudeCrossingDetector method g.
/**
* Compute the value of the detection function.
* <p>
* The value is the longitude difference between the spacecraft and the fixed
* longitude to be crossed, with some sign tweaks to ensure continuity.
* These tweaks imply the {@code increasing} flag in events detection becomes
* irrelevant here! As an example, the longitude of a prograde spacecraft
* will always increase, but this g function will increase and decrease so it
* will cross the zero value once per orbit, in increasing and decreasing
* directions on alternate orbits. If eastwards and westwards crossing have to
* be distinguished, the velocity direction has to be checked instead of looking
* at the {@code increasing} flag.
* </p>
* @param s the current state information: date, kinematics, attitude
* @return longitude difference between the spacecraft and the fixed
* longitude, with some sign tweaks to ensure continuity
* @exception OrekitException if some specific error occurs
*/
public double g(final SpacecraftState s) throws OrekitException {
// convert state to geodetic coordinates
final GeodeticPoint gp = body.transform(s.getPVCoordinates().getPosition(), s.getFrame(), s.getDate());
// longitude difference
double delta = MathUtils.normalizeAngle(sign * (gp.getLongitude() - longitude), 0.0);
// ensure continuity
if (FastMath.abs(delta - previousDelta) > FastMath.PI) {
sign = -sign;
delta = MathUtils.normalizeAngle(sign * (gp.getLongitude() - longitude), 0.0);
}
previousDelta = delta;
return delta;
}
use of org.orekit.bodies.GeodeticPoint in project Orekit by CS-SI.
the class EllipsoidTessellator method extractSample.
/**
* Extract a sample of points from a mesh.
* @param mesh mesh from which grid should be extracted
* @param zone zone covered by the mesh
* @return extracted grid
* @exception OrekitException if tile direction cannot be computed
*/
private List<GeodeticPoint> extractSample(final Mesh mesh, final SphericalPolygonsSet zone) throws OrekitException {
// find how to select sample points taking quantization into account
// to have the largest possible number of points while still
// being inside the zone of interest
int selectedAcrossModulus = -1;
int selectedAlongModulus = -1;
int selectedCount = -1;
for (int acrossModulus = 0; acrossModulus < quantization; ++acrossModulus) {
for (int alongModulus = 0; alongModulus < quantization; ++alongModulus) {
// count how many points would be selected for the current modulus
int count = 0;
for (int across = mesh.getMinAcrossIndex() + acrossModulus; across <= mesh.getMaxAcrossIndex(); across += quantization) {
for (int along = mesh.getMinAlongIndex() + alongModulus; along <= mesh.getMaxAlongIndex(); along += quantization) {
final Mesh.Node node = mesh.getNode(along, across);
if (node != null && node.isInside()) {
++count;
}
}
}
if (count > selectedCount) {
// current modulus are better than the selected ones
selectedAcrossModulus = acrossModulus;
selectedAlongModulus = alongModulus;
selectedCount = count;
}
}
}
// extract the sample points
final List<GeodeticPoint> sample = new ArrayList<GeodeticPoint>(selectedCount);
for (int across = mesh.getMinAcrossIndex() + selectedAcrossModulus; across <= mesh.getMaxAcrossIndex(); across += quantization) {
for (int along = mesh.getMinAlongIndex() + selectedAlongModulus; along <= mesh.getMaxAlongIndex(); along += quantization) {
final Mesh.Node node = mesh.getNode(along, across);
if (node != null && node.isInside()) {
sample.add(toGeodetic(node.getS2P()));
}
}
}
return sample;
}
use of org.orekit.bodies.GeodeticPoint 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;
}
Aggregations