Skip to content
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

How to use Snap.path.intersection result #674

Open
zachstence opened this issue Jul 9, 2024 · 8 comments
Open

How to use Snap.path.intersection result #674

zachstence opened this issue Jul 9, 2024 · 8 comments

Comments

@zachstence
Copy link

zachstence commented Jul 9, 2024

Can anybody help me understand how to use the values returned from Snap.path.intersection? Specifically, what do t1, t2, bez1, and bez2 represent? I've read the docs, and they don't explain things very well (i.e., what is a "t value"? what is an "order number for a segment"?).

t1 and t2

My assumption was that these are ratios for how far along the paths the intersection points occur, as a ratio of their overall length.

bez1 and bez2

My assumption was that these are bezier curves (with the array elements being args to M {},{} C {},{} {},{} {},{}), but how do they relate to the intersections?

However, my assumptions don't seem to be correct based on this codepen. The subpath I generated doesn't line up with the intersection point, and the bezier curve is just the whole original path. How are these values computed/meant to be used?

@ibrierley
Copy link
Collaborator

Is there something specific you are trying to achieve with it ? I've tended to use them just for the overlapping parts eg https://svg.dabbles.info/snaptut-circlepath (press run). Also last answer at https://stackoverflow.com/questions/50011373/how-to-find-a-new-path-shape-from-intersection-of-svg-paths may help. It's a while since I've looked into this stuff, but if still stuck, I'll try and dig into the code.

@zachstence
Copy link
Author

Thanks for the response!

I'm trying to do what the Codepen is doing: Get a subpath of a path from the beginning to the intersection point.

Looks like that StackOverflow answer is doing a similar thing to me (assuming t values are a ratio of distance), but instead of using the whole path, they're stepping through each segment (bezier curve) of the path and using that path? Is that how t values are supposed to be used?

I'll try and use that method in my Codepen and see if it works.

@zachstence
Copy link
Author

Unfortunately didn't have much luck... I think I'm going to try an alternative approach to split paths into subpaths using PaperJS and approximation with straight lines.

If you have any guidance/knowledge on how the t values are used I'd greatly appreciate it! But if its too unfamiliar and would take a lot of effort, no worries either

@ibrierley
Copy link
Collaborator

I have a feeling it's something like the following...don't beat me up if I'm wrong or it doesn't make sense though :D

bez1 bezier of first path matching the intersect ?
bez2 bezier of 2nd path matching the intersect ?
t1 percentage of how far along the first path the intersect occurred ?
t2 percentage of how far along the second path the intersect occurred ?
x,y position of intersect
segment1 which segment element of the first path intersected ?
segment2 which segment element of the second path intersected ?

@zachstence
Copy link
Author

That is what I assumed too. That's what I'm doing in the Codepen (I think?) and the subpath doesn't line up with the intersection.

@ibrierley
Copy link
Collaborator

Sorry, yes, I see what you mean, I hadn't re-looked at the original post :). It does seem to work with certain values (I think)....which makes me scratch my head, so the point I'm not sure if I'm just misunderstanding it, or a bug (wondering if its funny with straight lines somehow..) So maybe PaperJS or something would be a better alternative.

@ibrierley
Copy link
Collaborator

ibrierley commented Jul 12, 2024

Just out of interest, I dug out an old email I wrote to myself oddly from searching on snap intersection, I haven't gone throught it all.... I've posted the code to a jsfiddle here https://jsfiddle.net/u43sdmqy/

Email below, I can't find what post/question this was originally relating to! If I find the original thread I'll amend. Note the comment on straight lines.

Edit: added links at bottom from original

...

This is a none trivial exercise, so I would firstly look for a workaround, as there's lots of edge cases you may need to account for. I will try and show an example though, to try and highlight how it could be approached using the intersection() method.

Edit: There are some bugs I think with straighter lines, not sure if it's my code or Snap or misunderstanding converting to cubic, but leaving here in case someone sees and improves.

Firstly if you look at the intersection array, it will show some elements...

