Shading an intersection of shapes

167 views
Skip to first unread message

Chris Mullins

unread,
Nov 9, 2011, 3:25:28 PM11/9/11
to Raphaël
Hi there,

Cool library! Thanks for it. :)

I'm working on an interactive Venn diagram. I'd like to be able to
shade the intersection of two or more ellipses. Is this something
that's easy (or pragmatic) to do with Raphaël?

Also, I'm detecting the set of ellipses that a point lies within by
doing this: http://pastebin.com/SwPZRN7t .

I'd hoped for a better way to do this, but couldn't find one. Do any
of you have suggestions?

Thanks so much,
- Chris

akkad

unread,
Nov 10, 2011, 1:32:53 PM11/10/11
to Raphaël

Hey Chris,

what do you think about this :
create paths with the shape of ellipses and find the coordinates on
the paths that coincide. Once you find these two, draw another path
between these two coordinates along the paths. Then you can fill this
new path.
Voila!

Chris Mullins

unread,
Nov 10, 2011, 4:01:36 PM11/10/11
to Raphaël
Interesting! I'll give that a try. Thanks.

I tried a very naïve approach last night that seems to work pretty
well. I fill the region with lines, where the lengths are found by
brute force. I do this until the endpoints for the lines fall outside
the starting region. The effect is something like this:

https://img.skitch.com/20111110-xau7srgnm866ia153cjebb8kp9.jpg

It seems more computationally expensive than necessary, but there's no
noticeable delay between clicking and having the region shaded.

Ed Davies

unread,
Nov 10, 2011, 5:42:07 PM11/10/11
to Raphaël
On Nov 10, 6:32 pm, akkad <nonadr...@gmail.com> wrote:
> what do you think about this :
> create paths with the shape of ellipses and find the coordinates on
> the paths that coincide. Once you find these two, ...

It depends on how the ellipses in the diagram are generated but note
that in general the paths of intersecting ellipses can coincide in 0,
1, 2, 3, 4 or an infinite number of distinct points. At least, those
are the cases I can visualize, perhaps there are others.

0: one ellipse is totally inside the other.
1: one ellipse is totally inside the other but they touch at one point
of tangency.
2: normal Venn diagram case or one inside the other with two points of
tangency (e.g., either non-circular and one's semi-major axis is the
other's semi-minor axis).
3: one point of tangency but the "inner" ellipse sticks out of the
other side of the outer.
4: the ellipses cross each other.
infinite: same ellipses.

dusadrian

unread,
Oct 20, 2015, 3:31:31 AM10/20/15
to Raphaël
Hi all,

I am bringing back this old topic... is there some kind of a step by step example to shade the intersection of two general shapes?
I learned how to use pathIntersection(), but I just don't understand what the output of that is or how can I use it to create another shape with the intersection.

Thanks,
Adrian

Ian

unread,
Oct 20, 2015, 4:27:25 AM10/20/15
to Raphaël
It returns the points where the paths intersect.

That does't tell you what shape it is though, and there is no way to find that out as far as I'm aware.

I don't suppose using opacity 0.3 or whatever, and just letting the opacity build up in the intersected part is good enough ?

Ian

unread,
Oct 20, 2015, 4:32:52 AM10/20/15
to Raphaël
Ignore me on that last one, think I was getting mixed up, and it does more than I remembered!

dusadrian

unread,
Oct 21, 2015, 4:51:08 AM10/21/15
to Raphaël
Hi Ian,

Right, I figured that much.
What I would be really interested is to find the path length at the intersection point, and then simply get the subpath between the two.
Append the other subpath to this one and (voila), we get the intersection shape.

I can get the coordinates of a point at a specific length, but I don't see any option to get the length of the path at a specific point... any idea?

Thanks,
Adrian

Ian

unread,
Oct 21, 2015, 5:14:33 AM10/21/15
to Raphaël
I had a quick peek at this but ran out of time, once I saw the documentation in details...here is how I would approach it, I may well be wrong in what the bits do, but it may give you some ideas...

If we take a look at a quick fiddle I did, eg https://jsfiddle.net/cqrf411L/4/ (last few lines don't really work atm but may give an idea of where I was heading )

I think the pathIntesection returns the following...

x,y which are obvious...
t1,t2...now these I think are less obvious, but I'm guessing they are a percentage as the range of 0-1 (ie if its 76% through that segment of the path, it will be 0.76), which I'm guessing combine with the next one...
segment1,segment2 which are the respective path segments that the t1,t2 correspond to. So my pseudologicode that I would have explored would be...

Get the pathIntersection...
Access the segment, eg I think this may correspond to path.attrs.path[ segment1 ] or could be matched from the bez1,bez2
create the subPath using the t1 value (how far along the segment is it)

If its the first point, we probably want the subpath after the point (so from t1 until the end), add all the corresponding segments until the next intersection point, at which point we take the subpath of the respective segment until the t1 percentage,
Repeat for the 2nd path (and repeat if there are more intersections, I am wondering if this could work for complex paths ?).

We may have to use the previous segment or next segment start/end point for build the start/end points of the overall path 

I may have got some bits wrong in what they mean, and that may be as clear as mud! :)

dusadrian

