# `moc`
Read, write, create and manipulate HEALPix **M**ulti-**O**rder **C**overage maps (**MOC**s),
i.e. discretized geomatrical surfaces on the unit sphere.
[![](https://img.shields.io/crates/v/moc.svg)](https://crates.io/crates/moc)
[![](https://img.shields.io/crates/d/moc.svg)](https://crates.io/crates/moc)
[![API Documentation on docs.rs](https://docs.rs/moc/badge.svg)](https://docs.rs/moc/)
[![BenchLib](https://github.com/cds-astro/cds-moc-rust/actions/workflows/bench.yml/badge.svg)](https://github.com/cds-astro/cds-moc-rust/actions/workflows/bench.yml)
MOC Lib Rust, the Rust MOC library used in:
* [MOCPy](https://github.com/cds-astro/mocpy),
* [MOCli](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/cli);
* [MOCSet](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/set);
* [MOCWasm](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/wasm);
* [Aladin Lite V3](https://github.com/cds-astro/aladin-lite/tree/develop);
see the [Cargo.tom](https://github.com/cds-astro/aladin-lite/blob/develop/src/core/Cargo.toml) file.
MOC Lib Rust rely on the [CDS HEALPix Rust library](https://github.com/cds-astro/cds-healpix-rust).
## About
This Rust library implements the v2.0 of the [MOC standard](https://ivoa.net/documents/MOC/),
including (S-)MOCs, T-MOCs and ST-MOCs.
It also implements a still experimental F-MOC (F for Frequency).
MOC Lib Rust is used in:
* [MOCPy](https://github.com/cds-astro/mocpy), a Python wrapper to manipulate MOCs;
* a standalone command line tool [MOCli](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/cli) for linux, MacOS and Windows;
* a standalone command line tool [MOCSet](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/set) for linux, MacOS and Windows;
* a WASM library [MOCWasm](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/wasm) to be used in web browsers.
For tools able to display MOCs, see:
* the [Aladin Desktop](https://aladin.u-strasbg.fr/) sky atlas in Java (also supports MOC operations);
* [Aladin Lite](https://aladin.u-strasbg.fr/AladinLite/), "a lightweight version of the Aladin Sky Atlas running in the browser";
* [MOCPy](https://cds-astro.github.io/mocpy/) scripts, a python wrapper using the very same Rust MOC library.
## Release
The github [releases](https://github.com/cds-astro/cds-moc-rust/releases) section number
is the [MOCCli](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/cli),
[MOCSet](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/set)
and [MOCWasm](https://github.com/cds-astro/cds-moc-rust/tree/main/crates/wasm)
release number.
## Install/test
[Install rust](https://www.rust-lang.org/tools/install)
(and check that `~/.cargo/bin/` is in your path),
or update the Rust compiler with:
```bash
rustup update
```
Run tests (with or without seeing `stdout`):
```bash
cargo test
cargo test -- --nocapture
```
Run benches:
```bash
cargo bench
```
Build documentation
```bash
cargo doc --open
```
Build the library for fast test or final build
```bash
# Fast build (large not optimized file)
cargo build
# Optimized file
cargo build --release
```
## Particularities
* The core of this library is very generic
* We implemented lazy, streamed operations:
+ an operation between 2 MOCs takes in input 2 iterators and returns an iterator (**streaming**)
+ you can combine operations by combining iterators at no cost;
the process start when starting to iterate on the outermost iterator (**lazyness**)
```rust
// Signature of the Union operation between 2 2D-MOCs
pub fn or(
left_it: K1,
right_it: K2
) -> OrRange2Iter
where
T: Idx, // Type of the 1st quantity (e.g. u32 or u64)
Q: MocQty, // First quantity type, e.g Time
U: Idx, // Type of the 2nd quantity (e.g. u32 or u64)
R: MocQty, // Second quantity type, e.g Space (we use Hpx for HEALPix)
I1: RangeMOCIterator,
J1: RangeMOCIterator,
K1: RangeMOC2ElemIt,
I2: RangeMOCIterator,
J2: RangeMOCIterator,
K2: RangeMOC2ElemIt
```
## Possible Enhancements / Ideas
* [ ] Add operations on `RangeMOC2`
+ [X] `or`
+ [ ] `and`, `complement`, `fold`, ...
* [X] Implement a function dividing a disjoint MOCs into a list of joint MOCs
(tip: use the order and the flag of a BMOC, the flag telling is the cell has already been visited).
* [ ] Implement the compact notation (bits coding quad-tree traversal) for S-MOCs (binary + ASCII Base 64)
* [ ] Implement compact S-MOC: single z-order curve sorted array of indices with a 2 bits flag telling
whether the index is a single index, a range lower bound or a range upper bound
* [ ] Make a PostgresQL wrapper using e.g. [pgx](https://github.com/zombodb/pgx/)?
## WARNING about the STC-S to MOC function
STC-S parsing is ensured by the [STC crate](https://github.com/cds-astro/cds-stc-rust).
Current discrepancies between the STC standard and this implementation:
* The `DIFFERENCE` operation has been implemented as being a `symmetric difference`
+ why? probably because:
1. I am biased towards Boolean algebra, it as `XOR`
(exclusive `OR` or symmetric difference) but no `Difference`
2. I read parts of the STC standard after the STC-S implementation
3. `XOR` is already implemented in [cdshleapix](https://github.com/cds-astro/cds-healpix-rust), but `DIFFERENCE` is not.
+ has stated in the STC standard: `R1 – R2 = R1 AND (NOT R2))`;
but also: `R1 - R2 = R1 AND (R1 XOR R2)`, and
`XOR = (R1 OR R2) AND (NOT (R1 AND R2))` is more complex that `DIFFERENCE`
(so is worth having implented?).
* For `Polygon`: we do not use the STC convention
+ we support self-intersecting polygons
+ we generally return the smallest area polygon (use `NOT` to get its complement!)
+ one convention could be to use an additional (last) provided points as a control point
- note that for convex polygons, the control point could be the vertices gravity center
- in a GUI, a user could define the inner part of the polygon by a final click
+ why?
1. efficient algorithms dealing with polygons supports self-intersecting polygons
2. to support arbitrary defined polygons by a user clicking in a viewer such as Aladin or Aladin Lite
3. [cdshleapix](https://github.com/cds-astro/cds-healpix-rust) is based on self-intersecting polygons
* For `Box`: a position angle can be added as a last parameter, right after `bsize`.
So far, we reject STC-S having:
* a frame different from `ICRS`
* a flavor different from `Spher2`
* units different from `degrees`
## 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.
### Warning
The code is formatted using 2 tab spaces instead of the regular 4:
```bash
cargo fmt -- --config tab_spaces=2
```
## Acknowledgements
This work has been partly supported by the ESCAPE project.
ESCAPE - The **E**uropean **S**cience **C**luster of **A**stronomy & **P**article Physics **E**SFRI Research Infrastructures -
has received funding from the **European Union’s Horizon 2020** research and innovation programme under **Grant Agreement no. 824064**.