Reflect a object along x and y axis - actionscript-3

Need to reflect a group containing objects as shown in picture.
I have a sample image for what i have done in my current progress.
Objective: Reflection of objects should be done along x and y axis as per the below image

Very easy approach: for reflection you should have copy of the object that will be reflected.
Reflection could be made by myReflectedObject.scaleY = -1
myReflectedObject.scaleY = -1;
myReflectedObject.alpha = 0.4;
//manage Y position accordingly

The simple code looks like this:
copiedDisplayObject.scaleY = -1;
copiedDisplayObject.alpha = 0.4;
That is really a specific example of reflection over a line, where the line happens to be the x axis. (ie y = 0x + 0) If you want to reflect over another line, you can use a matrix. The code below preserves previous transformations on the display object, and reflects it over a line passing through the origin.
var m:Number = 0.25; //example slope -- from line: y = mx + 0
var tmpMatrix = copiedDisplayObject.transform.matrix;
var relectMatrix:Matrix = new Matrix(1-m*m, 2*m, 2*m, m*m -1);
tmpMatrix.concat(relectMatrix);
copiedDisplayObject.transform.matrix = tmpMatrix;
I found the matrix formula here: math.stackexchange question.

Related

Position one object based on another that's rotated

I have a set of blocks which could be rotated at any angle. My task is to create an extra block to one side of the set, adjacent to the last block. I'm using Flex/AS3 and openscales. An illustration will be good to explain what I want to achieve. I apologise in advance for the crudeness of my pictures, I only have MS Paint to hand!
My current formula for the picture 2 is simply:
block5XPos += block4XPos - block3XPos;
block5YPos += block4YPos - block3YPos;
** Edit **
I cannot work with Display Objects in the usual way i.e. rotate, addChild. I'm restricted to utilising x and y values and having to re-calculate these values.
If your solution allows, you could put all your blocks in a parent movieclip, rotate that movieclip. And then just modify the x parameter when you add new blocks to the parent movieclip. This would translate the block along the "local" x axis of the rotated parent.
Pseudocode:
var parent:MovieClip = new MovieClip()
parent.rotation = 45
addChild(parent)
var block1 = new BlockClip()
block1.x = 10
parent.addChild(block1)
var block2 = new BlockClip()
block2.x = 20
parent.addChild(block2)
I figured it out. I leveraged Math.cos and Math.sin to calculate the position of the new block based on the angle and distance from the last block.
private function calculateNewSlotPosition(slot:SlotDO):void {
var blockToRadians:Number = blockDegrees * Math.PI / 180;
var cos:Number = Math.cos(blockToRadians);
var sin:Number = Math.sin(blockToRadians);
for(var k:uint = 0; k < block.polygon.length; k++) {
block.polygon[k].x += ((block.width + workBlock.gap) * cos);
block.polygon[k].y -= ((block.width + workBlock.gap) * sin);
}
}

HTML5: Inverse text-color on canvas

I want to draw text on a canvas in the inverse color of the background (to make sure the text is readible no matter the background color). I believe in oldskool bitblt-ing, this was an XOR operation.
How to do this?
Update: most of the newer browsers now support the blending mode "difference" which can achieve the same result.
context.globalCompositeOperation = "difference";
Updated demo.
Old answer:
One should think that the XOR mode for composition would do this, but unfortunately canvas' XOR only XORs the alpha bits.
By applying the following code we can however receive a result such as this:
You can make an extension to the canvas like this:
CanvasRenderingContext2D.prototype.fillInversedText =
function(txt, x, y) {
//code - see below
}
Now you can call it on the context as the normal fillText, but with a slight change:
ctx.fillInversedText(txt, x, y);
For this to work we do the following first - measure text. Currently we can only calculate width of text and then assume the height. This may or may not work well as fonts can be very tall and so forth. Luckily this will change in the future, but for now:
var tw = this.measureText(txt).width;
var th = parseInt(ctx.font, '10');
th = (th === 0) ? 10 : th; //assume default if no font and size is set
Next thing we need to do is to setup an off-screen canvas to draw the text we want ot invert:
var co = document.createElement('canvas');
co.width = tw;
co.height = th;
Then draw the actual text. Color does not matter as we are only interested in the alpha channel for this canvas:
var octx = co.getContext('2d');
octx.font = this.font;
octx.textBaseline = 'top';
octx.fillText(txt, 0, 0);
Then we extract the pixel buffers for the area we want to draw the inverted text as well as all the pixels for the off-screen canvas which now contains our text:
var ddata = this.getImageData(x, y, tw, th);
var sdata = octx.getImageData(0, 0, tw, th);
var dd = ddata.data; //cache for increased speed
var ds = sdata.data;
var len = ds.length;
And then we invert each pixel where alpha channel for pixel is greater than 0.
for (var i = 0; i < len; i += 4) {
if (ds[i + 3] > 0) {
dd[i] = 255 - dd[i];
dd[i + 1] = 255 - dd[i + 1];
dd[i + 2] = 255 - dd[i + 2];
}
}
Finally put back the inverted image:
this.putImageData(ddata, x, y);
This may seem as a lot of operations, but it goes pretty fast.
Demo (warning if you are sensitive to flicker)
(the psychedelic background is just to have some variations as fiddle needs external images and most are prevented by CORS when we use pixel manipulation).
I've removed my old answer, as it did not solve the question. As of recently, there are new globalCompositeOperations that do all kinds of great things. I've created an example that shows how to obtain inverted text. In case that link breaks, the method is essentially this:
ctx.globalCompositeOperation = "difference";
ctx.fillStyle = "white";
//draw inverted things here
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation

