Scale, Position & Rotate Parent object to make chi

2019-09-01 04:41发布

问题:

Using the first photo below, let's say:

  • The red outline is the stage bounds
  • The gray box is a Sprite on the stage.
  • The green box is a child of the gray box and has a rotation set.
  • both display object are anchored at the top-left corner (0,0).

I'd like to rotate, scale, and position the gray box, so the green box fills the stage bounds (the green box and stage have the same aspect ratio).

I can negate the rotation easily enough

parent.rotation = -child.rotation

But the scale and position are proving tricky (because of the rotation). I could use some assistance with the Math involved to calculate the scale and position.

This is what I had tried but didn't produce the results I expected:

gray.scaleX = stage.stageWidth / green.width;
gray.scaleY = gray.scaleX;
gray.x = -green.x;
gray.y = -green.y;
gray.rotation = -green.rotation;

I'm not terribly experienced with Transformation matrices but assume I will need to go that route.

Here is an .fla sample what I'm working with: SampleFile

回答1:

You can use this answer: https://stackoverflow.com/a/15789937/1627055 to get some basics. First, you are in need to rotate around the top left corner of the green rectangle, so you use green.x and green.y as center point coordinates. But in between you also need to scale the gray rectangle so that the green rectangle's dimensions get equal to stage. With uniform scaling you don't have to worry about distortion, because if a gray rectangle is scaled uniformly, then a green rectangle will remain a rectangle. If the green rectangle's aspect ratio will be different than what you want it to be, you'd better scale the green rectangle prior to performing this trick. So, you need to first transpose the matrix to offset the center point, then you need to add rotation and scale, then you need to transpose it away. Try this set of code:

var green:Sprite; // your green rect. The code is executed within gray rect
var gr:Number=green.rotation*Math.PI/180; // radians
var gs:Number=stage.stageWidth/green.width; // get scale ratio
var alreadyTurned:Boolean; // if we have already applied the rotation+scale
function turn():void {
    if (alreadyTurned) return;
    var mat:flash.geom.Matrix=this.transform.matrix;
    mat.scale(gs,gs);
    mat.translate(-gs*green.x,-gs*green.y);
    mat.rotate(-1*gr);
    this.transform.matrix=mat;
    alreadyTurned=true;
}

Sorry, didn't have time to test, so errors might exist. If yes, try swapping scale, translate and rotate, you pretty much need this set of operations to make it work.



回答2:

For posterity, here is what I ended up using. I create a sprite/movieClip inside the child (green) box and gave it an instance name of "innerObj" (making it the actually content).

var tmpRectangle:Rectangle = new Rectangle(greenChild.x, greenChild.y, greenChild.innerObj.width * greenChild.scaleX, greenChild.innerObj.height * greenChild.scaleY);

//temporary reset 
grayParent.transform.matrix = new Matrix();

var gs:Number=stage.stageHeight/(tmpRectangle.height); // get scale ratio

var mat:Matrix=grayParent.transform.matrix;
mat.scale(gs,gs);
mat.translate(-gs * tmpRectangle.x, -gs * tmpRectangle.y);
mat.rotate( -greenChild.rotation * Math.PI / 180);

grayParent.transform.matrix = mat;


回答3:

If the registration point of the green box is at one of it's corners (let's say top left), and in order to be displayed this way it has a rotation increased, then the solution is very simple: apply this rotation with negative sign to the parent (if it's 56, add -56 to parent's). This way the child will be with rotation 0 and parent -> -56;

But if there is no rotation applied to the green box, there is almost no solution to your problem, because of wrong registration point. There is no true way to actually determine if the box is somehow rotated or not. And this is why - imagine you have rotated the green box at 90 degrees, but changed it's registration point and thus it has no property for rotation. How could the script understand that this is not it's normal position, but it's flipped? Even if you get the bounds, you will see that it's a regular rectangle, but nobody know which side is it's regular positioned one.

So the short answer is - make the registration point properly, and use rotation in order to display it like in the first image. Then add negative rotation to the parent, and its all good :)

Edit: I'm uploading an image so I can explain my idea better:

 

As you can see, I've created a green object inside the grey one, and the graphics INSIDE are rotated. The green object itself, has rotation of 0, and origin point - top left.

@Vesper - I don't think that the matrix will fix anything in this situation (remember that the green object has rotation of 0).

Otherwise I agree, that the matrix will do a pretty job, but there are many ways to do it :)