Rotation is different after resizing movieclip - algorithm

I am trying to implement transform methods to rotate and resize a movieclip at runtime and I have a problem when recalculating the rotation to follow the mouse.
I have a squared movieclip and a rotator object (a circle) at the right bottom corner of the square where I am listening for mouse events and on mouse move I do this:
_rotation = -(Math.atan2((event.stageX - this.x ), (event.stageY - this.y ))) * 180/Math.PI;
this.rotation = rotation + 45;//this is because my rotator object is on right,bottom corner
this works perfect as long as I don´t modify the width or height of the object but if I do modify then there is a small "jump" on the rotation of the object that I am not able of avoid.
I know this is due event.stageX and even.stageY are different as the rotator object, the one with the mouse listener, has moved after the resize event but no clue how to avoid the "jump".
Please excuse my bad English

You need to rotate the object around its center.
/**
* Rotates the object based on its center
* Parameters: #obj => the object to rotate
* # rotation => angle to rotate
* */
public function RotateAroundCenter(obj:Object, rotation:Number):void
{
var bound:Rectangle = new Rectangle();
// get the bounded rectangle of objects
bound = obj.getRect(this);
// calculate mid poits
var midx1:Number = bound.x + bound.width/2;
var midy1:Number = bound.y + bound.height/2;
// assign the rotation
obj.rotation = rotation;
// assign the previous mid point as (x,y)
obj.x = midx1;
obj.y = midy1;
// get the new bounded rectangle of objects
bound = obj.getRect(this);
// calculate new mid points
var midx2:Number = bound.x + bound.width/2;
var midy2:Number = bound.y + bound.height/2;
// calculate differnece between the current mid and (x,y) and subtract
//it to position the object in the previous bound.
var diff:Number = midx2 - obj.x;
obj.x -= diff;
diff = midy2 - obj.y;
obj.y -= diff;
}
Usage:
_rotation = -(Math.atan2((event.stageX - this.x ), (event.stageY - this.y ))) * 180/Math.PI;
RotateAroundCenter(this, rotation + 45);
Check this link

Related

Move object around cube’s corner without jittering using accelerometer

I can move object (star) around cube’s corner using accelerometer. Object move following the orbit (green circle). Control inverted, if I tilt right object go left and vise versa.
While spinning cube around corner object move perfect. But when I stop spinning cube, object on one of the cube’s edges, cause of inverted control start jittering.
For example if I try to stop object between red and blue planes, it begins jumping from one plane to another.
Code for object movement
new accelX = abi_MTD_GetFaceAccelX(object.plane);
new accelY = abi_MTD_GetFaceAccelY(object.plane);
object.angle -= accelX - accelY;
if (object.angle >= 90) {
object.plane = GetRightPlane(object.plane);
object.angle -= 90;
} else if (object.angle <= 0) {
object.plane= GetBottomPlane(object.plane);
object.angle = 90 + spaceship.angle;
}
MovePointAlongCircle(OUT object.posX, OUT object.posY, object.orbit, object.angle);
Find coordinate on plane
const OBJECT _ORBIT_CENTER = 260;
new objectOrbit = 150;
MovePointAlongCircle(&posX, &posY, objectOrbit, anglePhi) {
posX = OBJECT_ORBIT_CENTER - (objectOrbit * cos(anglePhi));
posY = OBJECT _ORBIT_CENTER - (objectOrbit * sin(anglePhi));
}
I can get accelerometer values individually on each plane or like the cube is a one thing.
Trigonometric functions like sin and cos use fixed point and look up table.
I've got atan function, which return angle [-45; 45].
Atan(x) {
return ((PI_4_FIXED * x >> FP) - ((x * (ABS(x) - 256) >> FP) * (62 + (17 * ABS(x) >> FP)) >> FP)) * RAD_2_DEG >> FP;
}

three.js: Limiting camera's rotation