segment1  = path1 segment number the intersection occurs on
segment2  = path2 segment number the intersection occurs on
t1 = ratio how far through path1 segment the intersection occurs
t2 = ratio how far through path2 segment the intersection occurs

So using these, we can loop through each path segment, add them together until we get to the intersection. At that point, we want to break that path section up depending on 't', e.g if its 0.75, we want to split that subpath up 0.75 towards the end of it (range of 0->1).

So now we have to get the path segments. We can do this using svgElement.pathSegList(), however some browsers have deprecated this (Chrome I think), however you can get a polyfill (see the top answer [here][1]. To avoid needing it for this example, I've converted the path to cubic segments using path.toCubic();

So we loop through each path, loop through each pathseglist, and loop through each intersection, building the path up until the intersection segment. At each intersection taking the ratio through that section (getting the length to create a subpath later), and then carrying on from that last place.

Note1: There may be a simpler way! Eg take a look at an intersection library [here][2]

Note2: In this example, it's a circle, so the start/end points are split, just like they are when creating the path, you may need to think about this if the real examples will be circles.

Note3: There are likely to be bugs, this is just to highlight how I 'think' it could be used.

var p1='M 185.90092404385516 250 m -170.90092404385516 0 a 170.90092404385516 170.90092404385516 0 1 0 341.8018480877103 0 a 170.90092404385516 170.90092404385516 0 1 0 -341.8018480877103 0';
var p2='M 336.8744227648239 250 m -148.12557723517602 0 a 148.12557723517602 148.12557723517602 0 1 0 296.25115447035205 0 a 148.12557723517602 148.12557723517602 0 1 0 -296.25115447035205 0';

var cubics = [ Snap.path.toCubic( p1 ), Snap.path.toCubic( p2 ) ];
var PAPER=Snap(document.getElementById('svg'));

var path1=PAPER.path( cubics[0] );
path1.attr({'fill-opacity':0.3})

var path2=PAPER.path( cubics[1] );
path2.attr({'fill-opacity':0.3})

var intersection=Snap.path.intersection(p1, p2);

var newPath
var lastSegCount = 0;
var lastChunkLength = 0;

for( var path = 0; path < 2; path ++ ) {

  for( var i = 0; i<=intersection.length; i++ ) {
    newPathString = '';

    if( i<intersection.length) {
      for (a = 0; a<intersection[i]['segment'+(path+1)]; a++) {
        newPathString += cubics[path][a][0] + cubics[path][a].slice(1)
      }

      var len = Snap.path.getTotalLength( newPathString )

      newPathString += cubics[path][intersection[i]['segment'+(path+1)]][0] + cubics[path][intersection[i]['segment'+(path+1)]].slice(1)

      totalNewLen = Snap.path.getTotalLength( newPathString )
      diffLen = totalNewLen - len;

      newChunkLength = diffLen * intersection[i]['t'+(path+1)] + len;
    } else {
      newChunkLength = Snap.path.getTotalLength( cubics[path] )
    }
    var newPath = Snap.path.getSubpath( cubics[path], lastChunkLength, newChunkLength );
    lastChunkLength = newChunkLength;

    PAPER.path( newPath ).attr({ fill: 'none', stroke: '#'+Math.floor(Math.random()*16777215).toString(16), strokeWidth: 4 } )


  }

}

http://stackoverflow.com/questions/34352624/alternative-for-deprecated-svg-pathseglist
http://www.kevlindev.com/geometry/2D/intersections/index.htm
http://jsfiddle.net/rzvu3s7m/24/

@tuomotalvitie
Copy link

I am not absolutely sure about this (which is why I am adding this here as a comment only), but there may be a problem (or inconsistency) in how Arcs (A) are counted towards segment1, as I somewhat consistently got mangled graphs due to the segment1 pointing to wrong (larger order number) segment before I changed my Arcs to Beziers. The coordinates were correct in both cases.

And what I mean by problem is that the segment number does not seem to always match parsePathString segment numbers. Which may be a function of the intersection function converting arcs to beziers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants