Позиционирование подпредставления с произвольной точкой привязки в суперпредставлении - PullRequest
0 голосов
/ 15 января 2019

У меня трудные времена, чтобы понять правильный алгоритм. У меня есть суперпредставление (зеленый) и подпредставление (желтый). Имея произвольную опорную точку (просто выбранную точку, не смешивающуюся со свойством anchor слоя) в этом подпредставлении (красный), я должен разместить и изменить размер подпредставления так, как эта красная точка помещается в центр суперпредставления , а подпредставление изменяется при необходимости пропорционально (если после перемещения его кадр выходит за границы суперпредставления). Авто макет не используется. Смотри картинку, что я хочу получить.

Таким образом, в основном я написал подпрограмму теста C ++, в которой новый пропорциональный прямоугольник вычисляется «вокруг» заданной новой точки (поэтому эта точка получает центр этого нового прямоугольника), но я не знаю, что делать дальше, чтобы обработать точку, которая не в центре подпредставления. Rect - это в основном структура с x, y, width, height членами.

    Rect
    calculateRectInBounds(const Rect &boundingRect, const Rect &initialRect, const Point &translationPoint)
    {
        double boundsWidth = boundingRect.getWidth();
        double boundsHeight = boundingRect.getHeight();
        double distanceX, distanceY;
        Size sizeByWidth, sizeByHeight;

        // detect part where point is

        /*
         * UL | UR
         * ---C---
         * LL | LR
         */

        // -- upper left - check left & top borders

        if (translationPoint.x <= boundsWidth / 2 && translationPoint.y < boundsHeight / 2) {
            distanceX = translationPoint.x;
            distanceY = translationPoint.y;

            sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
            sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);

            if (sizeByWidth.height > distanceY) {
                return {translationPoint.x - sizeByHeight.width,
                        0,
                        sizeByHeight.width * 2,
                        sizeByHeight.height * 2};
            }

            return {0,
                    translationPoint.y - sizeByWidth.height,
                    sizeByWidth.width * 2,
                    sizeByWidth.height * 2};
        }

        // -- upper right - check top & right borders

        if (translationPoint.x > boundsWidth / 2 && translationPoint.y <= boundsHeight / 2) {
            distanceX = boundsWidth - translationPoint.x;
            distanceY = translationPoint.y;

            sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
            sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);

            if (sizeByWidth.height > distanceY) {
                return {translationPoint.x - sizeByHeight.width,
                        0,
                        sizeByHeight.width * 2,
                        sizeByHeight.height * 2};
            }

            return {translationPoint.x - sizeByWidth.width,
                    translationPoint.y - sizeByWidth.height,
                    sizeByWidth.width * 2,
                    sizeByWidth.height * 2};
        }

        // -- lower right - check right & bottom borders

        if (translationPoint.x >= boundsWidth / 2 && translationPoint.y > boundsHeight / 2) {
            distanceX = boundsWidth - translationPoint.x;
            distanceY = boundsHeight - translationPoint.y;

            sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
            sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);

            if (sizeByWidth.height > distanceY) {
                return {translationPoint.x - sizeByHeight.width,
                        translationPoint.y - sizeByHeight.height,
                        sizeByHeight.width * 2,
                        sizeByHeight.height * 2};
            }

            return {translationPoint.x - sizeByWidth.width,
                    translationPoint.y - sizeByWidth.height,
                    sizeByWidth.width * 2,
                    sizeByWidth.height * 2};
        }

        // -- lower left - check bottom & left borders

        if (translationPoint.x < boundsWidth / 2 && translationPoint.y >= boundsHeight / 2) {
            distanceX = translationPoint.x;
            distanceY = boundsHeight - translationPoint.y;

            sizeByWidth = scaleSizeToWidth(initialRect.getSize(), distanceX);
            sizeByHeight = scaleSizeToHeight(initialRect.getSize(), distanceY);

            if (sizeByWidth.height > distanceY) {
                return {translationPoint.x - sizeByHeight.width,
                        translationPoint.y - sizeByHeight.height,
                        sizeByHeight.width * 2,
                        sizeByHeight.height * 2};
            }

            return {0,
                    translationPoint.y - sizeByWidth.height,
                    sizeByWidth.width * 2,
                    sizeByWidth.height * 2};
        }

        // -- center

        return initialRect;
    }

Size
scaleSizeToWidth(Size size, double newWidth)
{
    return {newWidth, (std::min(size.width, newWidth) / std::max(size.width, newWidth)) * size.height};
}

Size
scaleSizeToHeight(Size size, double newHeight)
{
    return {(std::min(size.height, newHeight) / std::max(size.height, newHeight)) * size.width, newHeight};
}

enter image description here

EDIT

Благодаря ответу @MBo правильная процедура

    Rect
    calculateRectInBounds(const Rect &boundingRect, const Rect &initialRect, const Point &anchorPoint)
    {
        auto lDist = anchorPoint.x - initialRect.getX();
        auto rDist = initialRect.getWidth() - lDist;
        auto tDist = anchorPoint.y - initialRect.getY();
        auto bDist = initialRect.getHeight() - tDist;

        auto lRatio = (lDist * 2) / boundingRect.getWidth();
        auto rRatio = (rDist * 2) / boundingRect.getWidth();
        auto tRatio = (tDist * 2) / boundingRect.getHeight();
        auto bRatio = (bDist * 2) / boundingRect.getHeight();

        auto scale = 1 / std::max({lRatio, rRatio, tRatio, bRatio});

        auto x = initialRect.getWidth() / 2 - lDist * scale + initialRect.getX();
        auto y = initialRect.getHeight() / 2 - tDist * scale + initialRect.getY();
        auto width = initialRect.getWidth() * scale;
        auto height = initialRect.getHeight() * scale;

        return {x, y, width, height};
    }

1 Ответ

0 голосов
/ 15 января 2019

Получить расстояние от красной точки до всех краев прямоугольника подпредставления

RedX, YellowWidth-RedX, RedY, YellowHeight - RedY

и рассчитать 4 соотношения с размерами суперпредставления

L = (2 * RedX) / GreenWidth
R = (2 * (YellowWidth-RedX)) / GreenWidth
T = (2 * RedY) / GreenHeight
B = (2 * (YellowHeight-RedY)) / GreenHeight

затем найдите максимум из них

Mx = Max(L,R,T,B)

Теперь определите масштаб:

Scale = 1 / Mx 

Новые координаты подпредставления:

X =  YellowWidth / 2  - (RedX * Scale)
Y =  YellowHeight / 2  - (RedY * Scale)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...