1
votes

I want to draw a curved path (an arc or a cubic bezier curve) from a point to a circle. The following parameters are known: pX (x-position of the point), pY (y-position of the point), cX (x-position of the circle's center), cY (y-position of the circle's center) and cR (radius of the circle).

This figure illustrates the problem.

enter image description here

The circle is not opaque and when the path is drawn from the point to the circle's center, it is visible through the circle (see #1 in the linked figure). It shouldn't be happening as there exists some background content that has to be visible through the circle. So, the solution I imagine is to draw the path up to the circle's border.

Drawing a straight line until the circle's border is easy (see #2 in the linked figure):

var theta = Math.atan2(cY - pY, cX - pX);
var startX = pX;
var startY = pY;
var endX = cX - cR * Math.cos(theta);
var endY = cY - cR * Math.sin(theta);
line.attr('x1', startX).attr('y1', startY).attr('x2', endX).attr('y2', endY);

If I apply the same principle to a curved path, it will be drawn incorrectly (see #3 in the linked figure). It has to keep the shape as if it was pointing to the circle's center, but end without overlapping the circle (see #4 in the linked figure).

Additional observations:

  • the curve can be as thick as the circle
  • there can exist several hundred of circle-arc pairs simultaneously in the visualization, therefore the performance has also be taken into consideration

Any suggestions on how to solve this? Thanks in advance!

1
use a mask or clip region on the pathrioV8
@rioV8 In my case, there can be several hundreds of bubble-arc pairs (big data vis). Won't the additional several hundreds of clip path objects negatively affect the performance of the visualization?urss
then make sure you draw the circles in a group that is after the group with the paths or for each path circle combo, draw the circle after the path, then the circle will mask the path, oops forgot the non opaque circlerioV8
note that if your line has any sort of thickness, it doesn't matter what you do: it will always look bad because the touching edge of your line won't have the same radius of curvature as your circle, so it'll either overlap, or more likely will have gaps on the side. So what you really want is to look up how to clip a shape based on another shape: draw the line to the center of the circle, and then replace the line with whatever is d3's equivalent of exclusion(line, circle).Mike 'Pomax' Kamermans
@Mike'Pomax'Kamermans you are right regarding the curvature. I will try the masking or path clipping suggestion.urss

1 Answers

0
votes

Look at this picture:

The resulting curve together with its control points.

The red dot is your point (pX,pY), the black dot is the center of the circle. You choose the green point somewhere in the plane (you can experiment with its location to find a curve that you like) and construct the blue point as the intersection of your circle with the straight line connecting the black and green points.

Now you use the red point, the green point and the blue point as a control polygon to construct a quadratic Bézier curve. It will start from the red point, end in the blue point on the circle and its tangent there will be towards the center of the circle.

If your curve would be really thick, this simple solution might be insufficient. In that case I recommend doing as @rioV8 recommends.