У меня трудные времена, чтобы понять правильный алгоритм. У меня есть суперпредставление (зеленый) и подпредставление (желтый). Имея произвольную опорную точку (просто выбранную точку, не смешивающуюся со свойством 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};
}
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};
}