Rust D3 Geo
Rust 2021 Edition.
This is a port d3-geo into RUST. Not all projection have been implemented and there are number of known bugs that I am activley working on.
Here is a list of the currently supported projections.
- AziumuthalEqualArea
- AzimuthalEquiDistant
- Equirectangular
- Gnomic
- Mercator
- Orthographic
- Stereographic
Examples
Examples are provided to help developers convert their existing javascript to rust. To run the example please follow the "Running the examples" below.
As a confidence building exercise, this demo shows a side by side comparison of the all the projections rendered by in both javascript and rust.
When to use the rust version of the library
The limits of the javascript library become obvious when developing interactive applications that process large datasets. For example the examples/globe applications operate on a 50m resolution map of the earth. On a desktop machine this is beyond the javascript version.
Current Status
The majority of the library has been ported along with the associated tests. The aim is to eventaully release this as a rust crate. but at the moment is this alpha grade software.
-
The recenter state-based API refacor is almost complete. Once fit_size_resampling() is reinstated the code-coverage metric will jump 10% back to the previous value of approx 82%
-
The API is not stabalised. If perfomance issues arise then the API will change. Additionaly I plan a final review to remove anything uneeded before making changes become complicated.
-
The clipping algorithm in clip/rejoin/mod.rs needs to be refactored. see The intersection Problem. Test coverage in that area is high so the algortihms is working but the data structures make extensive use of vectors ( heap objects ) containng references to other heap objects
Vec<Options<Rc<RefCell<_Intersection_>>>>
which is not performant.
Running the examples
-
node and npm installation guide
-
wasm-pack installation guide
To view the application either create a devleopment build, or construct a static-web site as follows
Start And Run A Development Build
git clone https://github.com/martinfrances107/rust_d3_geo.git
cd rust_d3_geo/examples/ring/
cargo build
npm install
npm start
The last command "npm run start" will automatically open your default browser at http:://localhost::8080
Building A Static Site
Much better performance can be acheived by bulding a static web site and viewing that direclty.
git clone https://github.com/martinfrances107/rust_d3_geo.git
cd rust_d3_geo/examples/ring
cargo build
npm run build
This creates a static HTML site in the dist/ directory.
To view the site you cannot just point you browser at a location of the form file:://home/user/alice/dist/index.html
By security reasons, browsers prevent HTML pages with WASM files from being viewed this way. You must host the site first.
A way forward here is to use a npm package called serve
sudo npm install --global serve
serve dist
If everything works you will be given a locaation to view
For example http:://localhost::3000
Benchmarking
Also rust_d3_geo_voronoi uses this library, and that project contains a benchmark which contains an exact port of a benchmark in d3-geo-voronoi . Based on that benchmark rust is 31% faster, or permits a 37% increase in throughput.
Future Multi thread support
-
rayon is rust's crate for multithread support. I have made extensive use of iterators when porting the code and rayon support the easy conversion of single threaded iterators to multithread iterators.
-
The Hashmaps - appear slow. Maybe I can get performace improvements by replacing them with B-tree collections?
Architecture discussion
There is an aspect of the design that needs review. It related to the best way to implement a doubly-linked list which has cross links between nodes. A full discusion can be found here
Coding Standard
-
Idomatic RUST, as defined by cargo clippy where possible.
-
No booleans as arguments to functions/methods, use two state enums instead. See "Reflect" as an example.
This allow for a clearer statement of intent :-
builder.reflect_y_set;
-
"Type-Driven API Design" is the preferred way of constructing state machines.
In the example below, when assembling a stream pipeline, connect() can only be called when the state is "Unconnected". The output type's STATE is "Connected".
The "Stream" trait is only implemented when the STATE is "Connected". By design, all code is prevented from calling line_start() or point() unless the object has been connected to another pipeline stage.
Unimplemented sections of the library.
I am trying to get a program of mine to run faster, but I want this to eventually be a true library port. So feel free to add suggestions to my todo list.
A complete list of all ported projections can be found in invert-test.rs. Out of the 15 distinct projections listed only 7 have been ported so far.
Other To-do's
Document API changes such as
- src/projection/clip_angle_reset()
- src/projection/clip_extent_clear()
Finally
todo.md contains a more detailed list