# `mapproj`
Implementation of (a part of) map projections defined in the [FITS World Coordinate System (WCS)](https://fits.gsfc.nasa.gov/fits_wcs.html).
[](https://crates.io/crates/mapproj)
[](https://crates.io/crates/mapporj)
[](https://docs.rs/mapproj/)
Purpose
-------
The original purpose was mainly to add projections and to support the display of FITS images in
[Aladin Lite V3](https://aladin.cds.unistra.fr/AladinLite/).
Now, this library is also used in the display of HEALPix density maps (Skymaps),
of Multi Order healpix Maps (MOMs) and of Multi Order Coverage maps (MOCs)
in the [cds-healpix-rust](https://github.com/cds-astro/cds-healpix-rust)
and [cds-moc-rust](https://github.com/cds-astro/cds-moc-rust) projects.
Disclaimer
----------
This library does not support FITS parsing and keywords analysis.
For such features, see the [fits-rs](https://github.com/cds-astro/fitsrs)
and [wcs-rs](https://github.com/cds-astro/wcs-rs) projects by Matthieu Baumann.
Details
-------
Contrary to the [WCS paper](https://arxiv.org/pdf/astro-ph/0207413.pdf),
and following a previous work by F. Ochsenbein, we use the vernal point
`(1, 0, 0)` as default projection center/origin.
For zenithal projections, we thus project on the yz-plane
using the euclidean coordinates instead of the equatorial coordinates.
Changing the projection center corresponds to a simple 3x3 matrix multiplication
of the euclidean coordinates.
This work has been first done internally in 2017 (still by F.-X. Pineau),
in Java, to support more projections in Aladin Desktop (not released yet, not public yet).
F. Ochsenbein previously implemented TAN, STG, SIN, ZEA, ARC, AIT, SFL, MER and CEA
(for lambda=1, i.e. Lambert's projection) in its AstroCoo library.
Example
-------
Given the following FITS cards:
```bash
CTYPE1 = 'RA---SIN'
CTYPE2 = 'DEC--SIN'
CRPIX1 = 382.00001513958 / reference pixel in X coordinate
CRPIX2 = 389.500015437603 / reference pixel in Y coordinate
CRVAL1 = 183.914583333 / RA of reference position (degrees)
CRVAL2 = 36.3275 / DEC of reference position (degrees)
WCSDIM = 2
CD1_1 = -2.7777777349544E-4
CD2_2 = 2.77777773495436E-4
CDELT1 = -2.7777777349544E-4 / Redundancy with CD1_1, we ignore it
CDELT2 = 2.77777773495436E-4 / Redundancy with CD2_2, we ignore it
```
```rust
// Imports
use mapproj::{
CenteredProjection, ImgXY, LonLat
img2lonlat::Img2LonLat,
img2proj::ImgXY2ProjXY,
zenithal::sin::Sin,
};
// Define constants
let crpix1 = 382.00001513958_f64;
let crpix2 = 389.500015437603_f64;
let crval1 = 183.914583333_f64;
let crval2 = 36.3275_f64;
let cd11 = -2.7777777349544e-4_f64;
let cd22 = 2.77777773495436e-4_f64;
// Set the projection
let mut proj = CenteredProjection::new(Sin::default());
let proj_center = LonLat::new(crval1.to_radians(), crval2.to_radians());
proj.set_proj_center_from_lonlat(&proj_center);
let img2proj = ImgXY2ProjXY::from_cd(crpix1, crpix2, cd11, 0.0, 0.0, cd22);
let img2lonlat = Img2Celestial::new(img2proj, proj);
// We could have set the projection center here instead of previously:
// img2lonlat.set_proj_center_from_lonlat(proj_center);
// Use to project, unproject coordinates:
// - we choose on purpose position in the image of the projection center
let img_coo_input = ImgXY::new(382.00001513958, 389.500015437603);
let lonlat = img2lonlat.img2lonlat(&img_coo_input).unwrap();
assert!((lonlat.lon() - proj_center.lon()).abs() < 1e-14);
assert!((lonlat.lat() - proj_center.lat()).abs() < 1e-14);
let img_coo_input = img2lonlat.lonlat2img(&lonlat).unwrap();
assert!((img_coo_input.x() - img_coo_input.x()).abs() < 1e-14);
assert!((img_coo_input.y() - img_coo_input.y()).abs() < 1e-14);
```
To Do list
----------
* [X] Add conic projections (`COD`, `COE`, `COO`, `COP`)
* [X] Add cylindrical projections (`CAR`, `CEA`, `CYP`, `MER`)
* [X] Add hybrid projection (`HPX`)
* [X] Add pseudo cylindrical projections (`AIT`, `MOL`, `PAR`, `SFL`)
* [X] Add zenithal projections (`AIR`, `ARC`, `AZP`, `FEYE`, `NCP`, `SIN`, `STG`, `SZP`, `TAN`, `ZEA`, `ZPN`)
* [ ] Add polyconic and pseudoconic projections (`BON, PCO`)?
* [ ] Add quad cube projections (`TSC`, `CSC`, `QSC`)?
* [X] Add bounds to each projection
* [ ] Make individual implementations of `is_in_proj_bounds` to avoid useless computations
(but will introduce redundancy with unproj)
* [ ] Check and possibly document constants to be added to match WCS projection bounds
* [X] Support `CRPIX` + `CD` convention
* [X] Support `CRPIX` + `PC` + `CDELT` convention
* [X] Support `CRPIX` + `CROTA` + `CDELT` convention
* [ ] Add support for LONPOLE?
* [ ] Test and complete SIP
* [X] Add to git the pdf document containing computational details
* [ ] Check, fix typo, enrich the pdf document containing computational details
* [ ] Add generation of projection files and plots (like in the Java lib)
Acknowledgements
----------------
If you use this code and work in a scientific public domain
(especially astronomy), please acknowledge its usage and the
[CDS](https://en.wikipedia.org/wiki/Centre_de_donn%C3%A9es_astronomiques_de_Strasbourg)
who developed it.
It may help us in promoting our work to our financiers.
License
-------
Like most projects in Rust, this project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.
Contribution
------------
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.