I'm working with three.js, attempting to model a real world camera. As such, I'd like to limit its axis of rotation to 90 degrees along x and y axises.
Is there a simply way to do this? My current code isn't working particularly well (and goes crazy when you attempt to move the camera past the X and Y boundaries simultaneously)
if(xRot != null && xRot != undefined){
camera.rotateX(xRot);
}
if(yRot != null && yRot != undefined){
camera.rotateY(yRot);
}
if(camera.rotation.x < minCameraRotX){
camera.rotation.x = minCameraRotX;
}else if (camera.rotation.x > maxCameraRotX){
camera.rotation.x = maxCameraRotX;
}
if(camera.rotation.y < minCameraRotY){
camera.rotation.y = minCameraRotY;
}else if(camera.rotation.y > maxCameraRotY){
camera.rotation.y = maxCameraRotY;
}
Any advice would be greatly appreciated!!!
I actually managed to find a solution by checking some of the existing code in a Three.js demo for a library called PointerLock. The idea is to actually stack multiple objects inside each other: start with an object that moves horizontally (the yaw object), place another object inside the yaw object that moves vertically (the pitch object), and then place the actual camera inside the pitch object.
Then, you only rotate the outside objects (yaw and pitch) along their respective axises, so if you rotate both, they'll self-correct. For example, if you rotate the yaw 45 degrees along the y-axis (making it turn to the right) and then rotate the pitch 45 degrees (making it turn downward), the pitch will go 45 degrees downward from the yaw's already rotated position.
Given that the camera is inside both, it just points wherever the yaw and pitch direct it.
Here is the code
/*
* CAMERA SETUP
*
* Root object is a Yaw object (which controls horizontal movements)
* Yaw object contains a Pitch object (which controls vertical movement)
* Pitch object contains camera (which allows scene to be viewed)
*
* Entire setup works like an airplane with a
* camera embedded in the propellor...
*
*/
// Yaw Object
var yawObject = new THREE.Object3D();
// Pitch Object
var pitchObject = new THREE.Object3D();
// Camera Object
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// Max Camera angles (in radians)
var minCameraRotX = 0.5;
var maxCameraRotX = 0.5;
var minCameraRotY = 1;
var maxCameraRotY = 1;
// Setup
yawObject.add( pitchObject );
pitchObject.add( camera );
scene.add(yawObject);
...
var rotateCamera = function(xRot, yRot, zRot){
yawObject.rotation.y += yRot;
pitchObject.rotation.x += xRot;
// Enforce X-axis boundaries (rotates around y-axis)
yawObject.rotation.y = Math.max( minCameraRotY, Math.min( maxCameraRotY, yawObject.rotation.y ) );
// Enforce Y-axis boundaries (rotates around x-axis)
pitchObject.rotation.x = Math.max( minCameraRotX, Math.min( maxCameraRotX, pitchObject.rotation.x ) );
}
Here is the source code I referenced: https://github.com/mrdoob/three.js/blob/acda8a7c8f90ce9b71088e903d8dd029e229678e/examples/js/controls/PointerLockControls.js
Also, this is sort of cheesy, but this little plane cartoon helped me visual exactly what was going on in my setup

Rotate a Sprite around another Sprite -libGDX-

