Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • orekit/rugged
  • sdinot/rugged
  • yzokras/rugged
  • youngcle/rugged-mod
4 results
Show changes
Showing
with 1452 additions and 0 deletions
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Development Guidelines
The following guidelines are used for Rugged development.
## Development
Rugged is an intermediate level library. It may be used in very different
contexts which cannot be foreseen, from quick studies up to critical
operations. The main driving goals are the following ones:
* validation
* robustness
* maintainability
* efficiency
The first goal, validation, implies tests must be as extensive as possible.
They should include realistic operational cases but also contingency cases.
The [jacoco](http://www.eclemma.org/jacoco/ "Jacoco homepage") tool must be used to
monitor test coverage. A very high level of coverage is desired. We do not
set up mandatory objective figures, but only guidelines here. However,a 60%
line coverage would clearly not be acceptable at all and 80% would be considered
deceptive.
The second goal, robustness, has some specific implications for a low level
component like Rugged. In some sense, it can be considered an extension of the
previous goal as it can also be improved by testing. It can also be improved
by automatic checking tools that analyze either source code or binary code. The
[spotbugs](https://spotbugs.github.io/ "Spotbugs homepage") tool is already configured for
automatic checks of the library using a maven plugin.
This is however not sufficient. A library is intended to be used by applications
unknown to the library development team. The library development should be as
flexible as possible to be merged into an environment with specific constraints.
For example, perhaps an application should run 24/7 during months or years, so
caching all results to improve efficiency may prove disastrous in such a use case,
or it should be embedded in a server application, so printing to standard output
should never be done. Experience has shown that developing libraries is more
difficult than developing high level applications where most of the constraints
are known beforehand.
The third goal, maintainability, implies code must be readable, clear and
well documented. Part of this goal is enforced by the stylistic rules explained
in the next section, but this is only for the _automatic_ and simple checks. It
is important to keep a clean and extensible design. Achieving simplicity is
really hard, so this goal should not be taken too lightly. Good designs are a
matter of balance between two few objects that do too many things internally
an ignore each other and too many objects that do nothing alone and always need
a bunch of other objects to work. Always think in terms of balance, and check
what happens if you remove something from the design. Quite often, removing something
improves the design and should be done.
The fourth goal, efficiency, should be handled with care to not conflict with the
second and third goals (robustness and maintainability). Efficiency is necessary but
trying too much too achieve it can lead to overly complex unmaintainable code, to too
specific fragile code, and unfortunately too often without any gain after all because
of premature optimization and unfounded second-guess.
One surprising trick, that at first sight might seem strange and inappropriate has
been used in many part for Rugged and should be considered a core guideline. It
is the use of _immutable_ objects. This trick improves efficiency because many costly
copying operation are avoided, even unneeded one added for defensive programming. It
improves maintainability because both the classes themselves and the classes that use
them are much simpler. It also improves robustness because many (really many ...)
difficult to catch bugs are caused by mutable objects that are changed in some deeply
buried code and have an impact on user code that forgot to perform a defensive copy.
Orbits, dates, vectors, and rotations are all immutable objects.
## Source Control Management
The source code control management system used is [Git](http://git-scm.com/ "Git homepage"). The
main Rugged repository is located at [https://gitlab.orekit.org/orekit/rugged.git](https://gitlab.orekit.org/orekit/rugged.git).
Starting after version 2.0, the branch management workflow is adapted from
both [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and
from the [Orfeo ToolBox Workflow](https://wiki.orfeo-toolbox.org/index.php/Git#Workflow "OTB workflow").
It is the same as chosen for Orekit.
![Rugged git workflow](./images/rugged-git-flow.png)
This implies that development occurs on a develop branch only.
Developers create feature branches, and merge them on the develop
branch when ready. The develop branch should always be functional
so people wanting to be on the bleeding edge can use it (for example
to create nightly builds or to prepare their application for upcoming
features before the official release).
In order to improve traceability, when a feature branch is merged into
develop, it should use
git merge ---no-ff
the --no-ff flag prevents fast-forward so the history makes it clear there
was a feature branch at this point.
Feature branches are temporary, they are deleted when they are not useful anymore.
Feature branches may be present only in one developer workspace and never appear
in the main repository, however, they may also be pushed on the main repository
if the developer wants to share work or needs community feedback.
When a release is desired, a dedicated branch should be created, with a name
following the pattern release-x.y. These branches are created from the
develop branch. When the release is ready, the branch is merged both into the
master branch and into the develop branch. Once a release branch has been set
up, it will remain. This allows users relying on this specific version to be
able to retrieve the fixes published afterward (i.e. x.y.1, x.y.2...).
After a release has been published and pushed to master, it may be necessary
to publish an urgent bugfix if a serious problem in the released version is
found. Short-lived bugfix branches that are created directly from master are
devoted to this. These bugfix branches are merged back into master and develop.
The master branch always refer to the latest stable release performed. No
direct work is done on this branch. It is updated only by merging either
release branches or bugfix branches branches to it.
## Style Rules
For reading ease and consistency, the existing code style should be
preserved for all new developments. The rules are common ones, inherited
mainly from the Sun Code Conventions for the Java Programming Language guide style and
from the default [checkstyle](http://checkstyle.sourceforge.net/) tool
configuration. A few of these rules are displayed below. The complete
definition is given by the checkstyle configuration file in the project
root directory.
* *header rule*
all source files start with the Apache license header,
* *indentation rules*
no tabs, 4 spaces indentation, no indentation for case statements,
* *operators wrapping rules*
lines are wrapped after operators (unlike Sun),
* *whitespace rules*
operators are surrounded by spaces, method parameters open parenthesis
is not preceded by space, lines do not end with white space,
* *curly brace rules*
open curly brace are at end of line, with the matching closing curly brace
aligned with the start of the corresponding keyword (_if_, _for_,
_while_, _case_ or _do_),
* *encoding rules*
characters encoding is _UTF8_, the git property _core.autocrlf_ should be
set to _input_ on Linux development machines and to _true_ on Windows
development machines (to ensure proper conversion on all operating systems),
* *naming rules*
classes names begin with upper case, instance methods and fields
names begin with lower case, class fields are all upper case with
words separated by underscores,
* *ordering rules*
class variables come first, followed by instance variables, followed
by constructors, and followed by methods, public modifiers come first,
followed by protected modifiers followed by private modifiers,
* *javadoc rules*
all elements have complete javadoc, even private fields and methods
(there are some rare exceptions, in case of code translated from
the fortran language and models with huge parameters sets),
* *robustness rules*
switch/case construct have a default argument, even when all possible
cases are already handled, as many classes as possible are immutable,
* *miscellaneous rules*
_star_ imports are forbidden, parameters and local variables are final
wherever possible.
## Design Rules
* *coverage* (validation)
seek for a line test coverage of at least 80% (more is better)
* *spotbugs* (robustness)
fix _all_ errors and warnings found by spotbugs
* *no runtime assumptions* (robustness)
do not make assumptions on the runtime environment of applications using Orekit
(they may be embedded with no console, no possible user interaction, no network,
no writable file system, no stoppable main program, have memory constraints,
time constraints, be run in different linguistic contexts ...)
* *simplicity* (maintainability)
follow Occam's razor principle or its declination in computer science: KISS (Keep It Simple, Stupid)
* *balanced design* (efficiency)
seek efficiency, but do not overstep robustness and maintainability
* *immutable objects* (robustness, maintainability)
use immutable objects as much as possible
* *checkstyle* (style)
fix _all_ errors and warnings found by checkstyle
[Top of the page](#top)
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Overview
Rugged is a sensor-to-terrain mapping tool which takes into account Digital Elevation Models (DEM)
in its line of sight computation. It is a free software
intermediate-level library written in Java and implemented as an add-on for [Orekit](https://www.orekit.org/ "Orekit homepage").
![Earth_FlatVsRugged.gif](./images/Earth_FlatVsRugged.gif)
It mainly provides direct and inverse location, i.e. it allows
to compute accurately which ground point is looked at from a specific
pixel in a spacecraft instrument, and conversely which pixel will
see a specified ground point. This mapping between ground and sensor
is computed with a viewing model taking into account ground Digital
Elevation Model, Earth rotation will all its tiny irregularities,
on-board sensor pixels individual line-of-sights, spacecraft motion and
attitude and several physical effects.
![RuggedExplained.png](./images/RuggedExplained.png)
*Effects of taking into account the DEM in the computation of latitude, longitude and altitude*
Direct and inverse location can be used to perform full ortho-rectification
of images and correlation between sensors observing the same area.
## Features
* Direct/inverse location
* Refinement
* Can support several types of Digital Elevation Models, including user-provided models
* Several intersection models algorithms available
* Can propagate orbit by itself for preliminary mission analysis or data generation
* Can propagate attitude by itself for preliminary mission analysis or data generation
* *very* fast
* Both modern and legacy models for Earth rotation
* Lieske (1976), Wahr (1980),
* Mathews, Herring, Buffett (2002)
* Capitaine (2006)
* Complete set of corrections applied for greater accuracy
* δΔψ, δΔε on precession nutation (about 3m correction since 2013, steadily increasing)
* ΔUT₁, lod on proper rotation (can theoretically reach up to 400m)
* u, v pole wander (polhody), (about 15m correction)
* light time correction (about 1.2m)
* aberration of light correction (about 20m)
* line-of-sight curvature in geodetic coordinates,
(0m at nadir, 10m at 30° dive angle, hundreds of meters for skimming los)
* atmospheric refraction
* Not limited to Earth
* Highly portable (Linux, Windows, MacOSX, ...)
* Localized in several languages
* Danish
* English
* French
* Galician
* German
* Italian
* Norwegian
* Romanian
* Spanish
## Free software
Rugged is freely available both in source and binary formats, with all related
documentation and tests.
It is distributed under the [Apache License Version 2.0](./license.html). This
is a well known business-friendly license. This means anybody can use it to build
any application, free or not. There are no strings attached to your own code.
Everybody is encouraged to use Rugged as a common intermediate level layer to improve
interoperability in space systems.
## Maintained library
Rugged has been in development since 2014 inside [CS GROUP](https://www.csgroup.eu/ "CS GROUP homepage")
and is still used and maintained by its dual teams
of space dynamics and image processing experts.
Rugged is used for image processing of the Sentinel 2 mission at European Space
Agency (ESA), as well as in the frame of ESA Scientific Exploitation of Operational Missions (SEOM),
to calculate topographic shadow masks for Sentinel 2 products.
Rugged has been used to validate Airbus Defence and Space (ADS) geolocation library.
Rugged has been also used as a Research Library by the French Space Agency (CNES) for refinement studies for VHR push broom sensors (Pleiades).
Rugged is used for study purposes inside CS GROUP.
[Top of the page](#top)
# Rugged Release Guide
This release guide is largely inspired from [Hipparchus Release
Guide](https://www.hipparchus.org/release-guide.html) and [Orekit Release Guide](https://www.orekit.org/site-orekit-development/release-guide.html). It lists the steps that
have been used in the past to release a new version of Rugged. When in doubt
ask the experts: Sébastien Dinot <sebastien.dinot@csgroup.eu> for website questions
and Luc Maisonobe <luc.maisonobe@csgroup.eu> for everything else.
## Prerequisites
1. Obtain private key of the Rugged Signing Key, key id:
`9A928E5485FBC44A2A4F9C2E9128808ECB6C9DED`
2. Register for account on OSSRH and associate it with the Rugged project, see:
https://central.sonatype.org/pages/ossrh-guide.html
If you need help with either, ask on the [development section of the Rugged
forum](https://forum.orekit.org/c/rugged-development/).
Once you have a SonaType OSS account, the corresponding credentials must be set
in the `servers` section of your `$HOME/.m2/settings.xml` file, using an id of
`ossrh`:
<servers>
<server>
<id>ossrh</id>
<username>the user name to connect to the OSS site</username>
<password>the encrypted password</password>
</server>
</servers>
Use `mvn -ep` to generate an encrypted password.
## Install Graphviz
[Graphviz (dot)](https://graphviz.org) is used to generated diagrams of
the technical documentation (static site).
## Verify the status of develop branch
Before anything, check on the [continuous integration
site](https://sonar.orekit.org/dashboard?id=org.orekit%3Arugged) that everything is fine on
develop branch:
* All tests pass;
* Code coverage is up to the requirements;
* There are no bugs, vulnerabilities or code smells.
If not, fix the warnings and errors first !
It is also necessary to check on the [Gitlab CI/CD](https://gitlab.orekit.org/orekit/rugged/pipelines)
that everything is fine on develop branch (i.e. all stages are passed).
## Prepare Git branch for release
Release will be performed on a dedicated branch, not directly on master or
develop branch. So a new branch must be created as follows and used for
everything else:
git branch release-X.Y
git checkout release-X.Y
## Update maven plugins versions
Release is a good opportunity to update the maven plugin versions. They are all
gathered at one place, in a set of properties in `rugged/pom.xml`, for instance:
<rugged.spotbugs-maven-plugin.version>4.0.4</rugged.spotbugs-maven-plugin.version>
<rugged.jacoco-maven-plugin.version>0.8.5</rugged.jacoco-maven-plugin.version>
<rugged.maven-assembly-plugin.version>3.1.1</rugged.maven-assembly-plugin.version>
...
You can find the latest version of the plugins using the search feature at
[http://search.maven.org/#search](http://search.maven.org/#search). The
properties name all follow the pattern `rugged.some-plugin-name.version`, the
plugin name should be used in the web form to check for available versions.
Beware that in some cases, the latest version cannot be used due to
incompatibilities. For example when a plugin was not recently updated and
conflicts appear with newer versions of its dependencies.
Beware also that some plugins use configuration files that may need update too.
This is typically the case with `maven-checkstyle-plugin` and
`spotbugs-maven-plugin`. The `/checkstyle.xml` and `/spotbugs-exclude-filter.xml` files may need to be checked.
Before committing these changes, you have to check that everything works. So
run the following command:
mvn clean
LANG=C mvn -Prelease site
If something goes wrong, either fix it by changing the plugin configuration or
roll back to an earlier version of the plugin.
Browse the generated site starting at page `target/site/index.html` and check
that everything is rendered properly. You may also check the contents of the pages.
When everything runs fine and the generated site is OK, then you can commit the
changes:
git add rugged/pom.xml rugged/checkstyle.xml rugged/spotbugs-exclude-filter.xml
git commit -m "Updated maven plugins versions."
## Updating changes.xml
Finalize the file `src/changes/changes.xml` file.
The release date and description, which are often only set to `TBD` during
development, must be set to appropriate values. The release date at this step
is only a guess one or two weeks in the future, in order to take into account
the 5 days release vote delay.
Replace the `TBD` description with a text describing the version released:
state if it is a minor or major version, list the major features introduced by
the version etc (see examples in descriptions of former versions).
Commit the `changes.xml` file.
git add src/changes/changes.xml
git commit -m "Updated changes.xml for official release."
## Updating documentation
Several files must be updated to take into account the new version:
| file name | usage | required update |
|-------------------------------------|----------------------------|--------------------------------------------------------------------------------------------------------|
| `src/site/markdown/index.md` | site home page | Update the text about the new features (see changes from **changes.xml**) |
| `src/site/markdown/downloads.md.vm` | downloads links | Declare the new versions, don't forget the date |
Once the files have been updated, commit the changes:
git add src/site/markdown/*.md
git commit -m "Updated documentation for the release."
## Change library version number
The `pom.xml` file contains the version number of the library. During
development, this version number has the form `X.Y-SNAPSHOT`. For release, the
`-SNAPSHOT` part must be removed.
Commit the change:
git add pom.xml
git commit -m "Dropped -SNAPSHOT in version number for official release."
## Check the JavaDoc
Depending the JDK version (Oracle, OpenJDK, etc), some JavaDoc warnings can be present.
Make sure there is no JavaDoc warnings by running the following command:
mvn javadoc:javadoc
If possible, run the above command with different JDK versions.
## Tag and sign the git repository
When all previous steps have been performed, the local git repository holds the
final state of the sources and build files for the release. It must be tagged
and the tag must be signed. Note that before the vote is finished, the tag can
only signed with a `-RCx` suffix to denote Release Candidate. The final tag
without the `-RCx` suffix will be put once the vote succeeds, on the same
commit (which will therefore have two tags). Tagging and signing is done using
the following command, with `-RCn` replaced with the Release Candidate number:
git tag X.Y-RCn -s -u 9A928E5485FBC44A2A4F9C2E9128808ECB6C9DED -m "Release Candidate n for version X.Y."
The tag should be verified using command:
git tag -v X.Y-RCn
## Pushing the branch and the tag
When the tag is ready, the branch and the tag must be pushed to Gitlab so
everyone can review it:
git push --tags origin release-X.Y
## Static site (technical documentation)
The static site is generated locally using:
mvn clean
LANG=C mvn site
The official site is automatically updated on the hosting platform when work is
merged into branches `develop`, `release-*` or `master`.
## Generating signed artifacts
When these settings have been set up, generating the artifacts is done by
running the following commands:
mvn deploy -DskipStagingRepositoryClose=true -Prelease
During the generation, maven will trigger gpg which will ask the user for the
pass phrase to access the signing key. If maven didn’t prompt to you, you have to
add `-Dgpg.passphrase=[passphrase]`
Once the commands ends, log into the SonaType OSS site
[https://oss.sonatype.org/](https://oss.sonatype.org/) and check the staging
repository contains the expected artifacts with associated signatures and
checksums:
- rugged-X.Y.pom
- rugged-X.Y.jar
- rugged-X.Y-sources.jar
- rugged-X.Y-javadoc.jar
The signature and checksum files have similar names with added extensions `.asc`,
`.md5` and `.sha1`.
Sometimes, the deployment to Sonatype OSS site also adds files with double extension
`.asc.md5` and `.asc.sha1`, which are in fact checksum files on a signature file
and serve no purpose and can be deleted.
Remove `rugged-X.Y.source-jar*` since they are duplicates of the
`rugged-X.Y-sources.jar*` artifacts. Then click the “Close” button.
## Update Rugged version in Rugged test website
One edit needs to be made to the Rugged website before calling the vote. Fetch the current code:
git clone https://gitlab.orekit.org/orekit/website-2015
Switch to `develop` branch and edit `_data/rugged/versions.yml` by adding the new version X.Y
to the list.
Once the modification pushed to develop branch, the [test website](https://test.orekit.org/rugged) will be updated
## Calling for the vote
Everything is now ready so the developers and PMC can vote for the release.
Create a post in the [Rugged development category of the forum](https://forum.orekit.org/c/rugged-development/)
with a subject line of the form:
[VOTE] Releasing Rugged X.Y from release candidate n
and content of the form:
This is a VOTE in order to release version X.Y of the Rugged library.
Version X.Y is a maintenance release.
Highlights in the X.Y release are:
- feature 1 description
...
- feature n description
The release candidate n can be found on the GitLab repository as
tag X.Y-RCn in the release-X.Y branch:
<https://gitlab.orekit.org/orekit/rugged/tree/X.Y-RCn>
The release notes can be read here:
<https://test.orekit.org/site-rugged-X.Y/changes-report.html>
Maven artifacts are available at
<https://oss.sonatype.org/content/repositories/orgorekit-xxxx/>
The votes will be tallied in 120 hours for now, on 20yy-mm-ddThh:mm:00Z
(this is UTC time).
You should also ping PMC members so they are aware of the vote. Their
vote is essential for a release as per project governance.
## Failed vote
If the vote fails, the maven artifacts must be removed from OSS site by
dropping the repository. Then a new release candidate must
be created, with a new number, a new tag and new artifacts. Another vote is
needed for this new release candidate. So make the necessary changes and then
start from the “Tag and sign the git repository” step.
## Successful vote
When the vote for a release candidate succeeds, follow the steps below to
publish the release.
## Tag release version
As the vote passed, a final signed tag must be added to the succeeding release
candidate, verified and pushed:
git tag X.Y -s -u 9A928E5485FBC44A2A4F9C2E9128808ECB6C9DED -m "Version X.Y."
git tag -v X.Y
git push --tags
## Merge release branch into master
Merge the release branch into the `master` branch to include any changes made.
git checkout master
git merge --no-ff release-X.Y
Then commit and push.
## Merge master branch into develop
Merge the `master` branch into the `develop` branch to include any changes made.
git checkout develop
git merge --no-ff master
Then update the version number to prepare for the next development cycle:
- edit the pom.xml to update version to a SNAPSHOT,
- make space in the `/src/changes/changes.xml` file for new changes.
Then commit and push.
## Publish maven artifacts
The maven artifacts must be published using OSS site to release the repository.
Select the Rugged repository in "Staging Repositories" and click the “Release”
button in [Nexus Repository Manager](https://oss.sonatype.org/).
## Upload to Gitlab
Navigate to Projects > Rugged > Repository > Tags. Find the X.Y tag and
click the edit button to enter release notes. Use the **path** in the [Nexus
repository](https://packages.orekit.org/#browse/browse:maven-releases:org%2Forekit%2Frugged) to
set the artifacts in the release notes.
- rugged-X.Y.jar
- rugged-X.Y-sources.jar
- rugged-X.Y-javadoc.jar
Navigate to Projects > Rugged > Project Overview > Releases and make sure it looks nice.
## Synchronize the Github mirror
To enhance the visibility of the project, [a mirror](https://github.com/CS-SI/Rugged) is maintained on Github.
The releases created on Gitlab are not automatically pushed on this mirror.
They have to be declared manually to make visible the vitality of Rugged.
1. Login to Github
2. Go to the [Rugged releases](https://github.com/CS-SI/Rugged/releases) page
3. Click on the [Draft a new release](https://github.com/CS-SI/Rugged/releases) button
4. In the "Tag version" field of the form and in the "Release title" field, enter the tag of the release to be declared
5. Describe the release as it has been done on Gitlab
6. Click on "Publish release"
Github automically adds two assets (zip and tarball archives of the tagged source code).
## Update Rugged website
Several edits need to be made to the Rugged website after the vote.
Edit `download/.htaccess` and replace the URLs of the 3 Rugged artifacts
with the ones used to create the release notes.
Edit `_layouts/home_rugged.html` and edit the text of the button to use the new version.
Edit `rugged/overview.html` with the new Orekit and Hipparchus versions. Don't forget to update the
rugged/img/rugged-architecture.png image with the new dependencies.
Create a new post for the release in `_post/` using as template a previous Rugged post (in order to be published in the Rugged News page). To be noticed the `--future` option is needed to see a post in the future, otherwise `jekyll serve` will ignore it !
Run:
jekyll serve --future
and make sure the website looks nice. View it on http://localhost:4000/
## Close X.Y milestone
In Gitlab, navigate to Projects > Rugged > Issues > Milestones.
Click “Close Milestone” for the line corresponding to the release X.Y.
## Announce release
The last step is to announce the release by creating a post in the
[Rugged announcements category of the forum](https://forum.orekit.org/c/rugged-announcements/)
with a subject line of the form:
Rugged X.Y released
and content of the form:
The Rugged team is pleased to announce the release of Rugged version X.Y.
This is a minor/major version, including both new features and bug fixes.
The main changes are:
- feature 1 description
...
- feature n description
This version depends on Orekit X.x and Hipparchus Y.y.
For complete release notes please see:
https://www.orekit.org/site-rugged-X.Y/changes-report.html
The maven artifacts are available in maven central.
The source and binaries can be retrieved from the forge releases page:
https://gitlab.orekit.org/orekit/rugged/-/releases
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Getting the sources
## Released versions
In order to get the source for officially released versions, go to the
[Release page](https://gitlab.orekit.org/orekit/rugged/tags) in Rugged
forge and select one of the `rugged-x.y-sources.zip` files. The `x.y` part in the name
specifies the version.
If this is the first time you download the library and
you have not yet set up your own data set with UTC-TAI history, JPL ephemerides,
IERS Earth Orientation Parameters ... you may want to also download the
`orekit-data.zip` file which is an example file suitable for a quick start (see
[configuration](./configuration.html) for further reading about data configuration).
It is also possible to retrieve published versions from the Git repository
(see next section below), if retrieving either release-x.y branches or the
master branch.
## Development version
The development of the Rugged project is done using the [Git](http://git-scm.com/ "Git homepage")
source code control system. Rugged Git master repository is available online.
The latest developments are in the develop branch. This is the one you want to retrieve
if you need the latest feature before they are published in an official release.
See [guidelines](./guidelines.html) for the branching workflow used in Rugged.
* you can browse it using the [Repository](https://gitlab.orekit.org/orekit/rugged/tree/develop)
tab in Rugged Gitlab.
* you can clone it anonymously with the command:
git clone -b develop https://gitlab.orekit.org/orekit/rugged.git
* if you are a committer, you can clone it using your ssh credentials with the command:
git clone -b develop git@gitlab.orekit.org:orekit/rugged.git
[Top of the page](#top)
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Direct Location with a DEM
The aim of this tutorial is to compute a direct location grid by intersection of
the line of sight with a DEM (Digital Elevation Model), using Duvenhage's algorithm.
This algorithm is the most performant one in Rugged.
The following figure shows the effects of taking into account the DEM in the computation of latitude, longitude and altitude:
![RuggedExplained.png](../images/RuggedExplained.png)
## Feeding Rugged with DEM tiles
Rugged does not parse DEM files but takes buffers of elevation data as input.
It is up to the calling application to read the DEM and load the data into buffers.
Rugged provides a tile mecanism with cache for large DEMs allowing the user to load
one tile at a time. This is in line with the format of world coverage DEMs such as SRTM.
Rugged offers an interface for updating the DEM tiles in cache with a callback function
triggered everytime a coordinate falls outside the current region.
The calling application must implement the callback function for loading the tiles.
We recommend to use GDAL (http://www.gdal.org/) to parse the DEM files as it handles most
formats (including geoTIFF for Aster DEM or DTED for SRTM). Rugged does not include the
parsing of the DEM, by design, and yet we could have used GDAL.
We want Rugged to remain a low-level library that does not pull too many third-party libraries.
### Implementing the interface TileUpdater for DEM loading.
In this tutorial, we will not include real DEM data. Instead we are going to create a fake DEM
representing a volcano in a form of a perfect cone, similar to the Mayon volcano
in the Philippines, except that we will locate it somewhere just below our satellite.
This example is already part of Rugged tests cases, the source code is available
in the package `org.orekit.rugged.raster`, file VolcanicConeElevationUpdater.java.
The class `VolcanicConeElevationUpdater` implements the interface `TileUpdater` with its method `updateTile`.
The method is in charge of loading a tile. The extent of the tile must be such that it covers
at least the ground point with coordinates (latitude, longitude) which are passed as arguments to the method.
The tile is an object of type `UpdatableTile` which has two methods :
* `setGeometry(minLatitude, minLongitude, latitudeStep, longitudeStep, latitudeRows, longitudeRows)` : initializes the extent of the new tile before loading
* `setElevation(latIdx, longIdx, elevation)` : fills the tile buffer at indices (latIdx, lonIdx) with value elevation
Here's the source code of the class `VolcanicConeElevationUpdater` :
import org.hipparchus.util.FastMath;
import org.orekit.rugged.raster.TileUpdater;
import org.orekit.rugged.raster.UpdatableTile;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.utils.Constants;
public class VolcanicConeElevationUpdater implements TileUpdater {
private GeodeticPoint summit;
private double slope;
private double base;
private double size;
private int n;
public VolcanicConeElevationUpdater(GeodeticPoint summit, double slope, double base,
double size, int n) {
this.summit = summit;
this.slope = slope;
this.base = base;
this.size = size;
this.n = n;
}
public void updateTile(double latitude, double longitude, UpdatableTile tile)
throws RuggedException {
double step = size / (n - 1);
double minLatitude = size * FastMath.floor(latitude / size);
double minLongitude = size * FastMath.floor(longitude / size);
double sinSlope = FastMath.sin(slope);
tile.setGeometry(minLatitude, minLongitude, step, step, n, n);
for (int i = 0; i < n; ++i) {
double cellLatitude = minLatitude + i * step;
for (int j = 0; j < n; ++j) {
double cellLongitude = minLongitude + j * step;
double distance = Constants.WGS84_EARTH_EQUATORIAL_RADIUS *
FastMath.hypot(cellLatitude - summit.getLatitude(),
cellLongitude - summit.getLongitude());
double altitude = FastMath.max(summit.getAltitude() - distance * sinSlope,
base);
tile.setElevation(i, j, altitude);
}
}
}
}
### Important notes on DEM tiles :
* Ground point elevation are obtained by bilinear interpolation between 4 neighbouring cells. There is no specific algorithm for border management. As a consequence, a point falling on the border of the tile is considered outside. **DEM tiles must be overlapping by at least one line/column in all directions**.
* In Rugged terminology, the minimum latitude and longitude correspond to the centre of the farthest Southwest cell of the DEM. Be careful if using GDAL to pass the correct information as there is half a pixel shift with respect to the lower left corner coordinates in gdalinfo.
The following diagram illustrates proper DEM tiling with one line/column overlaps between neighbouring tiles :
![DEM-tiles-overlap.png](../images/DEM-tiles-overlap.png)
This diagram tries to represent the meaning of the different parameters in the definition of a tile :
![tile-description.png](../images/tile-description.png)
## Initializing Rugged with a DEM
The initialization step differs slightly from the first tutorial [Direct location](./direct-location.html),
as we need to pass the information about our TileUpdater.
Instantiate an object derived from TileUpdater :
TileUpdater updater = new VolcanicConeElevationUpdater(summit, slope, base, FastMath.toRadians(1.0), 100);
int nbTiles = 8 ; //number max of tiles in Rugged cache
AlgorithmId algoId = AlgorithmId.DUVENHAGE;
Initialize Rugged with these parameters :
Rugged rugged = new RuggedBuilder().
setDigitalElevationModel(updater, nbTiles).
setAlgorithm(algoId).
setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF).
setTimeSpan(startDate, stopDate, 0.1, 10.0).
setTrajectory(InertialFrameId.EME2000,
satellitePVList, 6, CartesianDerivativesFilter.USE_P,
satelliteQList, 8, AngularDerivativesFilter.USE_R).
addLineSensor(lineSensor).
build();
## Computing a direct location grid
In a similar way as in the first tutorial [Direct Location](./direct-location.html),
we call Rugged direct location method. This time it is called in a loop so as to generate a full grid on disk.
DataOutputStream dos = new DataOutputStream(new FileOutputStream("demDirectLoc.c1"));
int lineStep = (maxLine - minLine) / nbLineStep;
int pxStep = (maxPx - minPx) / nbPxStep;
for (int i = 0; i < nbLineStep; i++) {
List<GeodeticPoint> pointList = new ArrayList<GeodeticPoint>(nbPxStep);
int currentLine = minLine + i * lineStep;
for (int j = 0; j < nbPxStep; j++) {
int currentPx = minPx + j * pxStep;
// Call to direct localization on current line
Vector3D position = lineSensor.getPosition();
AbsoluteDate currentLineDate = lineSensor.getDate(currentLine);
Vector3D los = lineSensor.getLOS(absDate, currentPx);
pointList.add(rugged.directLocation(currentLineDate, position, los));
}
for (GeodeticPoint point : pointList) {
if (point != null) {
dos.writeFloat((float) FastMath.toDegrees(point.getLatitude()));
} else {
dos.writeFloat((float) base);
}
}
for (GeodeticPoint point : pointList) {
if (point != null) {
dos.writeFloat((float) FastMath.toDegrees(point.getLongitude()));
} else {
dos.writeFloat((float) base);
}
}
for (GeodeticPoint point : pointList) {
if (point != null) {
dos.writeFloat((float) point.getAltitude());
} else {
dos.writeFloat((float) base);
}
}
}
## Source code
The source code is available in DirectLocationWithDEM.java (package fr.cs.examples under src/tutorials)
[Top of the page](#top)
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Rugged initialization and direct location
This tutorial explains how to initialize Rugged and use it to geolocate a satellite image.
Let's imagine the sensor is a single line imager with 2000 pixels and 20° field of view,
oriented 10° off nadir. GPS and AOCS auxiliary data are available and provide us with a
list of positions, velocities and attitude quaternions recorded during the acquisition. By
passing all this information to Rugged, we will be able to precisely locate each point of
the image on the Earth. Well, not exactly precise, as this first tutorial does not use a
Digital Elevation Model, but considers the Earth as an ellipsoid. The DEM will be added in
a second tutorial: [Direct location with a DEM](./direct-location-with-DEM.html). The objective
here is limited to explain how to initialize everything Rugged needs to know about the sensor
and the acquisition.
## Sensor's definition
Let's start by defining the imager. The sensor model is described by its viewing geometry
(i.e. the line of sight of each physical pixel) and by its datation model.
### Line of sight
We need to define the line of sight (LOS) vector coordinates of each sensor pixel in the
satellite frame; X axis is parallel to the velocity vector in the absence of steering, Z is
pointing towards the Earth and Y is such that X,Y,Z forms a right-handed coordinate system.
For this we need the following packages
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import java.util.ArrayList;
import java.util.List;
import org.orekit.rugged.los.LOSBuilder;
import org.orekit.rugged.los.FixedRotation;
import org.orekit.rugged.los.TimeDependentLOS;
The raw viewing direction of pixel i with respect to the instrument is defined by the vector:
List<Vector3D> rawDirs = new ArrayList<Vector3D>();
for (int i = 0; i < 2000; i++) {
// 20° field of view, 2000 pixels
rawDirs.add(new Vector3D(0d, i*FastMath.toRadians(20)/2000d, 1d));
}
The instrument is oriented 10° off nadir around the X-axis, we need to rotate the viewing
direction to obtain the line of sight in the satellite frame
LOSBuilder losBuilder = new LOSBuilder(rawDirs);
losBuilder.addTransform(new FixedRotation("10-degrees-rotation", Vector3D.PLUS_I, FastMath.toRadians(10)));
Here we have considered that the viewing directions are constant with time, it is also possible to
have time-dependent lines-of-sight by using other transforms. It is also possible to append several
transforms between the raw directions and the final lines-of-sight.
TimeDependentLOS lineOfSight = losBuilder.build();
### Datation model
The datation model gives the line number in the image as a function of time, and vice-versa the
time as a function of the line number. Here we are using a linear datation model (line sampling
rate is constant)
We use Orekit for handling time and dates, and Rugged for defining the datation model:
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.rugged.linesensor.LinearLineDatation;
AbsoluteDate absDate = new AbsoluteDate("2009-12-11T10:49:55.899994", TimeScalesFactory.getGPS());
LinearLineDatation lineDatation = new LinearLineDatation(absDate, 1d, 20);
The LinearLineDataion class is instanciated with 3 arguments: the first is the reference date,
the second is the line number at the reference date, and the last argument is the line rate (20
lines per second in this example) .
Note that Orekit can handle many different time scales through TimeScalesFactory, so we do not
need to worry about conversion.
### Line sensor
With the LOS and the datation now defined , we can initialize a line sensor object in Rugged:
import org.orekit.rugged.linesensor.LineSensor;
LineSensor lineSensor = new LineSensor("mySensor", lineDatation, Vector3D.ZERO, lineOfSight);
The first parameter is the nickname of the sensor. It is necessary because we can define multiple
sensors (useful for an imager with several spectral channels or detector arrays). The third argument
is the sensor position relative to the centre of the satellite reference frame. Here it is set to 0.
## Satellite position, velocity and attitude
As input to Rugged, we will need to pass sufficient information to describe the position and
orientation of the platform during the acquisition. In our example, the list of positions, velocities
and quaternions are hard-coded. In real life, we would extract GPS and AOCS data from the satellite
auxiliary telemetry.
Note that for simulation purpose, we could also use Orekit to simulate the orbit. It offers very
convenient functions to propagate sun-synchronous orbits with yaw steering compensation (typical
orbits for Earth Observation satellites).
### Reference frames
Rugged expects the positions (unit: m), velocities (unit: m/s) and quaternions to be expressed in an inertial frame.
All standard inertial and terrestrial frames are implemented in Orekit, so we just need to specify
which frames we are using and convert if necessary.
Conversion from inertial to Earth-rotating frame is transparent to the user and is based on the most
recent precession/nutation model on top of which corrections published by the IERS are applied. IERS
bulletins and other physical data are provided within the orekit data folder. There are several ways
to configure Orekit to use this data. More information is given
[here](../configuration.html)
In our application, we simply need to know the name of the frames we are working with. Positions and
velocities are given in the ITRF terrestrial frame, while the quaternions are given in EME2000
inertial frame.
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.utils.IERSConventions;
Frame eme2000 = FramesFactory.getEME2000();
boolean simpleEOP = true; // we don't want to compute tiny tidal effects at millimeter level
Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, simpleEOP);
### Satellite attitude
The attitude quaternions are grouped in a list of TimeStampedAngularCoordinates objects:
import org.orekit.utils.TimeStampedAngularCoordinates;
List<TimeStampedAngularCoordinates> satelliteQList = new ArrayList<TimeStampedAngularCoordinates>();
Each attitude sample (quaternion, time) is added to the list,
AbsoluteDate attitudeDate = new AbsoluteDate(gpsDateAsString, TimeScalesFactory.getGPS());
Rotation rotation = new Rotation(q0, q1, q2, q3, true); // q0 is the scalar term
Vector3D rotationRate = Vector3D.ZERO;
Vector3D rotationAcceleration = Vector3D.ZERO;
TimeStampedAngularCoordinates pair = new TimeStampedAngularCoordinates(attitudeDate, rotation, rotationRate, rotationAcceleration);
satelliteQList.add(pair);
where, for instance, gpsDateAsString is set to "2009-12-11T10:49:55.899994"
### Positions and velocities
Similarly the positions and velocities will be set in a list of `TimeStampedPVCoordinates`. Before being
added to the list, they must be transformed to EME2000:
import org.orekit.utils.TimeStampedPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.frames.Transform;
List<TimeStampedPVCoordinates> satellitePVList = new ArrayList<TimeStampedPVCoordinates>();
AbsoluteDate ephemerisDate = new AbsoluteDate(gpsDateAsString, TimeScalesFactory.getGPS());
Vector3D position = new Vector3D(px, py, pz); // in ITRF, unit: m
Vector3D velocity = new Vector3D(vx, vy, vz); // in ITRF, unit: m/s
PVCoordinates pvITRF = new PVCoordinates(position, velocity);
Transform transform = itrf.getTransformTo(eme2000, ephemerisDate);
PVCoordinates pvEME2000 = transform.transformPVCoordinates(pvITRF);
satellitePVList.add(new TimeStampedPVCoordinates(ephemerisDate, pvEME2000.getPosition(), pvEME2000.getVelocity(), Vector3D.ZERO));
## Rugged initialization
Finally we can initialize Rugged. It looks like this:
import org.orekit.rugged.api.AlgorithmId;
import org.orekit.rugged.api.BodyRotatingFrameId;
import org.orekit.rugged.api.EllipsoidId;
import org.orekit.rugged.api.InertialFrameId;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.api.RuggedBuilder;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.CartesianDerivativesFilter;
Rugged rugged = new RuggedBuilder().
setAlgorithm(demAlgoId).
setDigitalElevationModel(demTileUpdater, nbTiles).
setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF).
setTimeSpan(acquisitionStartDate, acquisitionStopDate, tStep, timeTolerance).
setTrajectory(InertialFrameId.EME2000,
satellitePVList, nbPVPoints, CartesianDerivativesFilter.USE_P,
satelliteQList, nbQPoints, AngularDerivativesFilter.USE_R).
addLineSensor(lineSensor).
build();
Argh, that sounds complicated. It is not so difficult since we have already defined most of what is
needed. Let's describe the Rugged instance building process line by line:
As the Rugged top level object that will be used for all user interaction is quite involved and can be
built in several different ways, a [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern)
approach has been adopted. The builder itself is configured by calling dedicated setters for each
concept (Digital Elevation Model, intersection algorithm, trajectory, ...).
As all these concepts can be chained together, the setters themselves implement the
[fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) pattern, which implies each setter
returns the builder instance, and therefore another setter can be called directly.
The *setAlgorithm* setter specifies the intersection algorithm to use. As this tutorial is intended to be very
simple for a beginning, we choose to use directly the ellipsoid and not a real Digital Elevation Model,
so we can use `AlgorithmId.IGNORE_DEM_USE_ELLIPSOID` as the single parameter of this setter.
The *setDigitalElevationModel* setter specifies the Digital Elevation Model. In fact, as we decided to ignore the Digital
Elevation Model in this tutorial, we could have omitted this call and it would have worked correctly.
We preferred to let it in so users do not forget to set the Digital Elevation Model for intersection
algorithms that really use them. As the model will be ignored, we can put the parameters for this
setter to `null` and `0`. Of course if another algorithm had been chosen, null parameters would clearly
not work, this is explained in another tutorial: [Direct location with a DEM](./direct-location-with-DEM.html).
The *setEllipsoid* setter defines the shape and orientation of the ellipsoid. We use simple predefined enumerates:
`EllipsoidId.WGS84`, `InertialFrameId.EME2000`, but could also use a custom ellipsoid if needed.
The *setTimeSpan* setter is used to define the global time span of the search algorithms (direct and inverse
location). Four parameters are used for this: acquisitionStartDate, acquisitionStopDate,
tStep (step at which the pre-computed frames transforms cache will be filled), timeTolerance (margin
allowed for extrapolation during inverse location, in seconds. The tStep parameter is a key parameter
to achieve good performances as frames transforms will be precomputed throughout the time span using
this time step. These computation are costly because they involve Earth precession/nutation models to
be evaluated. So the transformed are precomputed and cached instead of being recomputed for each pixel.
However, if direct and inverse location are expected to be performed over a reduced time span (say a few
tens of seconds), precomputing the transforms over half an orbit at one millisecond rate would be a
waste of computing power. Typical values are therefore to restrict the time span as much as possible
to properly cover the expected direct and inverse location calls, and to use a step between one millisecond
and one second, depending on the required accuracy. The exact value to use is mission-dependent. The
final timeTolerance parameter is simply a margin used before and after the final precomputed transforms to
allow a slight extrapolation if during a search the interval is slightly overshoot. A typical value is
to allow a few images lines so for example a 5 lines tolerance would imply computing the tolerance as:
timeTolerance = 5 / lineSensor.getRate(0)).
The *setTrajectory* setter defines the spacecraft evolution. The arguments are the list of time-stamped positions and
velocities as well as the inertial frame with respect to which they are defined and options for interpolation:
number of points to use and type of filter for derivatives. The interpolation polynomials for nbPVPoints
without any derivatives (case of `CartesianDerivativesFilter.USE_P`: only positions are used, without velocities)
have a degree nbPVPoints - 1. In case of computation with velocities included (case of
`CartesianDerivativesFilter.USE_PV`), the interpolation polynomials have a degree 2*nbPVPoints - 1. If the
positions/velocities data are of good quality and separated by a few seconds, one may choose only a few points
but interpolate with both positions and velocities; in other cases, one may choose more points but interpolate
only with positions. We find similar arguments for the attitude quaternions.
The last setter used, *addLineSensor*, registers a line sensor. As can be deduced from its prefix (`add` instead of `set`), it
can be called several time to register several sensors that will all be available in the built Rugged instance.
We have called the method only once here, so we will use only one sensor.
After the last setter has been called, we call the `build()` method which really build the Rugged instance
(and not a RuggedBuilder instance has the setter did).
Rugged takes into account by default some corrections for more accurate locations:
* light time correction (compensates or not light time between ground and spacecraft).
* aberration of light correction (compensates or not aberration of light, which is velocity composition between light and spacecraft when the light from ground points reaches the sensor).
Not compensating the delay or the velocity composition are mainly useful for validation purposes against system
that do not compensate it. When the pixels line of sight already includes the aberration of light correction,
one must obviously deactivate the correction.
If those corrections should be ignored, some other setters must be inserted before the call to `build()`:
setXxxx().
setLightTimeCorrection(false).
setAberrationOfLightCorrection(false).
build();
The various setters can be called in any order. The only important thing is that once a Rugged instance
has been created by calling the `build()` method, it is independent from the builder so later calls
to setters will not change the build instance. In fact, it is possible to create a builder, then
call its `build()` method to create a first Rugged instance, and then to modify the builder configuration
by calling again some of the setters and building a second Rugged instance from the new configuration.
This allows to perform comparisons between two different configurations in the same program and without
having to recreate everything. For instance, one can procede in three steps like this:
RuggedBuilder ruggedBuilder = new RuggedBuilder().
setAlgorithm(xxxx).
[ ... some setters ...]
setTrajectory(xxxx);
Then add the desired sensor(s):
ruggedBuilder.addLineSensor(lineSensor);
And create the Rugged instance:
Rugged rugged = ruggedBuilder.build();
## Direct location
Finally everything is set to do some real work. Let's try to locate a point on Earth
for upper left point (first line, first pixel):
import org.orekit.bodies.GeodeticPoint;
Vector3D position = lineSensor.getPosition(); // This returns a zero vector since we set the relative position of the sensor w.r.t. the satellite to 0.
AbsoluteDate firstLineDate = lineSensor.getDate(0);
Vector3D los = lineSensor.getLOS(firstLineDate, 0);
GeodeticPoint upLeftPoint = rugged.directLocation(firstLineDate, position, los);
The line number can have negative values; the associated date must belong to the time span given when building Rugged with setTimeSpan(acquisitionStartDate, acquisitionStopDate,...).
Otherwise a RuggedException will be thrown.
The pixel number must be given between 0 and the (Sensor pixel size – 1); in our example between 0 and 1999.
Otherwise an ArrayIndexOutOfBoundsException will be thrown.
## Source code
The source code is available in DirectLocation.java (package fr.cs.examples under src/tutorials)
[Top of the page](#top)
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<a name="top"></a>
# Inverse Location
The aim of this tutorial is to compute the inverse location of a point on Earth
in order to give the sensor pixel, with the associated line, seeing this point.
We will also explain how to find the date at which sensor sees a ground point,
which is a kind of inverse location only focusing on date.
## Inverse location of a point on Earth
The initialization of Rugged is similar as in the [Direct location](./direct-location.html) tutorial up to rugged initialization..
### Point defined by its latitude, longitude and altitude
Once Rugged initialized, one can compute the line number and the pixel number of a point defined by its Geodetic coordinates:
import org.orekit.bodies.GeodeticPoint;
import org.orekit.rugged.linesensor.SensorPixel;
GeodeticPoint gp = new GeodeticPoint(latitude, longitude, altitude);
SensorPixel sensorPixel = rugged.inverseLocation(sensorName, gp, minLine, maxLine);
where minLine (maxLine, respectively) is the minimum line number for the search interval (maximum line number, respectively).
The inverse location will give the sensor pixel number and the associated line number
seeing the point on ground.
**In case the point cannot be seen between the prescribed line numbers, the return result is null.
No exception will be thrown in this particular case**.
### Point defined by its latitude and longitude (no altitude)
Similarly, one can compute the line number and the pixel number of a point defined solely
by its latitude en longitude. The altitude will be determined automatically with the DEM.
SensorPixel sensorPixel = rugged.inverseLocation(sensorName, latitude, longitude, minLine, maxLine);
## Date location
Once Rugged initialized, one can compute the date at which sensor sees a point on Earth.
### Point defined by its latitude, longitude and altitude
For a point defined by its Geodetic coordinates:
AbsoluteDate dateLine = rugged.dateLocation(sensorName, gp, minLine, maxLine);
### Point defined by its latitude and longitude (no altitude)
Similarly, for a point defined solely by its latitude en longitude (altitude determined automatically with the DEM):
AbsoluteDate dateLine = rugged.dateLocation(sensorName, latitude, longitude, minLine, maxLine);
## Determine the min/max lines interval
Rugged provides a way to determine a **very** rough estimation of the line using only
the position-velocities of the satellite. It assumes the position-velocities are regular enough and without holes.
OneAxisEllipsoid oneAxisEllipsoid = ruggedBuilder.getEllipsoid();
Frame pvFrame = ruggedBuilder.getInertialFrame();
RoughVisibilityEstimator roughVisibilityEstimator= new RoughVisibilityEstimator(oneAxisEllipsoid, pvFrame, satellitePVList);
One can compute the approximated line with the rough visibility estimator:
AbsoluteDate roughLineDate = roughVisibilityEstimator.estimateVisibility(gp);
double roughLine = lineSensor.getLine(roughLineDate);
The result will never be null, but may be really far from reality if ground point is away from trajectory.
With this rough line, taken some margin around (for instance 100), one can initialize
the min/max lines as search boundaries for inverse location, taken into account sensor min and max lines:
int minLineRough = (int) FastMath.max(FastMath.floor(roughLine - margin), sensorMinLine);
int maxLineRough = (int) FastMath.min(FastMath.floor(roughLine + margin), sensorMaxLine);
then one can compute the inverse location:
SensorPixel sensorPixel = rugged.inverseLocation(sensorName, gp, minLineRough, maxLineRough);
## Source code
The source code is available in InverseLocation.java (package fr.cs.examples under src/tutorials)
[Top of the page](#top)
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Calling Rugged from Matlab
Examples of direct and inverse location were provided by the Centre de Techniques Spatiales of the Algerian Space Agency.
Under `src/site/resources/sources/matlab-examples/` :
* Direct location: `DirectLocation.m`
* Inverse location: `InverseLocation.m`
* Function to parse a DIMAP file: `dim2rugged.m`
If you have any question about the examples, please contact issam.boukerch@yahoo.fr, researcher at the CTS.
<!--- Copyright 2013-2022 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
src/site/resources/images/DEM-tiles-overlap.png

9.2 KiB

src/site/resources/images/Earth_FlatVsRugged.gif

86.8 KiB

src/site/resources/images/RuggedExplained.png

15.2 KiB

src/site/resources/images/aberration-of-light-correction.png

26 KiB

src/site/resources/images/flat-body-interpolation-error.png

137 KiB

src/site/resources/images/ignoring-EOP-1996.png

15.3 KiB

src/site/resources/images/ignoring-EOP-2010.png

11.6 KiB

src/site/resources/images/light-time-correction.png

24.1 KiB

src/site/resources/images/logo_cs_group.png

19.1 KiB

src/site/resources/images/orekit-logo.png

21.4 KiB

File added