How to rotate MXML component round its center like a wheel respectfully to mouse? - apache-flex

So I have that panel or any other mxml component. I want somehow to rotate it around like a wheel of a car with which you drive it... loke a Racing wheel... sow like when mousebutton is down it captures pont of component... when you move mouse component rotates (not moves) according to new mouse position... How to rotate MXML component round its center like a wheel respectfully to mouse?
welll feel free to edit this question because I know Ive formulated it in a bad way...

Add these to a utility class if you don't want to add a dependency to fl.motion.*
/**
* Rotates a matrix about a point defined inside the matrix's transformation space.
* This can be used to rotate a movie clip around a transformation point inside itself.
*
* #param m A Matrix instance.
*
* #param x The x coordinate of the point.
*
* #param y The y coordinate of the point.
*
* #param angleDegrees The angle of rotation in degrees.
* #playerversion Flash 9.0.28.0
* #langversion 3.0
* #keyword Matrix, Copy Motion as ActionScript
* #see flash.geom.Matrix
*/
public static function rotateAroundInternalPoint(m:Matrix, x:Number, y:Number, angleDegrees:Number):void
{
var point:Point = new Point(x, y);
point = m.transformPoint(point);
m.tx -= point.x;
m.ty -= point.y;
m.rotate(angleDegrees*(Math.PI/180));
m.tx += point.x;
m.ty += point.y;
}
/**
* Rotates a matrix about a point defined outside the matrix's transformation space.
* This can be used to rotate a movie clip around a transformation point in its parent.
*
* #param m A Matrix instance.
*
* #param x The x coordinate of the point.
*
* #param y The y coordinate of the point.
*
* #param angleDegrees The angle of rotation in degrees.
* #playerversion Flash 9.0.28.0
* #langversion 3.0
* #keyword Matrix, Copy Motion as ActionScript
* #see flash.geom.Matrix
*/
public static function rotateAroundExternalPoint(m:Matrix, x:Number, y:Number, angleDegrees:Number):void
{
m.tx -= x;
m.ty -= y;
m.rotate(angleDegrees*(Math.PI/180));
m.tx += x;
m.ty += y;
}
They are MatrixTransformer's rotateAroundInternalPoint() and rotateAroundExternalPoint()
That would be for 2d. For 3d see transformAround.
Don't forget to check if layout siblings are updated properly or not.
HTH

I believe you can rotate the component using the rotateX, rotateY, and rotateZ properties:
http://docs.huihoo.com/flex/4/mx/core/UIComponent.html#rotationX
Just make that happen in response to a mouse click.

Related

Matrix function-- how to add an "up" vector?

A friend gave me some code that creates a matrix that rotates from one vector to another vector. Very useful for pointing things at one another.
An issue that's come up is, often the matrix will do odd flips in its rotating. I.E. I'll end up with a result that's rotated correctly-- but is upside down in Z, or something like that.
Is there a way to add an up-vector to this code, to force the matrix to avoid rotating around the axis of the up-direction if possible?
Here's the code:
Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)
{
theV1.Normalize();
theV2.Normalize();
float aDot=theV1.Dot(theV2);
if (gMath.Abs(aDot)>=1.0f-gMath.mMachineEpsilon)
{
if (aDot<0)
{
Vector aPerp=theV1.Perp(); // We don't care which perp, we just need a perp
RotateAroundAxis3D(aPerp,180);
}
}
else
{
Vector aAxis;
float aAngle=0;
aAxis=gMath.Cross(theV1,theV2);
aAngle=gMath.Deg((float)acos(gMath.Dot(theV1,theV2)));
RotateAroundAxis3D(aAxis,aAngle);
}
return *this;
}
Edit: Added the code for the RotateAroundAxis3D function...
Matrix& Matrix::RotateAroundAxis3D(Vector theVector, float theAngle)
{
//
// Multiply the angle by -1 to put it into Raptis Space.
//
theAngle=180-theAngle;
theVector.Normalize();
Matrix aMat;
float aSin=gMath.Sin(theAngle);
float aCos=gMath.Cos(theAngle);
aMat.m00=(1.0f - aCos) * theVector.mX * theVector.mX + aCos;
aMat.m10=(1.0f - aCos) * theVector.mX * theVector.mY - aSin * theVector.mZ;
aMat.m20=(1.0f - aCos) * theVector.mX * theVector.mZ + aSin * theVector.mY;
aMat.m01=(1.0f - aCos) * theVector.mY * theVector.mX + aSin * theVector.mZ;
aMat.m11=(1.0f - aCos) * theVector.mY * theVector.mY + aCos;
aMat.m21=(1.0f - aCos) * theVector.mY * theVector.mZ - aSin * theVector.mX;
aMat.m02=(1.0f - aCos) * theVector.mZ * theVector.mX - aSin * theVector.mY;
aMat.m12=(1.0f - aCos) * theVector.mZ * theVector.mY + aSin * theVector.mX;
aMat.m22=(1.0f - aCos) * theVector.mZ * theVector.mZ + aCos;
return Multiply(&aMat);
}
I assume the function:
Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)
should rotate this so theV1 becomes theV2. If the case then in my opinion the case if (gMath.Abs(aDot)>=1.0f-gMath.mMachineEpsilon) this should not do anything, but you are rotating by 180deg around unaligned perpendicular vector to theV1. That is simply wrong I would leave the matrix as is in such case without any change so:
Matrix& Matrix::VectorToVector(Vector theV1, Vector theV2)
{
theV1.Normalize();
theV2.Normalize();
float aDot=theV1.Dot(theV2);
if (gMath.Abs(aDot)<1.0f-gMath.mMachineEpsilon)
{
Vector aAxis;
float aAngle=0;
aAxis=gMath.Cross(theV1,theV2);
aAngle=gMath.Deg((float)acos(gMath.Dot(theV1,theV2)));
RotateAroundAxis3D(aAxis,aAngle);
}
return *this;
}
If the problem persists then the cause might be in RotateAroundAxis3D(aAxis,aAngle); however without seeing its implementation its hard to say. If it uses quaternions or Euler angles it might be the reason. If the case take a look at this:
Creating a cube with only 2 known points
the function vec3 rotate(float ang,vec3 axis,vec3 p) rotates vector you can change it to rotate matrix by rotating its 3 basis vectors and origin.
btw there is also another option for doing this aligning see:
Problem superimposing and aligning 3D triangles