video game link
I'm trying to make a game (see link above) , and I need to have the stick rotate around himself to maintain the orientation face to center of the circle.
this is how I declare the Sprite, and how I move it around the circle:
declaration:
line = new Sprite(new Texture(Gdx.files.internal("drawable/blockLine.png")));
line.setSize(140, 20);
lineX = Gdx.graphics.getWidth()/2 - line.getWidth()/2;
lineY = (Gdx.graphics.getHeight()/2 - line.getHeight()/2) + circle.getHeight()/2;
movement:
Point point = rotatePoint(new Point(lineX, lineY), new Point(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), angle+= Gdx.graphics.getDeltaTime() * lineSpeed);
line.setPosition(point.x, point.y);
rotatePoint function:
Point rotatePoint(Point point, Point center, double angle){
angle = (angle ) * (Math.PI/180); // Convert to radians
float rotatedX = (int) (Math.cos(angle) * (point.x - center.x) - Math.sin(angle) * (point.y-center.y) + center.x);
float rotatedY = (int) (Math.sin(angle) * (point.x - center.x) + Math.cos(angle) * (point.y - center.y) + center.y);
return new Point(rotatedX,rotatedY);
}
Any sugestions ?
I can't test right now but I think the rotation of the line should simply be:
Math.atan2(rotatedPoint.getOriginX() - middlePoint.getOriginX(), rotatedPoint.getOriginY() - middlePoint.getOriginY()));
Then you'll have to adjust rad to degrees or whatever you'll use. Tell me if it doesn't work!
I would take a different approach, I just created a method that places n Buttons around a click on the screen. I am using something that looks like this:
float rotation; // in degree's
float distance; //Distance from origin (radius of circle).
vector2 originOfRotation; //Center of circle
vector2 originOfSprite; //Origin of rotation sprite we are calculating
Vector2 direction = new vector2(0, 1); //pointing up
//rotate the direction
direction.rotate(rotation);
// add distance based of the direction. Warning: originOfRotation will change because of chaining method.
// use originOfRotation.cpy() if you do not want to init each frame
originOfSprite = originOfRotation.add(direction.scl(distance));
Now you have the position of your sprite. You need to increment rotation by x each frame to have it rotate. If you want the orientation of the sprite to change you can use the direction vector, probably rotated by 180 again. Efficiency wise I'm not sure what the difference would be.

direct2d image viewer How to convert screen coordinates to image coordinates?

I'm trying to figure out how to convert the mouse position (screen coordinates) to the corresponding point on the underlying transformed image drawn on a direct2d surface.
the code here should be considered pseudo code as i'm using a modified c++/CLI wrapper around direct2d for c#, you won't be able to compile this in anything but my own project.
Render()
{
//The transform matrix combines a rotation, followed by a scaling then a translation
renderTarget.Transform = _rotate * _scale * _translate;
RectF imageBounds = new RectF(0, 0, _imageSize.Width, _imageSize.Height);
renderTarget.DrawBitmap(this._image, imageBounds, 1, BitmapInterpolationMode.Linear);
}
Zoom(float zoomfactor, PointF mousepos)
{
//mousePos is in screen coordinates. I need to convert it to image coordinates.
Matrix3x2 t = _translate.Invert();
Matrix3x2 s = _scale.Invert();
Matrix3x2 r = _rotate.Invert();
PointF center = (t * s * r).TransformPoint(mousePos);
_scale = Matrix3x2.Scale(zoomfactor, zoomfactor, center);
}
This is incorrect, the scale center starts moving around wildly when the zoomfactor increases or decreases smoothly, the resulting zoom function is not smooth and flickers a lot even though the mouse pointer is immobile on the center of the client surface. I tried all the combinations I could think of but could not figure it out.
If I set the scale center point as (imagewidth/2, imageheight/2), the resulting zoom is smooth but is always centered on the image center, so I'm pretty sure the flicker isn't due to some other buggy part of the program.
Thanks.
I finally got it right
this gives me perfectly smooth (incremental?, relative?) zooming centered on the client center
(I abandoned the mouse position idea since I wanted to use mouse movement input to drive the zoom)
protected float zoomf
{
get
{
//extract scale factor from scale matrix
return (float)Math.Sqrt((double)((_scale.M11 * _scale.M11)
+ (_scale.M21 * _scale.M21)));
}
}
public void Zoom(float factor)
{
factor = Math.Min(zoomf, 1) * 0.006f * factor;
factor += 1;
Matrix3x2 t = _translation;
t.Invert();
PointF center = t.TransformPoint(_clientCenter);
Matrix3x2 m = Matrix3x2.Scale(new SizeF(factor, factor), center);
_scale = _scale * m;
Invalidate();
}
Step1: Put android:scaleType="matrix" in ImageView XML file
Step 2: Convert screen touch points to Matrix value.
Step 3: Divide each matrix value with Screen density parameter to
get same coordinate value in all screens.
**XML**
<ImageView
android:id="#+id/myImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
android:src="#drawable/ga"/>
**JAVA**
#Override
public boolean onTouchEvent(MotionEvent event) {
float[] point = new float[]{event.getX(), event.getY()};
Matrix inverse = new Matrix();
getImageMatrix().invert(inverse);
inverse.mapPoints(point);
float density = getResources().getDisplayMetrics().density;
int[] imagePointArray = new int[2];
imagePointArray[0] = (int) (point[0] / density);
imagePointArray[1] = (int) (point[1] / density);
Rect rect = new Rect( imagePointArray[0] - 20, imagePointArray[1] - 20, imagePointArray[0] + 20, imagePointArray[1] + 20);//20 is the offset value near to the touch point
boolean b = rect.contains(267, 40);//267,40 are the predefine image coordiantes
Log.e("Touch inside ", b + "");
return true;
}

