-
Notifications
You must be signed in to change notification settings - Fork 161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New graphics pipeline? #78
Comments
Re #3, especially that you're using terms such as sources and sinks: for one-off pipeline executions, the promise style may be sufficient. But if the pipeline isn't just for a singular execution, but instead considers updates over time, then an FRP inspired library such as most.js or the even more compact flyd would be a more natural fit. A hacky example for what I mean by updates over time is here, it uses the core of flyd for the data propagation (but the experiment ending up totally not idiomatic D3; wasn't a goal here). In general, some folks find RxJS, most.js, xstream and similar libraries more natural and composable than promises, and better at error handling. André Staltz and Ben Lesh come to mind. Some personal notes on the utility of a data flow concept are here. |
Maybe add that transforms should offer an .invert() function (by default we could use numerical interpolation, w/o needing an explicit setup). [ I'm very excited by this as I already have a few real use cases in mind, such as 2D linear transforms (the plane is shown in perspective and support "vertical" bars of data); the "fisheye" projection http://bl.ocks.org/Fil/1b574a4185a04273de47b49591243102 ; the Bertin 1953 projection; and exceptions to clipping (where you clip at an angle but allow a small "ear" of interesting land to get in though it's a bit farther than the clip angle). |
My opinion is that the standard intermediate form for any geographic processing system which wants good performance should be cartesian (x, y, z) coordinates on the domain [–1, 1] × [–1, 1] × [–1, 1]. These make it easy to rotate, clip, build search trees, compute lengths and areas, project onto Gnomonic, orthographic, stereographic, etc. maps, and so on, without dealing with the same kinds of edge cases / singularities you get when working with a latitude/longitude grid, and without needing to constantly evaluate transcendental functions everywhere. For example, to find the distance between two points on a (assumed spherical) globe, you can find the straight-line distance in Cartesian coordinates d, and then take 2arcsin(d/2) to get the angular distance; depending on the precision required this can be approximated pretty cheaply. If such coordinates need to be compressed when you don’t want to represent each point as 3 double precision floats somewhere (e.g. if you want to send a giant polyline to a worker thread or save it to a file, and want to minimize I/O), a very computationally cheap and effective representation is to take the stereographic projection onto a plane, and then cut the resolution, e.g. to a pair of half-precision floats. Both the forward and inverse stereographic projections are extremely cheap, requiring only a few multiplications/additions and a single division operation per point. |
@Fil Good point about inverting transforms. If a transform only has a reference to its output sink, then there’s no way for it to encapsulate inversion… Hrm. @jrus That’s an interesting idea. I would guess it would be harder to reuse much of our existing implementation with that approach, but it might still be worth pursuing. |
I was able to implement multipass clipping using projection.preclip! See the geoPipeline here: |
Hi Mike. @mbostock For example here is two almost the same projections, it differs in distance parameter only: 2.140612617 vs 2.124627867.
Spent many hours trying to solve it. I use the example from here https://observablehq.com/@jjhembd/tilting-the-satellite, Tried different extra factors for preclip function, like Do you have any ideas how it could be fixed? |
@mrnix please open a new issue with a link to a notebook with the settings that actually fail. |
In September 2014, I started work on a modular geographic projection pipeline that would allow you to compose geometric transformations during rendering. For example:
Rather than having a monolithic projection that renders GeoJSON to a context (Canvas or SVG), the new modular rendering pipeline would have three types of objects: sources, transforms, and sinks. A source generates a sequence of geometry calls (e.g., polygonStart, lineStart, point…). A sink receives geometry calls. And a transform is both a source and a sink that transforms the input geometry to some output geometry. A pipeline is thus a source followed by zero or more transforms followed by a sink.
Example sources:
Example transforms:
Example sinks:
Open Questions:
Where would you convert from degrees to radians? Another transform? Or would all the sinks and transforms that operate on spherical geometry require degrees as input, trading performance for convenience?
Is everything immutable? Do you have to rebuild the entire pipeline when anything changes? Will that be slow?
Is there a way to avoid massive nested function calls when constructing a pipeline, say using a source.then?
Is there a way to make it less verbose? Are we going to continue to provide convenience functionality such as d3.geoArea(feature) in addition to d3.geoSphericalAreaSink? Is there a more concise way to distinguish between objects that operate on planar versus spherical geometry (say using the “geom” rather than “geo” prefix)?
How do you retrieve values from sinks (e.g., when computing area)? Maybe there’s a sink.value function that you call after sending it geometry, and transform.value is implemented as a pass-through to the underlying sink?
Some of the work is here:
https://github.com/d3/d3/compare/graphics-pipeline
The text was updated successfully, but these errors were encountered: