Вращающаяся линия внутри прямоугольника - PullRequest
0 голосов
/ 13 декабря 2018

То, чего я пытаюсь добиться, - это повернуть линию вокруг центра прямоугольника, чтобы он всегда оставался в своих границах, касаясь их (или имея некоторый отступ).Теперь у меня есть следующая процедура для этого, как вы видите, я использую 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 голосов
/ 13 декабря 2018

Псевдокод, чтобы найти пересечение луча, испускаемого из центра прямоугольника (с углом 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
...