2d physics ball bouncing and rolling on incline response

I asked this question before but it got closed because it said I was asking for recommendations which isn't allowed.
Really I'm just looking for a solution whether it's from a book,website or someone who knows how to do this.
I progressed somewhat since I asked the question the last time, but anyways:
So far I've got a program where you can spawn balls which can collide with other balls and bounce off the window boundaries just fine, you can also draw a linestrip (am using sfml as I'm just a beginner and it requires very little setting up before you can get going with coding), so you hold down the mouse and every however many pixels it'll set the line you're currently drawing and start a new one at the end, so I can either do straight edges or change the setting to make a new line every pixel and make very ugly curves with the mouse (need to figure out how to do splines).
It makes no difference for the collision as it finds the closest point on the line every frame.
So dropping the ball onto the incline is fine, it bounces off like it should, or even several times,
but getting it to roll is a different story, even if you start the ball on the incline with 0 velocity as soon as it starts colliding it gets sent up off the incline instead of moving along it, and starts doing tiny bounces.
The only solution I found, which is terrible, is to time each bounce (or height of bounce I guess) and when its low enough to stop it bouncing and only have gravity act on it.
I'd be happy with it except what happens is it will bounce lower and lower until it reaches the
threshold, at which point it visibly slows down before it starts accelerating again rolling down the incline, which looks really bad, like it comes to a halt and starts getting pulled along.
Ideally I'd like it to actually simulate the physical forces rather than having to resort to tricks like timing the bounces.
While I was writing this I put in some code to work out what the angle is that the ball hits the incline at and I think the problem lies there, it's fine if it hits it from free fall but when rolling the angle shows as about 67-72 degrees when it should be..0 i guess?
Any help appreciated.
Here's the code for the collision.
void Particle::collideRamp(sf::Vector2f cp,sf::Vector2f l1,sf::Vector2f l2) {
//distance between ball and closest point on line
float dx = x - cp.x;
float dy = y - cp.y;
float distance = hypot(dx, dy);
//find line normal
float lx = l2.x - l1.x;
float ly = l2.y - l1.y;
sf::Vector2f LineNormal = normalize(ly, -lx);
//make velocity and projection same length so can mirror velocity against normal
sf::Vector2f normalMag(velocity.x * LineNormal.x,velocity.y * LineNormal.y);
sf::Vector2f Projection = LineNormal * hypotf(normalMag.x, normalMag.y);
sf::Vector2f vel = normalize(velocity.x, velocity.y) * hypotf(normalMag.x, normalMag.y);
//working on making circles rotate but early days
float rsx = prevx - x;
float rsy = prevy - y;
float rSpeed = hypot(rsx, rsy) / circumference;
//work out gravity forces for the incline, sin#mg down incline etc.
sf::Vector2f gravPerpendicular = normalize(-ly, lx);
sf::Vector2f gravParallell = normalize(lx, ly);
float gravPerMag;
float gravParMag;
gravParMag = sin(M_halfPI + atan2f(gravParallell.x,gravParallell.y));
gravPerMag = cos(M_halfPI + atan2f(gravParallell.x,gravParallell.y));
//// Collision detected.
if (distance < (radius)) {
//work out angle the ball struck the incline
float iAngle = atan2f(lx, ly) + atan2f(velocity.x, velocity.y);
//cout << iAngle * 180 / M_PI << " aft " << endl;
//make sure its 0-90
if (iAngle > 1.5708)
iAngle = 1.5708 - (iAngle - 1.5708);
//move the ball back if it went past the line by the amount it passed it by
sf::Vector2f v = normalize(velocity.x + forceAcc.x, velocity.y + forceAcc.y);
float overlap = (radius - distance );
x -= v.x * overlap;
y -= v.y * overlap;
rotationSpeed = rSpeed;
//messing with changing the angle only if bounce is a certain height as this is what's causing the
//problem i think, however the ball slows down before it starts rolling making it look weird
if (collClock.getElapsedTime().asSeconds() > 0.01) {
sf::Vector2f newVel = ((velocity + Projection) + Projection);
forceAcc = newVel;
float e = elasticity * elasticity;
forceAcc *= e;
velocity = sf::Vector2f(0, 0);
}
//add gravity forces, since the force that goes along the line normal is cancelled out
//by an equal force from the line I guess it doesn't need to be added?
//accelerateI(sf::Vector2f(-sin(gravPerpendicular) * gravPerMag * gravity * mass, cos(gravPerpendicular) * gravPerMag * gravity * mass));
//accelerate(sf::Vector2f(sin(gravPerpendicular) * gravPerMag * gravity * mass, -cos(gravPerpendicular) * gravPerMag * gravity * mass));
//this one rolls it down the incline
accelerateI(sf::Vector2f(gravParallell.x * gravParMag * gravity * mass, gravParallell.y * gravParMag * gravity * mass ));
//trying wether subtracting gravity helps
//accelerateI(sf::Vector2f(0, -1 * gravity * mass));
//friction
//accelerateI(sf::Vector2f(gravParallell.x * forceAcc.x * friction * mass, gravParallell.y * forceAcc.y * friction * mass));
collClock.restart();
}
}
Thanks guys

