Rotate points belonging to a Bezier curve in canvas js

Asked

Viewed 77 times

1

all right? I’d like help with a problem I recently got while working with JS. I need to make a function in JS that can rotate a set of points present in a Bezier curve.

I previously researched a way to perform this rotation of points, but all I found is related to rotating the context of the canvas being used. However this does not serve in my case, due to the fact of having to store the point values after the rotation of the curve.

So I tried to apply a geometric equation to find the value of the angle between two points where the mouse touches the screen so that I can do the rotation. This equation is below:

if (mousePosition.x == null) {
    mousePosition.x = event.clientX;
    mousePosition.y = event.clientY;
} else {
    // noinspection JSSuspiciousNameCombination
    let productModule = {
        first: Math.sqrt(Math.pow(event.clientX, 2) + Math.pow(event.clientY, 2)),
        second: Math.sqrt(Math.pow(mousePosition.x, 2) + Math.pow(mousePosition.y, 2))
    };
    let scaleProduct = Math.abs((event.clientX * mousePosition.x) + (event.clientY * mousePosition.y));
    let angle = Math.acos(scaleProduct / (productModule.first * productModule.second));
    rotateBezier(curveName, angle);
}
mousePosition.x = event.clientX;
mousePosition.y = event.clientY;

Theoretically, this equation is correct (it was an orientation of GA professors from my university), unless I wrote it wrong :P

Continuing, after obtaining the angle, I pass the same to the function of rotation below which aims to change the value of the position of the points in the curve of Ezier and redesign this curve in the canvas later.

function runPointsAndChange(curveName, callback_1, callback_2) {
    if (all_curves[curveName] != null) {
        all_curves[curveName].forEach(function(points, index, array) {
            points.forEach(function(point, position, arr) {
                if (position % 2 === 0) {
                    points[position] = callback_1(points[position], points[position + 1]);
                } else {
                    points[position] = callback_2(points[position], points[position - 1]);
                }
            });
        });
        bezier_curve(curveName); //função que desenha todas as curvas, e desenha um retângulo ao redor da curva selecionada
    }
}

function rotateBezier(curveName, angle) {
    curveName = curveName.replace(" ", "-").toLowerCase();
    const boxDimensions = getBoxDimensions(curveName, null, true);
    const imgOfLf = $("#image").offset().left;
    const imgOfTp = 10; //imageOffset.top;
    let origin = {
        x: (boxDimensions[0] + boxDimensions[2]) / 2,
        y: (boxDimensions[1] + boxDimensions[3]) / 2
    };
    runPointsAndChange(curveName, function(pointX, pointY) {
        return origin.x + imgOfLf + (pointX * Math.cos(angle)) - (pointY * Math.sin(angle));
    }, function(pointY, pointX) {
        return origin.y + imgOfTp + (pointX * Math.sin(angle)) + (pointY * Math.cos(angle));
    });
}

For some reason I couldn’t figure out, the function didn’t work properly. I found out if the rotateBezier function was incorrect by passing the value as parameter Math.PI, and I found that it can rotate the curve, but it moves from position and stops relatively in the center of the canvas.

So I would like to help with this problem, and I thank you in advance.

1 answer

1


I was able to detect the problem. First in the rotation function, whose name is rotateBezier the use of the origin in both x and y and of the offsets used should be eliminated. The function was as follows::

function rotateBezier(curveName, angle) {
    curveName = curveName.replace(" ", "-").toLowerCase();
    runPointsAndChange(curveName, function(pointX, pointY) {
        return (pointX * Math.cos(angle)) - (pointY * Math.sin(angle));
    }, function(pointY, pointX) {
        return (pointX * Math.sin(angle)) + (pointY * Math.cos(angle));
    }, true);
}

Later I had to change the main code informed to calculate the angle, and add the following lines after the declaration of Angle

if (isNaN(angle)) {
    angle = 0;
} else {
    angle *= highLowAngle(mousePosition, {
        x: event.clientX,
        y: event.clientY
    });
}

Where the function highLowAngle is to detect whether to rotate to the right or left. The contents of the function are as follows::

function highLowAngle(oldPosition, currentPosition) {
    let maxX = Math.abs(oldPosition.x - currentPosition.x), maxY = Math.abs(oldPosition.y - currentPosition.y);
    if (Math.max(maxX, maxY) === maxX) {
        return oldPosition.x > currentPosition.x ? -1 : 1;
    }
    return oldPosition.y > currentPosition.y ? -1 : 1;
}

That was enough to solve my mistake. I hope that whoever sees the answer later benefits from it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.