2

状況

特定の要素位置に対する現在のマウス位置に必要な変換タイプを返す次のメソッド (actionscript 3 では、これはフラッシュ アプリケーションです) を作成しました。

要素は、移動、スケーリング、および回転できます。このメソッドは、これらの変換のいずれかが指定された座標に適用できるかどうかを返します。

(心配しないでください。このメソッドをデバッグする必要はありません。機能します。ここに追加して、私が何をしているのかを理解してください)

//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、幅、および高さは、表示される表示オブジェクトのものと常に同じであるため、これによって問題が発生することはありません。

さて、これらは結果です:

  • ローテーションがなければ、すべてが期待どおりに機能します
  • 約 45 回転で、ビジュアル表示オブジェクトにマウスを合わせると、次のようになります。
    • 下中央: 「scalerLeft」を返しますが、「scalerDown」を返す必要があります。
    • 右中央: scalerDown を返しますが、scalerRight を返す必要があります
    • 上部中央: scalerRight を返しますが、scalerUp を返す必要があります
    • 左中央: scalerUp を返しますが、scalerLeft を返す必要があります (ここでオフセット パターンに注意してください)。
    • ムーバーはかなり正確に戻ってくるようです
    • 回転子は、本来あるべき場所ではなく、コーナーの真下に戻っているようです
    • bottomLeft スケーラーは右下隅に戻っているようです。これと同じオフセットが問題であり、おそらく他のすべてのスケーラーでも同じであると思います

これはデバッグするのが面倒ですが、これが役立つかもしれません。

Justin の代替テキストの更新 #2 http://feedpostal.com/transformBug.gif オフセット/バグは、ローテーションが高くなるほど強くなるようです。0 回転では、このバグは発生しません。

これはあなたや他の誰かにとって意味がありますか? 前もって感謝します。

4

2 に答える 2

2

ここでいくつかの仮定を立てました。オブジェクトは長方形で 2 次元 (3D 回転なし) であると想定しています。これは、物事を単純化するために変換できる唯一のオブジェクトであると想定しています。また、他の回答のコメントから、オブジェクトの寸法 (eX、eY、eW、eH) が回転後も同じとしてリストされていることを理解しています。

さて、これが私の解決策です。シータと呼ぶオブジェクトの回転角度 (時計回りの回転に対して正であると仮定します) を知る必要があります。最初は、さまざまな領域 (たとえば、変換が「ムーバー」である領域) の境界ボックスを回転させる必要があると考えていましたが、それははるかに複雑です。すべきことは、マウスの x 座標と y 座標を、オブジェクトの中心を中心に、シータの反対方向に回転させることです。いくつかの明示的な手順を次に示します。

  1. それぞれの x 座標と y 座標 (cX と cY) から、オブジェクトの中心の x 変位と y 変位を引きます。結果の値は、オブジェクトの中心から離れた x および y 変位を示します。

  2. 角度シータを使用して、結果の座標を反時計回りに回転します。

  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を使用してサイズを変更することもお勧めします。widthheight

于 2010-02-02T15:42:04.273 に答える