Three.js How to point child of Object3d to face camera?

Here is the thing. I have an Object3d that is composed of 6 planes settled to form a cube. Now, after applying quaternion rotation based on mouse input and after the cube has stopped - I need the cube to turn straight to the camera at its closest side (plane child). What I am doing now is I’m getting the current Euler angles of my Object3d matrix, applying rotation to this matrix and setting it back to my object’s quaternion with setFromRotationMatrix() function. Sometimes this method works (usually at low angles) and sometimes the Z axis behaves wrong (or maybe Y, or even all of them, can’t tell).
Now, I certainly could just calculate the closest side and apply direct quaternion of this side to my object, which works, but that gives me no animation.
I’m using this code to get my current angles: http://www.cs.princeton.edu/~gewang/projects/darth/stuff/quat_faq.html#Q37. Based on that I calculate the closest 90 degrees rotation for every axis:
function lookAtCamDeg(val){
var d = 1;
var s = 1;
var newAngle;
if(val < 0)d*=-1;
val = Math.abs(val);
if(val <= 45)s*=-1;
if(val > 45)val=90-val;
newAngle = val*d*s;
return newAngle;
}
And applying that to turn my cube:
var angles = getAngles();http://www.cs.princeton.edu/~gewang/projects/darth/stuff/quat_faq.html#Q37
var newX = lookAtCamDeg(angles.x);
var newY = lookAtCamDeg(angles.y);
var newZ = lookAtCamDeg(angles.z);
var ma = cube.matrix;
ma = ma.rotateX(-newX*DEGREES)
ma = ma.rotateY(-newY*DEGREES)
ma = ma.rotateZ(-newZ*DEGREES)
cube.quaternion.setFromRotationMatrix(ma);
What I am thinking now is to try using separate planes of my cube (children) and based on their normals apply lookAt() method, but don’t know how to do it, since I need to rotate the whole object, not just one child. Could someone please lead me to the right direction to go? What is the best way to achieve my needs?
The THREE.Quaterion object contains methods for interpolation. So calculate the quaternion value of the original face normal, the quaternion you get here from setFromRotationMatrix(ma), and then apply THREE.Quaterion.slerp() repeatedly to get in-betweens, which can apply to cube.quaternion

AS3 - Finding the Y position of a rotated object if X is known

