矩形边界内的旋转线

时间:2018-12-13 11:37:22

标签: c++ algorithm drawing linear-algebra trigonometry

我想要实现的是围绕矩形中心旋转一条线,以便它始终停留在接触它们的边界内(或具有一些填充)。 现在,我有以下例程,如您所见,我使用tan计算将矩形分成8个部分(红线)

到目前为止,它仍然有效,但是由于某种原因,我在使用其他计算进行半径绘制(绿线)时存在不一致的地方,这些线并不总是如预期那样匹配,我想知道为什么。

仅使用sin / cos计算并找到线与矩形边界之间的交叉点,基本上可以实现相同的目的,但是由于某些原因,我无法使其正常工作。

    std::pair<Point, Point>
    MathUtils::calculateRotatingLine(Size size, double degrees)
    {
        auto width = size.width;
        auto height = size.height;

        double diagonalAngleTopRight = radiansToDegrees(atan((width / 2) / (height / 2)));
        double diagonalAngleBottomRight = 90 + (90 - diagonalAngleTopRight);
        double diagonalAngleBottomLeft = 180 + diagonalAngleTopRight;
        double diagonalAngleTopLeft = 180 + diagonalAngleBottomRight;
        double x, y;

        /*
         *  *8*1*
         * 7*   *2
         * 6*   *3
         *  *5*4*
         */

        // 1
        if (degrees >= 0 && degrees <= diagonalAngleTopRight) {
            x = width / 2 + height / 2 * tan(degreesToRadians(degrees));
            y = 0;
        }
        // 2
        else if (degrees > diagonalAngleTopRight && degrees <= 90) {
            x = width;
            y = width / 2 * tan(degreesToRadians(degrees - diagonalAngleTopRight));
        }
        // 3
        else if (degrees > 90 && degrees <= diagonalAngleBottomRight) {
            x = width;
            y = height / 2 + width / 2 * tan(degreesToRadians(degrees - 90));
        }
        // 4
        else if (degrees > diagonalAngleBottomRight && degrees <= 180) {
            x = width - height / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomRight));
            y = height;
        }
        // 5
        else if (degrees > 180 && degrees <= diagonalAngleBottomLeft) {
            x = width / 2 - height / 2 * tan(degreesToRadians(degrees - 180));
            y = height;
        }
        // 6
        else if (degrees > diagonalAngleBottomLeft && degrees <= 270) {
            x = 0;
            y = height - width / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomLeft));
        }
        // 7
        else if (degrees > 270 && degrees <= diagonalAngleTopLeft) {
            x = 0;
            y = height / 2 - width / 2 * tan(degreesToRadians(degrees - 270));
        }
        // 8
        else {
            x = height / 2 * tan(degreesToRadians(degrees - diagonalAngleTopLeft));
            y = 0;
        }

        return {Point{width / 2, height / 2}, Point{x, y}};
    }

绿线计算

    Point
    MathUtils::calculateCirclePoint(double radius, double degrees)
    {
        return {radius * cos(degreesToRadians(degrees)), radius * sin(degreesToRadians(degrees))};
    }

enter image description here

编辑

太棒了,感谢@MBo

    Point
    MathUtils::calculateCrossPoint(Size size, double degrees)
    {
        auto x0 = size.width / 2;
        auto y0 = size.height / 2;

        auto vx = cos(degreesToRadians(degrees - 90));
        auto vy = sin(degreesToRadians(degrees - 90));

        //potential border positions
        auto ex = vx > 0 ? size.width : 0;
        auto ey = vy > 0 ? size.height : 0;

        //check for horizontal/vertical directions
        if (vx == 0) {
            return {x0, ey};
        }

        if (vy == 0) {
            return {ex, y0};
        }

        // in general case find times of intersections with horizontal and vertical edge line
        auto tx = (ex - x0) / vx;
        auto ty = (ey - y0) / vy;

        // and get intersection for smaller parameter value
        if (tx <= ty) {
            return {ex, y0 + tx * vy};
        }

        return {x0 + ty * vx, ey};
    }

1 个答案:

答案 0 :(得分:3)

伪代码以查找从矩形中心(弧度为an的角)发射的光线与边缘的交点。 (也可用于其他(x0,y0)位置)

x0 = width / 2; 
y0 = height / 2; 
vx = cos(an);
vy = sin(an);

//potential border positions    
ex = vx > 0? width: 0
ey = vy > 0? height: 0

 //check for horizontal/vertical directions
if vx = 0 then
   return cx = x0,  cy = ey
if vy = 0 then
    return cx = ex, cy = y0

//in general case find times of intersections with horizontal and vertical edge line
  tx = (ex - x0) / vx
  ty = (ey - y0) / vy

 //and get intersection for smaller parameter value
 if tx <= ty then 
    return cx = ex, cy = y0 + tx * vy
 else
    return cx = x0 + ty * vx,  cy = ey