Feature request: Freeform stroke offset
Hey, I found iShape yesterday - this is great set of tools you're creating. One of the usecases I have is something similar to the stroke demo, but not for a plain path, but for a non continuous set of lines, where some happen to join up and the offset can be different between the various lines. Is that something I could accomplish with iOverlay either directly from rust or from js with the wasm implementation? I could stroke all individual lines and then union them, but then I don't get the miter joins.
I guess I could individually stroke all pairs, which are connected and then union all those. Would only work if here's only two lines joined on a point. Does that make sense?
Hi, thanks for the question! Glad to hear that iOverlay useful. Are you asking about path to path join feature to resolve end to end joint problem?
iOverlay is already support multi-pathes but without pre-union it.
let paths = [
vec![[0.0, 0.0], [5.0, 0.0]],
vec![[0.0, 0.0], [5.0, -5.0]]
];
let style = StrokeStyle::new(2.0)
.start_cap(LineCap::Butt)
.end_cap(LineCap::Butt);
let shapes = paths.stroke(style, false);
assert_eq!(shapes.len(), 1);
assert_eq!(shapes[0].len(), 1);
assert_eq!(shapes[0][0].len(), 8);
It will prefectly work with LineCap::Round but not with LineCap::Butt. A missed pink part on the image.
I don't now how to help here. The first idea is union all paths but what if we have a several common ends?
It will prefectly work with LineCap::Round but not with LineCap::Butt. A missed pink part on the image.
Yeah, that pink part was what I was curious about. With rounded caps this would be easy, but that doesn't work for me. The usecase is drawing floorplans from just some source data and walls don't just form clear polygons. I still need those walls to be joined up using miter joins (with offset) like e.g. shown here: https://stackoverflow.com/questions/67166198/algorithm-for-miter-joins-on-multiple-lines
Ok, now your problem is much clearer.
It's too specific for a general boolean library, but you can implement it by hand, it's not so complex:
- Run a global offset with Bevel joins
- At each star node, collect all connected segment ends and compute their offset (green) points
- Take the convex hull of these offset points and union it with the global offset result
Since the green poins offsetted by the same radius, convex hull can be getted just by sorting all vectors by angle between each other
... Huh, this problem is kind of related to thickening road center-lines and figuring out the shared junction section. I worked on this a bunch years ago -- https://a-b-street.github.io/docs/tech/map/geometry/index.html#part-2-counting-coup describes the very messy implementation, https://osm2streets.org lets you try out the result. It has so many bugs. But thinking through the 3 step process above, I could see how that might work really well.
@LostKobrakai, if you do end up implementing anything like this, please do share, I'd love to try it against OSM road data too.
I've now gone a different way – closer to the posted stack overflow answer. I've switched to a graph structure, where I iterate all nodes and then order all edges related to it by angle of the vector between the current node and the one the edge points to. Then I calculate the rhombus between the left / right offset lines of each consequtive pair of edges keeping relation to which edges the calculated vector relates to. Then grouping vectors back up by wall gives me their respective polygon. Doesn't yet support miter offsets, but that should also be possible by returning not just a single vector from the rhombus calculation, but multiple where an offset shall be applied.