Ситуация
Я написал следующий метод (в ActionScript 3 это приложение Flash), который возвращает тип преобразования, необходимый для текущей позиции мыши относительно данной позиции элемента.
Элемент можно перемещать, масштабировать и вращать. Этот метод возвращает, если любое из этих преобразований применимо с заданными координатами:
(не волнуйтесь, вам не нужно отлаживать этот метод, он работает - просто добавьте его здесь, чтобы вы поняли, что я делаю)
//returns whether the mouse is at a transforming position
private static function mouseAtTransformPosition(cX:Number, cY:Number, eX:Number, eY:Number, eW:Number, eH:Number, margin:Number):String
{
//initialize the transformation type
var transformType:String = null;
//set the transformation type depending on the given coordinates
if ((cX > eX) && (cX < eX + eW) && (cY > eY) && (cY < eY + eH))
{
transformType = "mover";
}
else if ((cX > eX) && (cX < eX + eW) && (cY <= eY) && (cY >= eY - margin))
{
transformType = "scalerUp";
}
else if ((cX >= eX + eW) && (cX <= eX + eW + margin) && (cY > eY) && (cY < eY + eH))
{
transformType = "scalerRight";
}
else if ((cX > eX) && (cX < eX + eW) && (cY >= eY + eH) && (cY <= eY + eH + margin))
{
transformType = "scalerDown";
}
else if ((cX <= eX) && (cX >= eX - margin) && (cY > eY) && (cY < eY + eH))
{
transformType = "scalerLeft";
}
else if ((cX >= eX - margin) && (cX <= eX) && (cY >= eY - margin) && (cY <= eY))
{
transformType = "scalerUpLeft";
}
else if ((cX >= eX + eW) && (eX <= eX + eW + margin) && (cY >= eY - margin) && (cY <= eY))
{
transformType = "scalerUpRight";
}
else if ((cX >= eX + eW) && (cX <= eX + eW + margin) && (cY >= eY + eH) && (cY <= eY + eH + margin))
{
transformType = "scalerDownRight";
}
else if ((cX >= eX - margin) && (cX <= eX) && (cY >= eY + eH) && (cY <= eY + eH + margin))
{
transformType = "scalerDownLeft";
}
else if ((cX >= eX - margin * 2) && (cX <= eX) && (cY >= eY - margin * 2) && (cY <= eY))
{
transformType = "rotatorTopLeft";
}
else if ((cX >= eX + eW) && (cX <= eX + eW + margin * 2) && (cY >= eY - margin * 2) && (cY <= eY))
{
transformType = "rotatorTopRight";
}
else if ((cX >= eX + eW) && (cX <= eX + eW + margin * 2) && (cY >= eY + eH) && (cY <= eY + eH + margin * 2))
{
transformType = "rotatorBottomRight";
}
else if ((cX >= eX - margin * 2) && (cX <= eX) && (cY >= eY + eH) && (cY <= eY + eH + margin * 2))
{
transformType = "rotatorBottomLeft";
}
//return the found transformation type
return transformType;
}
Уточнение всех необходимых параметров:
cX: cursor X position
cY: cursor Y position
eX: element X position
eY: element Y position
eW: element width
eH: element height
margin: how far the cursor can be removed from an exact transformation location to still be applicable
Если преобразование не применимо, возвращается ноль.
Проблема
Теперь моя функция работает отлично. Проблема возникает сейчас, когда я ввожу вращение в элементы, которые должны быть преобразованы.
Когда вы поворачиваете элемент, углы перемещаются в другое положение. Теперь курсор должен находиться в разных положениях, чтобы получить одинаковые типы преобразования в зависимости от ситуации, как это делает мой метод выше (если нет вращения):
cursor is...
inside the element -> move
at top of element -> scale up
at right of element -> scale right
at bottom of element -> scale down
at left of element -> scale left
at top left of element -> scale up-left
at top right of element -> scale up-right
at bottom left of element -> scale down-left
at bottom right of element -> scale down-right
further top left of element -> rotate right/left
further top right of element -> rotate right/left
further bottom right of element -> rotate right/left
further bottom left of element -> rotate right/left
Вопрос
Мой метод делает это отлично, если нет вращения. Однако, как я могу изменить эту функцию, чтобы учесть вращение, например, изменение координат углов?
Обновление для Джастина
//checks whether mouse transforming is applicable
private static function checkMouseTransforming(cX:Number, cY:Number, render:Sprite):void
{
//temp disable rotation to get accurate width/height, x and y
var realRotation:Number = render.getChildAt(0).rotation;
render.getChildAt(0).rotation = 0;
var eX:Number = render.x;
var eY:Number = render.y;
var eW:Number = render.width;
var eH:Number = render.height;
var margin:uint = 10;
//restore real rotation
render.getChildAt(0).rotation = realRotation;
cX -= eX + eW / 2;
cY -= eY + eH / 2;
var theta:Number = render.getChildAt(0).rotation * Math.PI / 180;
var newcX:Number = Math.cos(theta) * cX - Math.sin(theta) * cY;
var newcY:Number = Math.sin(theta) * cX + Math.cos(theta) * cY;
newcX += eX + eW / 2;
newcY += eY + eH / 2;
var transformType:String = mouseAtTransformPosition(newcX, newcY, eX, eY, eW, eH, margin);
if (transformType)
{
//...
}
Как видите, поворот задается и принимается от дочернего элемента визуализируемого объекта. Это связано с тем, что фактический объект - это positionWrapper, а внутри этой обертки есть rotWrapper (для которого установлено вращение), а внутри этой обертки остается фактический видимый элемент. X, y, ширина и высота позиционного упаковщика всегда равны таковым у видимого экранного объекта, поэтому это не должно вызывать проблем.
Теперь вот результаты:
- Без вращения все работает как положено
- При повороте на 45 градусов при наведении указателя мыши на объект визуального отображения:
- нижний центр: он возвращает «scalerLeft», а должен возвращать «scalerDown»
- правый центр: возвращает ScalerDown, а должен возвращать ScalerRight
- верхний центр: возвращает ScalerRight, а должен возвращать ScalerUp
- левый центр: он возвращает scalerUp, а должен возвращать scalerLeft (обратите внимание на шаблон смещения здесь)
- Двигатель, кажется, возвращается довольно точно
- вращатель, кажется, возвращается в прямом нижнем углу, а не там, где он должен
- Скейлер bottomLeft, похоже, возвращается в нижнем правом углу, я думаю, что это то же самое смещение является проблемой и, вероятно, то же самое для всех других скейлеров
Это ошибка для отладки, но, возможно, это поможет.
Обновление № 2 для Джастина
альтернативный текст http://feedpostal.com/transformBug.gif
Смещение / ошибка, кажется, тем сильнее, чем выше вращение. При повороте на 0 эта ошибка не появляется.
Имеет ли это смысл для вас или кого-либо еще? Заранее спасибо.