Transform mouse coordinates to 3d coordinates

I have the following problem:
I have my mouse coordinates and I have a Model (Data Points) and I want the 3d Coordinates of my mouse coordinates and my lookAt Vector of this coordinates, so that I can make a raycast with the object, so that I can see the 3d values of the data points. So I want to click with the mouse and then I want to see the coordinates of the datapoint I clicked at.
I have the following from a tutorial, but it doesn't work. The ray origin and ray direction are not correct (I draw I line from ray origin in the ray direction and the ray origin isn't right:
Can anyone help me? Here is the code:
// Move the mouse cursor coordinates into the -1 to +1 range.
pointX = ((2.0f * (float)mouseX) / (float) screen_width) - 1.0f;
pointY = (((2.0f * (float)mouseY) / (float) screen_height) - 1.0f) * -1.0f;
m_D3D->GetProjectionMatrix(projectionMatrix);
pointX = pointX / projectionMatrix._11;
pointY = pointY / projectionMatrix._22;
// Get the inverse of the view matrix.
m_Camera->GetViewMatrix(viewMatrix);
D3DXMatrixInverse(&inverseViewMatrix, NULL, &viewMatrix);
// Calculate the direction of the picking ray in view space.
direction.x = (pointX * inverseViewMatrix._11) + (pointY * inverseViewMatrix._21)+
inverseViewMatrix._31;
direction.y = (pointX * inverseViewMatrix._12) + (pointY * inverseViewMatrix._22)
+ inverseViewMatrix._32;
direction.z = (pointX * inverseViewMatrix._13) + (pointY * inverseViewMatrix._23)
+ inverseViewMatrix._33;
// Get the origin of the picking ray which is the position of the camera.
origin = m_Camera->GetPosition();
// Get the world matrix and translate to the location of the sphere.
m_Impact->GetWorldMatrix(worldMatrix);
//D3DXMatrixTranslation(&translateMatrix, -5.0f, 1.0f, 5.0f);
//D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &translateMatrix);
// Now get the inverse of the translated world matrix.
D3DXMatrixInverse(&inverseWorldMatrix, NULL, &worldMatrix);
D3DXVec3TransformCoord(&rayOrigin, &origin, &inverseWorldMatrix);
D3DXVec3TransformNormal(&rayDirection, &direction, &inverseWorldMatrix);
// Normalize the ray direction.
D3DXVec3Normalize(&rayDirection, &rayDirection);
//collision_object->setTransform(col_matrix);
collision_model->setTransform(col_matrix);
float collision_point[3];
//bool collision_result = collision_object ->rayCollision(rayOrigin,
rayDirection, true);
bool collision_result = collision_model ->rayCollision(rayOrigin,
rayDirection, true);
if(collision_result == true)
{
intersect = true;
//collision_object->getCollisionPoint(collision_point, true);
collision_model->getCollisionPoint(collision_point, false);
*coordX = collision_point[0];
*coordY = collision_point[1];
*coordZ = collision_point[2];
}
One simple way to build a ray from mouse is as follow (pseudo code)
Get mouse coords to -1 -> 1 range (as you already do)
Create view projection matrix (view*projection)
Invert it.
Create 2 mouse vectors:
near = Vector3(mousex,mousey,0);
far = Vector3(mousex,mousey,1);
rayorigin = transformcoord(near, inverseviewprojection);
rayend = transformcoord(far, inverseviewprojection);
raydir = normalize(rayend-rayorigin);

Resources