2

情况

我编写了以下方法(在 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

如果没有适用的转换,它将返回 null。

问题

现在,我的功能似乎很好用。现在问题出现了,因为我正在向需要转换的元素引入旋转。

旋转元素时,角会移动到不同的位置。光标现在必须位于不同的位置才能根据情况获得相同的转换类型,就像我上面的方法一样(如果没有旋转):

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 并且在这个包装器内部有一个 rotationWrapper (旋转设置为)并且在该包装器内部实际的可见元素仍然存在。位置包装的 x、y、宽度和高度始终等于可见显示对象的 x、y、宽度和高度,因此这不会引起问题。

现在,这些是结果:

  • 没有旋转,一切都按预期工作
  • 当我将鼠标悬停在视觉显示对象上时,旋转大约 45 圈:
    • 底部中心:它返回“scalerLeft”,而它应该返回“scalerDown”
    • 右中心:它返回scalerDown,而它应该返回scalerRight
    • 顶部中心:它返回 scalerRight,而它应该返回 scalerUp
    • 左中心:它返回scalerUp,而它应该返回scalerLeft(注意这里的偏移模式)
    • 搬运工似乎很准确地返回
    • 旋转器似乎返回到角落的直接底部,而不是它应该返回的位置
    • bottomLeft 缩放器似乎在右下角返回,我认为这个相同的偏移量是问题所在,并且可能对于所有其他缩放器也是相同的

这是一个调试错误,但也许这会有所帮助。

Justin alt text http://feedpostal.com/transformBug.gif的更新 #2 偏移量/错误似乎越强,旋转越高。旋转为 0 时,不会出现此错误。

这对您或其他人有意义吗?提前致谢。

4

2 回答 2

2

我在这里做了一些假设。我假设对象是矩形和二维的(没有 3D 旋转)。我假设这是唯一可以转换以简化事情的对象。此外,从另一个答案的评论中,我了解到对象的尺寸(eX、eY、eW、eH)在旋转后仍然被列为相同。

现在,这是我的解决方案。您肯定需要知道我将称为 theta 的对象的旋转角度(我假设顺时针旋转为正)。起初我认为您应该旋转各个区域的边界框(例如,转换为“移动”的区域),但这要复杂得多。您应该做的是围绕对象中心和 theta 的相反方向旋转鼠标的 x 和 y 坐标。以下是一些明确的步骤:

  1. 从各自的 x 和 y 坐标(cX 和 cY)中减去对象中心的 x 位移和 y 位移。结果值给出了远离对象中心的 x 和 y 位移。

  2. 使用角度 theta 逆时针旋转生成的坐标。

  3. 将对象中心的 x 位移和 y 位移添加到上一步生成的 x 和 y 坐标中。

  4. 使用得到的 x 和 y 值作为 mouseAtTransformPosition 函数中的 cX 和 cY 值。

现在这里有一些代码来说明这一点。

cX -= eX + eW/2;
cY -= eY + eH/2;

newcX = cos(theta)*cX - sin(theta)*cY;
newcY = sin(theta)*cX + cos(theta)*cY;

newcX += eX + eW/2;
newcY += eY + eH/2;

newcX 和 newcY 将是 mouseAtTransformPosition 中实际使用的坐标。

如果这没有意义或者您有任何问题,请告诉我。

*** 更新:

我认为您以错误的方式旋转坐标。要更改旋转方向,请使用:

newcX = cos(theta)*cX + sin(theta)*cY;
newcY = -sin(theta)*cX + cos(theta)*cY;

而不是我上面的。试试这个,告诉我它是怎么回事。

于 2010-02-07T02:24:44.863 回答
1

如果您使用要转换的对象的mouseX/mouseY属性而不是其父对象(或相关的阶段)的属性,您将在对象坐标空间中获得它们。
因此,您永远不必担心旋转或缩放,并且可以保持您的代码几乎不变。

我还建议使用scaleX/scaleY来更改大小,因为width并且height会随着您旋转对象而改变。

于 2010-02-02T15:42:04.273 回答