unread,
Oct 22, 2015, 7:06:55 AM10/22/15
to Raphaël
On Wednesday, 21 October 2015 12:14:33 UTC+3, Ian wrote:
I had a quick peek at this but ran out of time, once I saw the documentation in details...here is how I would approach it, I may well be wrong in what the bits do, but it may give you some ideas...

If we take a look at a quick fiddle I did, eg https://jsfiddle.net/cqrf411L/4/ (last few lines don't really work atm but may give an idea of where I was heading )

OK, I saw the fiddle... but that code (I think) cheats a bit because the intersection point "happens" to overlap with the starting point of the path.
In a real world scenario, we know where the starting point is, but we have no idea where the intersection point happens. So this is why I need to obtain the length of the path from the start point to the intersection points.

Raphael has a getPointAtLength() function, which returns the coordinated (x, y) of a point at a given length of the path.
But what is really needed is the inverse of that, namely the length of the path, from the beginning to a point of specific (x, y) coordinates.

I know that a point is inside a path, using Element.isPointInside(), but I don't know where (at which length) is that point inside a path.
I would have imagined that t1 and t2 are percentages of the total length of the path..., but either I don't understand how to use them, or they're not what we think they are.

For example, let's take these two shapes (some ellipses in coordinates using cubiec bezier curves), using your fiddle notation (where "r" is the paper):

var e1 = "M 293.4,210 C 290.7,288.9 320.1,357.5 359,363.4 398,369.3 431.7,310.2 434.4,231.3 437.1,152.4 407.7,83.77 368.8,77.87 329.8,71.96 296.1,131 293.4,210 z";
var e2 = "M 341.4,237.6 C 396.5,294 421,364.5 396.2,395.1 371.4,425.8 306.7,404.7 251.6,348.3 196.4,291.8 171.9,221.4 196.7,190.7 221.5,160.2 286.2,181.1 341.4,237.6 z";

var pe1 = r.path(e1);
var pe2 = r.path(e2);

var intersection = Raphael.pathIntersection( e1, e2 );

Now, the intersection points are indeed inside the path, but at which length...?
I would have imagined that t1 and t2 might be percentages of length, but that doesn't seem to be the case:

var pe1tl = pe1.getTotalLength(); // 691.3809814453125

console.log(pe1.getPointAtLength(pe1tl * intersection[0].t1)) // {x: 426.07913701276846, y: 289.4692102608795, alpha: 104.99917071647815}
console.log(pe1.getPointAtLength(pe1tl * intersection[0].t2)) // {x: 430.27349773764143, y: 172.0948398923059, alpha: 259.75147609911164}
console.log(pe1.getPointAtLength(pe1tl * intersection[1].t1)) // {x: 296.38104075711533, y: 177.4903843425423, alpha: 98.66809287261626}
console.log(pe1.getPointAtLength(pe1tl * intersection[1].t2)) // {x: 391.5010779152665, y: 89.10259705181718, alpha: 221.0237982989102}

As you can see, nothing resembles the intersection points.
So what t1 and t2 really are, is a mystery to me. Also, how could one use the coordinates from bez1 and bez2 components?

To my mind, the solution would be:
a. calculate the length of the path at the intersection point 1
b. calculate the length of the path at the intersection point 2
c. get the subpath using:
pe1.getSubpath(length1, length2)

But I'm stuck at a) and b)...
Adrian



Ian

unread,
Oct 22, 2015, 8:34:32 AM10/22/15
to Raphaël
I think you misunderstood the last couple of lines, it was just a direction, not a complete example. Here is a bit more further on, what I was meaning with the first paths first intersection only....you would need to build this into a function, repeat. 

Note, the first paths example segments that are intersects are both segment 2, often they will match on different segments, so you will need to build the subpath up (have included a note in the fiddle).

The bit I was missing I think, was that the segments in pathIntersection refer to the path when changed to a curves only path.

So if we do this...

var curves2 = Raphael.path2curve( p2 );
var curves1 = Raphael.path2curve( p1 );

We will have both of our paths as curves now. If you look at console log, you will see its an array of segments that its been converted to. Now we know that, we know which segment the first intersection hits. We also know where abouts it hits in length by the percentage t1

So we can build up the subpath (start with end of previous point if there is one), add the current segment path, get the length of it, and then getSubPath of it using t1 & subPath.length, do the same for the end/next intersection point (adding any inbetween segments).

Here is the fiddle, red line is the second segment (as thats intersection[0].segment1

Yellow is subpath of it, using the intersect[0].t1 and intersect[1].t1 this is the first bit of the intersection.


There's still a lot of work to do proceduralising it and using both paths, but hope that helps.

dusadrian

unread,
Nov 5, 2015, 5:34:28 AM11/5/15
to Raphaël
Thanks very much Ian, I'll look into this and hopefully come back with a complete example.
Apologies for responding so late, but for some reason it didn't get into my Inbox.
Best,
Adrian

dusadrian

unread,
Nov 23, 2015, 5:14:16 AM11/23/15
to Raphaël
Hi again,

The best solution I found... already exists:

It creates the intersection flawlessly, and the resulting object can be shaded afterwards.

Thanks again,
Adrian

On Thursday, 22 October 2015 15:34:32 UTC+3, Ian wrote:
Reply all
Reply to author
Forward
0 new messages