Rotate points belonging to a bezier curve on canvas js

0

Alright? I would like help with a problem I recently got while working with JS. I need to do a function in JS that can rotate a set of points present in a bezier curve.

I've previously researched a way to do this point rotation, but everything I found is related to rotating the context of the canvas being used. But this does not work for me, because I have to store the point values after the rotation of the curve.

So I tried to apply a geometric equation to find the angle value between two points where the mouse touches the screen so I can perform 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 teachers at my university), unless I wrote wrong: P

Continuing, after getting the angle, I do the same for the rotation function below which is intended to change the position value of the points on the bezier curve and redraw that curve on 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 could not figure out, the function did not work correctly. I checked if the rotateBezier function was incorrect by passing the value Math.PI , and found that it can rotate the curve, but it moves from position to position relatively in the center of the canvas.

So I'd like some help with this problem, thanks in advance.

    
asked by anonymous 07.12.2018 / 01:34

1 answer

0

I was able to detect the problem. First of all in the rotation function, whose name is rotateBezier one must eliminate the use of the origin in both x and y, and the offsets used. The function is 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 entered to calculate the angle, and add the following lines after the angle statement

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

Since the highLowAngle function is to detect whether it will rotate to the right or left. The content of the function is 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 anyone who sees the answer later will benefit from it.

    
11.12.2018 / 23:20