Igor Shmukler
Igor Shmukler

Reputation: 2216

Drawing curve with canvas

I am working on a [specialized] graphics editor. It is used to draw simple vector graphics elements including arcs/curves.

We support a shape that mixes straight lines and curves. It gets drawn as a bunch of straight sections. At a later point, a designer can convert a straight segment into a curve. It looks like the below: enter image description here

We persist this object as an array of dots. Each dot has coordinates x and y as well as optional angles r1 and r2. I draw the shape on canvas using the below:

        const parts = [ 
                      ...,
                      {x: 359, y: 187, r1: 0.4, r2: 0},
                      {x: 214, y: 184, r1: 0, r2: 0.5}
                      ...
        ];

        for (let j = 0, len = parts.length; j < len; j++) {
            const p1 = parts[j];
            const p2 = parts[j < len - 1 ? j + 1 : 0];
            if ('r1' in p && p.r1 > 0 && 'r2' in p2 && p2.r2 > 0) {
                console.log('point:', p1);
                console.log('next point:', p2);
                console.log('draw arc, angle:', p1['r1']);
                console.log('next vertex angle:', p2['r2']);
                ctx[j ? 'quadraticCurveTo' : 'moveTo'](p1.x + 50, p1.y + 50, p1.x, p1.y);
            } else {
                ctx[j ? 'lineTo' : 'moveTo'](p1.x, p1.y);
            }
        }

It works, I get straight lines and curves when I need them.

However, my control point is off. I temporarily coded it as p1.x + 50, p1.y + 50 and this is not right. Knowing p1 and p2, including coordinates and angles, how do I calculate the control point?

Upvotes: 0

Views: 254

Answers (1)

MBo
MBo

Reputation: 80187

You need to calculate intersection point of two rays. Using parametric representation:

      first ray              second ray
x = p1.x + t * cos(r1) = p2.x + u * cos(r2)
y = p1.y + t * sin(r1) = p1.y + u * sin(r2)

Solve this equation system (shortening variable names as p1.x=x1, cos(r2)=c2 etx )

x1 + t * c1 = x2 + u * c2 
y1 + t * s1 = y2 + u * s2 

t = (x2 - x1 + u * c2) / c1
y1 + (x2 - x1 + u * c2) / c1 * s1 = y2 + u * s2 
u  *  (c2 / c1 * s1 - s2) = (y2 - y1) -  (x2 - x1) / c1 * s1
u  *  (c2 * s1 - s2 * c1 ) = (y2 - y1) * c1 -  (x2 - x1) * s1

u = ((y2 - y1) * c1 -  (x2 - x1) * s1) / (c2 * s1 - s2 * c1 )

substitute this value into the first equations and get x,y of intersection

x = x2 + u * c2
y = y2 + u * s2

Zero value of denominator (c2 * s1 - s2 * c1) occurs for parallel vectors. Negative value of parameter u - for case of non-intersecting vectors when angle is too large. These cases are impossible when non-degenerate point sequence is used as input.

Upvotes: 2

Related Questions