I am trying to find out the Y position of a rotated object on stage, when only the X position is known. I am not extremely formiliar with how I'd go about doing this, but I know it'll be related to the Rotation of the border object.
What I need to do is know that based on the below X position that is worked out, what the exact maximum Y position can be before it hits the black border that is onscreen. I know that the original position is 280, but I am not sure at all how I then work out what the Y position is further down the line.
I have attached the code to find the X (all be it, it doesn't take into account any rotation as on this level it isn't needed), as well as a screenshot so you can understand clearly.
Thank you for your time.
private function init(e:Event = null):void{
var maxX:int = stage.width
var freeSpace:int = 300
var startX:int = Math.ceil(Math.random() * (maxX - (freeSpace+this.width))) + freeSpace;
this.x = startX
}
I'm not entirely sure on your question but hopefully these suggestions will help:
You can use the localToGlobal() function on a display object to return a rotated, translated, and scaled point within that display container to the stage. Example, $p:Point = myMovieClip.localToGlobal(new Point(10, 10));
A Matrix is also a nice and easy way to rotate a point. Example, var $mtx:Matrix = new Matrix(); $mtx.tx = 10; $mtx.ty = 10; $mtx.rotate(); and now $mtx.tx and $mtx.ty have the rotated result
Those probably won't answer your question, but I figured I'd mention them just in case and before I get into something more complex. Like wvxvw said you can't really solve the equation you're trying to do without some other variables. I wrote some code that shows how to find Y when comparing X to a point in a line segment:
import flash.display.Shape;
import flash.geom.Point;
import flash.display.Graphics;
import flash.events.MouseEvent;
var $s:Shape = new Shape();
addChild($s);
var borderStart:Point = new Point(stage.stageWidth/2, stage.stageHeight/2);
var borderRotation:Number = 45;
var borderLength:Number = 800;
var borderRad:Number = borderRotation * (Math.PI/180);
var borderEnd:Point = new Point(borderStart.x + Math.cos(borderRad) * borderLength, borderStart.y + Math.sin(borderRad) * borderLength);
stage.addEventListener(MouseEvent.MOUSE_MOVE, update);
function update(e:MouseEvent):void{
var $g:Graphics = $s.graphics;
$g.clear();
//Drawing the rotated border
$g.lineStyle(3, 0xff0000, .5);
$g.moveTo(borderStart.x, borderStart.y);
$g.lineTo(borderEnd.x, borderEnd.y);
//Finding if and where mouseX collides with our border
if (stage.mouseX >= Math.min(borderStart.x, borderEnd.x) && stage.mouseX <= Math.max(borderStart.x, borderEnd.x)){
var $x:Number = stage.mouseX;
//SOLVING HERE : Solve collision with X
var $percent:Number = ($x - borderStart.x)/(borderLength * Math.cos(borderRad));
var $y:Number = borderStart.y + Math.sin(borderRad) * borderLength * $percent;
//Drawing to our collision
$g.lineStyle(1, 0xffff00, .6);
$g.moveTo($x, 0);
$g.lineTo($x, $y);
$g.lineStyle(2, 0xffff00, 1);
$g.drawCircle($x, $y, 3);
trace("----\nCollision #\t" + "x: " + $x + "\ty:" + Math.round($y));
}
}
Hopefully this will give some insight on how to solve your particular issue.
I'm not sure if I'm answering the right question, because as you worded it, it's impossible to solve, or rather you would have to accept that Y can be just anything... (In order to be able to find a point in a vector space over R^2 you need a basis of two vectors of a form (x,y), but you only have a vector in R^1).
But it looks like you want to find an intersection of the "black line on the screen" - i.e. an arbitrary line and a vertical line through the lowest point of the "shape" which you want to fit. It's hard to tell from the question, what shape are you trying to fit, but if it is a rectangle, which is not rotated, then it would be either its bottom right or bottom left corner. You can then find which point to choose by comparing the angle between a horizontal line and the "black line" and the horizontal line and the bottom of the rectangle.
Next, you would need to find an intersection between these two lines, the formula can be found here: http://en.wikipedia.org/wiki/Line_intersection

find closest point to mouse position

I've got a grid of sprites.
Now I would like to drag an image on a grid-element.
Therefore I need to know which x/y of the grid-element is the closest point to the mouse-position.
All the grid-elements are stored in an array.
How can I achieve that?
You must loop through all the elements and find the smallest distance to the mouse. Then store the array index of the element. Try something like this:
// Setup variables outside of loop.
var mousePoint:Point = new Point(mouseX, mouseY);
var elementPoint:Point = new Point();
var element:Sprite;
var closestIndex:uint = 0;
var closestDist:Number;
// Loop through elements
for (var i:int = 0; i < gridElements.length; i++)
{
element = gridElements[i] as Sprite;
// Set the elementPoint's x and y rather than creating a new Point object.
elementPoint.x = element.x;
elementPoint.y = element.y;
// Find distance from mouse to element.
var dist:Number = Point.distance(mousePoint, elementPoint);
// Update closestIndex and closestDist if it's the closest.
if (i == 0 || dist < closestDist)
{
closestDist = dist;
closestIndex = i;
}
}
// Can now use closestIndex to get the element from the array.
trace('The closest element is at index', closestIndex, ', with a distance of', closestDist);
Of course, this will only get you the first closest element, so you must decide what you want to happen if there are two elements an equal distance away.
You will also need to allow for the origins of your elements. The will probably have there origins set to there top left, so you need to allow for this in your distance calculation.
You could also check for a minimum distance. So if the user is dragging too far away from any of the elements then do nothing.
If all you need is the x,y of the closest grid then all you have to do is.
var gridX:int = Math.floor(mouseX / NumberOfColumns);
var gridY:int = Math.floor(mouseY / NumberOfRows);
This will convert your mouse coordinates to your grid coordinates.
Now comes the problem. If your storing them in a 2d array then you have your x/y if your storing them in a flat array (1d) you need to look it up just like you created it.
var myObject:Object = my2dArray[gridX, gridY];
var myObject:Object = myFlatArray[(gridX * NumberOfRows) + gridY];
If you have taken care of how you create your array and push the items in it, it should be no problem to retrieve stuff without searching it.