AddForce transform.forward does not work in 2D unity

GetComponent<Rigidbody2D>().AddForce(transform.forward * Time.deltaTime * forceGathered, ForceMode2D.Impulse);
does not make gameobject move in 2D Unity.
I would like to make force gameobject according to another game object's rotation direction.
GetComponent() requires a parameter, in your case Rigidbody2D, so it should be like this:
GetComponent(typeof(Rigidbody2D)).AddForce(transform.forward * Time.deltaTime * forceGathered, ForceMode2D.Impulse);
...and the shorter version would be:
GetComponent<Rigidbody2D>().AddForce(transform.forward * Time.deltaTime * forceGathered, ForceMode2D.Impulse);
Also, I would recommended you to cache the Rigidbody2D component as it can get very expensive to use GetComponent() every time you need to access it.
It would be better to cache it on start:
Rigidbody2D rg;
void Start(){
rg = GetComponent<Rigidbody2D>();
}
void YourMovementFunction(){
if (!rg) return;
rg.AddForce(transform.forward * Time.deltaTime * forceGathered, ForceMode2D.Impulse);
}

nvd3 scatterplot: labels on bullets

I have a requirement that the bullets on a specific implementation of a scatterplot needs to have labels next to them, however, it is known that many of the datapoints in the set are identical or very close to one another, so if I were to set labels on a fixed coordinate relative to the bullet, the labels would stack on top of eachother and not be readable.
I want to implement this so that the labels will give way for eachother - moving around, so they don't overlap - and I am thinking that this is a common enough idea that some approach already exists, but I have no idea what to search for. Does this concept have a name?
I would ofcource appreciate an implementation example, but that is not the most important thing. I am sure I can solve it myself, but I'd rather not reinvent something that someone else has already done better.
The image above displays examples of bullets on top of and close to each other
I ended up finding inspiration in Simulated Annealing.
My solution looks like this
/**
* Implements an algorithm for placing labels on a chart in a way so that they
* do not overlap as much.
* The approach is inspired by Simulated Annealing
* (https://en.wikipedia.org/wiki/Simulated_annealing)
*/
export class Placer {
private knownPositions: Coordinate[];
private START_RADIUS = 20;
private RUNS = 15;
private ORIGIN_WEIGHT = 2;
constructor() {
this.knownPositions = []
}
/**
* Get a good spot to place the object.
*
* Given a start coordinate, this method tries to find the best place
* that is close to that point but not too close to other known points.
*
* #param {Coordinate} coordinate
* #returns {Coordinate}
*/
getPlacement(coordinate: Coordinate) : Coordinate {
let radius = this.START_RADIUS;
let lastPosition = coordinate;
let lastScore = 0;
while (radius > 0) {
const newPosition = this.getRandomPosition(coordinate, radius);
const newScore = this.getScore(newPosition, coordinate);
if (newScore > lastScore) {
lastPosition = newPosition;
lastScore = newScore;
}
radius -= this.START_RADIUS / this.RUNS;
}
this.knownPositions.push(lastPosition);
return lastPosition;
}
/**
* Return a random point on the radius around the position
*
* #param {Coordinate} position Center point
* #param {number} radius Distance from `position` to find a point
* #returns {Coordinate} A random point `radius` distance away from
* `position`
*/
private getRandomPosition(position: Coordinate, radius:number) : Coordinate {
const randomRotation = radians(Math.random() * 360);
const xOffset = Math.cos(randomRotation) * radius;
const yOffset = Math.sin(randomRotation) * radius;
return {
x: position.x + xOffset,
y: position.y + yOffset,
}
}
/**
* Returns a number score of a position. The further away it is from any
* other known point, the better the score (bigger number), however, it
* suffers a subtraction in score the further away it gets from its origin
* point.
*
* #param {Coordinate} position The position to score
* #param {Coordinate} origin The initial position before looking for
* better ones
* #returns {number} The representation of the score
*/
private getScore(position: Coordinate, origin: Coordinate) : number {
let closest: number = null;
this.knownPositions.forEach((knownPosition) => {
const distance = Math.abs(Math.sqrt(
Math.pow(knownPosition.x - position.x, 2) +
Math.pow(knownPosition.y - position.y, 2)
));
if (closest === null || distance < closest) {
closest = distance;
}
});
const distancetoOrigin = Math.abs(Math.sqrt(
Math.pow(origin.x - position.x, 2) +
Math.pow(origin.y - position.y, 2)
));
return closest - (distancetoOrigin / this.ORIGIN_WEIGHT);
}
}
There is room for improvement in the getScore method, but the results are good enough for my case.
Basically, all points try to move to a random position in a given radius and sees if that position is "better" than the original. The algorithm keeps doing that for a smaller and smaller radius until radius = 0.
The class keeps track of all known points, so that when you try to place point number two, the scoring can account for the presence of point number one.

World to screen coordinates in Unity

For my current project it is necessary, that I compute the screen coordinates of a given point in the world space in Unity.
I used this tutorial to write a methode to do so.
After some debugging the x and y screen coordinate are correct, but my z coordinates looks wrong and I have some more questions:
static public Vector3 convertWorldToScreenCoordinates (Vector3 point, PhotoData photoData)
{
// get the camera
Camera camera = GameObject.Find (photoData.cameraName).camera;
/*
* 1 convert P_world to P_camera
*/
Vector4 pointInCameraCoodinates = convertWorldToCameraCoordinates (point, photoData);
/*
* 2 convert P_camera to P_clipped
*/
Vector4 pointInClipCoordinates = camera.projectionMatrix * pointInCameraCoodinates;
/*
* 3 convert P_clipped to P_ndc
* Normalized Device Coordinates
*/
Vector3 pointInNdc = pointInClipCoordinates / pointInClipCoordinates.w;
/*
* 4 convert P_ndc to P_screen
*/
Vector3 pointInScreenCoordinates;
pointInScreenCoordinates.x = camera.pixelWidth / 2.0f * (pointInNdc.x + 1);
pointInScreenCoordinates.y = camera.pixelHeight / 2.0f * (pointInNdc.y + 1);
pointInScreenCoordinates.z = ((camera.farClipPlane - camera.nearClipPlane) * pointInNdc.z + (camera.farClipPlane + camera.nearClipPlane)) / 2.0f;
// return screencoordinates
return pointInScreenCoordinates;
}
PhotoData is a class, that contains some information about the camera. The important part here is that I can access the camera.
static public Vector4 convertWorldToCameraCoordinates (Vector3 point, PhotoData photoData)
{
// translate the point by the negative camera-offset
//and convert to Vector4
Vector4 translatedPoint = point - photoData.cameraPosition;
// by default translatedPoint.w is 0
translatedPoint.w = 1.0f;
// create transformation matrix
Matrix4x4 transformationMatrix = Matrix4x4.identity;
transformationMatrix.SetRow (0, photoData.camRight);
transformationMatrix.SetRow (1, photoData.camUp);
transformationMatrix.SetRow (2, - photoData.camForward);
Vector4 transformedPoint = transformationMatrix * translatedPoint;
return transformedPoint;
}
First of all, the tutorial mentions, that after computing the ndc-values, "the range of values is now normalized from -1 to 1 in all 3 axes". This is not true in my case and I do not see what I am doing wrong.
My second question is, does pointInClipCoordinates.z < 0 mean the world point is "behind" my camera?
And the last question so far is why do I have to use - photoData.camForward?
// edit: updated code + questions
For editor scripts, use HandleUtility.WorldToGUIPoint (available since Unity3D 4.12) to convert a world space point to a 2D GUI position.

Resources