-
Notifications
You must be signed in to change notification settings - Fork 944
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
removing jsts dependency #88
Comments
Completely agree. I am using jsts very reluctantly at this point, as I have found it pretty challenging to debug and its size really hurts client-side viability (I personally only use turf in node.js, so this is less of a problem for me). Nonetheless, using it allowed me to wrap a high level api around a set of features that would have taken me months to develop on my own. To get off jsts, we would need the following (I think this is a complete list):
I attempted to do a bit of reverse engineering from jsts, but these algorithms are pretty complex, and the fact that jsts uses a very "enterprisey" style makes it difficult to just pluck out the relevant bits. It might be much easier to borrow some ideas (or code) from one of the many geometry libraries out there such as jsclipper. It might not be the cleanest way to implement these features, but it has worked for others (like the bezier function, which was adapted from a canvas library) and I try not to let perfect be the enemy of good. TLDR: I really want to do this, but am a bit swamped at the moment. I am getting close to feature completeness though, so I may have time to circle back to this in a couple months if no one else decides to tackle it before then. |
I have started porting jsclipper to node (the current implementation is heavily tied to the browser and contains a lot of code that optimizes it for various browsers). Minified, I currently have it at 93kb, which is a lot better than the 500kb+ of jsts. This issue has become a big deal due to other issues relating to jsts using globals that blow up the browserify build for turf. Being clunky in the browser is one thing, but not working at all is unacceptable IMO. One big plus side to this approach is that jsclipper is blazing fast, and on top of that it has more buffer options than just about any "gis" type lib I have seen. The downside is that the underlying code in turf will need to transform geojson to the jsclipper data structure, then transform the results back to geojson. I don't see this as a huge issue though in lieu of an existing geojson-oriented module... or me knowing how the hell to do it myself :) The jsclipper code is a bit odd (ported from a C++, C#, & Delphi lib!), but still seems far more easy to read than the equivalent jsts internals, so this should not hurt "debugability" too much by comparison. Since I have started really using turf with the jsts dependencies, I have found it almost impossible to figure out what is going on when something goes wrong in jsts, which seems to be a symptom of a near direct Java to Javascript transformation with not much consideration of idioms. Jsts probably just needs some love, but I think the goal was simply a minimal port, so we might as well build something geared towards this problem space. TLDR: Solution to this issue coming ASAP |
I have successfully forked jsClipper to a node compatible version: https://github.com/morganherlocker/clipsy Also, I have completed a conversion module for getting from geojson to jsclipper data and back. https://github.com/morganherlocker/clipsy-geojson The results look very promising, and I think I now have everything I need to implement this within turf for the functions listed above. |
Wow, jsClipper is some insane code |
unsolicited feedback: in general I'd love to see more small modules for doing geo stuff and less grab-bags. e.g. there are nice simplification implementations in turf, topojson and mapshaper but they are part of much bigger coarse grained frameworks which doesn't work as well with browserify. it might seem like more work to publish 30 modules instead of 1 but in practice I've tried both approaches many times and when you try and build something complex having fine grained dependencies (small modules) helps out a lot |
👍 to that - the good thing is that turf right now is pretty decoupled internally so it's a good fit for splitting into little bits. |
@maxogden Unsolicited feedback is usually the best kind ;) I tend to prefer the small module approach as well, and have thought about it from the beginning with turf. As @tmcw mentioned, the code structure is about as simple as it gets. Index.js is just a list of functions being gathered up, and if each of them pointed out to separate installed modules, it would work the same. At the same time, I do think there is a balance between a framework that curates a set of utilities, and the more granular approach that lets people in the know build things however they want. Perhaps a compromise might be to break out submodules automatically as part of each release. There would still be the full turf module, but if you wanted the minimum dependencies, you could just use turf-isoband, turf-smooth, turf-buffer, etc. I have never tried this approach, so it may be totally zany. Any thoughts or suggestions would be appreciated. Also, my main reason for wanting a single point of development (even with the submodule options) is that it makes testing much easier, and it minimizes duplicated browserify dependencies if you needed to use multiple submodules. The actual turf code accounts for a pretty small percentage of the browserified file, especially in comparison to jsts and topojson. I am pretty green though, and I am open to advice on this. |
I like the hybrid approach you proposed, it enables both modular and old school consumers. Re: duplicated subdependencies, In a scenario like this I think its best to attempt to minimize the number of shared dependencies. Implementations of low-level geo algorithms are probably a good place to start by breaking out into individual modules that don't have any dependencies, and then requiring those in the higher level turf APIs. It's the conflation of these low-level algorithms and the high level APIs that is the most commonly frustrating thing that I see frameworks doing. |
@maxogden, @tmcw Quick update: I am coming into the final stretch of fully modularizing turf. On the dependency front:
This has all been quite a bit of work, but I think the payoff will be huge. After the modules are complete:
To be honest, I was a bit skeptical of the modular approach for this at first. Now that most of the work is done, I am optimistic that this will allow for the most flexible usage, which should lead to an increase in usability, and make it easier to contribute. |
@morganherlocker I think https://github.com/Raynos/mercury is a pretty cool example of a modular 'framework'. You can also run highly modular things on testling CI or travis pretty easily |
Adding to the 3.0.0 milestone: @morganherlocker can you top-edit this so that it describes the current overall state of this task - which turf modules still need de-JSTS'ing and what algorithms are required to do it, and what state are those tasks in? |
Any news? |
We are only using import turfPoint from 'turf-point';
import turfBuffer from 'turf-buffer';
import turfInside from 'turf-inside';
type TypePoint = [number, number];
/**
* Check if `point` is within the circle with center `center` and radius `radius`
*/
export default (point: TypePoint, center: TypePoint, radius: number) : boolean => {
let centerPoint,
circleAroundCenter,
insidePoint;
centerPoint = turfPoint(center);
insidePoint = turfPoint(point);
circleAroundCenter = turfBuffer(centerPoint, radius, 'meters');
return turfInside(insidePoint, circleAroundCenter);
}; Is there a away to do it without |
turf-buffer depends on jsts, so, unfortunately, no |
How would such a thing be called? "A function to generate a polygon describing a circle of certain radius using points as latitude and longitude" I will do my research and see if I can put one together. |
For geodesic circles, you can use the |
I just realised that since I simply need to check if a point is within a circle, all I need to do is check if distance from centre of the circle to the target is lesser than the radius, i.e. import turfPoint from 'turf-point';
import turfDistance from 'turf-distance';
import turfInside from 'turf-inside';
type TypePoint = [number, number];
/**
* Check if `point` is within the circle with center `center` and radius `radius`
*/
export default (point: TypePoint, center: TypePoint, radius: number) : boolean => {
let centerPoint,
insidePoint;
centerPoint = turfPoint(center);
insidePoint = turfPoint(point);
return turfDistance(centerPoint, insidePoint, 'kilometers') * 1000 < radius;
}; |
I'm moving this out of the 3.0.0 milestone. Removing JSTS continues to be Turf's excalibur. Whoever completes this task earns first-dibs when my mom sends cookies to the office. |
👍 For anyone up for the challenge, I can verify that the cookies are very good. |
Couple questions for would-be seekers of the cookie:
@tcql Is this still accurate? If so, are these outstanding issues atomic, squashable bugs, or more like high level revisions/refactors of the g-h module?
Is this the place to look? |
correct @anandthakker. The most promising offset/buffer algorithm has been http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf I've also looked into straight skeleton offset algorithms, but I have not had much luck getting any working, since the skeleton algorithm is a challenging lift by itself. |
@anandthakker We're looking into some alternatives to degeneracy handling that would simplify and theoretically get rid of remaining failures in GH. @mourner is using some tangential approaches to work on polygon fixing (kind of similar to ST_MakeValid), which could easily help us ditch remaining degeneracy issues.
per ☝️ ☝️, it's more the latter |
Current state of jsts in webpack: jsts has a |
It's not so much the filesize that worries me, the last time I attempted to use these so called code splitted modules I had tons of errors that depend on other external Also, there's been a few reported issues with handling MultiPolygon geometries (#702, #674). Instead of having a massive |
While I would welcome something more modern and modular (and in some cases faster) to replace On "code splitting" (or rather dead code elimination or tree shaking) it should at least work. I do it with several internal projects using |
I've sent PR that mostly implements buffer without JSTS: rowanwins/geojson-buffer#4 Hope it helps migrating out of it |
I use the JTS The problem is that I can't build the customized lib inside turf-buffer, because of the strict building rules: the customized lib must be build with buble but MonorepoLint check enforces to use the rollup configuration from the root directory. What is the best way to deal with the issue described above in order to contribute the new code? Short stats
You can find the current state of the code here: |
@rycgar thanks for doing that work. When you say you can't do the build you mean a separate build process that strips out the turf-jsts build? Because I was able to build I did some test builds with microbundle, esentially i just imported Current import of buffer as it stands with Changing out @rycgar branch with the custom build: Using @rycgar custom build brings down the final bundle size used in the test app to less than half. My recommendation would be as a minimum we just move to using |
@JamesLMilner thank you for your effort. Sorry for the late response, I am kind of busy right now :) I am able to build just the turf-buffer module, however, building the whole turf project (with the refactored turf-jsts lib) fails because of the MonorepoLint check that enforces to use the rollup configuration from the root directory. Build log from your PR:
With some hacks, it is possible to build it, but I do not want to mess with the implemented building procedure. I hope for a solution or a hint towards the solution, how we can make it possible. |
Looks like JSTS is still used in:
Is a) removing JSTS still a goal, and b) if yes do we want to track its removal from these last few packages in individual issues? Perhaps labelled so they stand a better chance of being picked up as people are working in those modules? |
I see some TODO-like comments in the source https://github.com/morganherlocker/turf/blob/4a4772433b3deb6ae5f8dc9d24afbdd9c6555911/lib/erase.js#L4 but it seems like a good idea to veer away from too much jsts lineage since it's a rather huge project with its own lingo and internal formats.
Evaluate this for an implementation guide:
https://github.com/akavel/polyclip-go/blob/master/clipper.go
The text was updated successfully, but these errors were encountered: