In the program that I'm working on, I have an object (the player) in the shape of a triangle, and that triangle is supposed to rotate always facing the mouse. given this two points I have tried different equations I've found online but non of them seem to work or at least preform well enough.
delta_x = cursor.X - pos.X;
delta_y = cursor.Y - pos.Y;
cursorAngle = (float)Math.Atan2(delta_y, delta_x) * (float)(180 / Math.PI);
this is the most efficient formula I found but it is still not working well enough, since it only faces the mouse at specific angles or distances. Cursor.X and .Y are the coordinates of the mouse and pos.X and .Y are the coordinates of the player.
I created this WinForm example that calculates the angle and distance of the mouse from the center of the form every time you move the mouse on the form. The result I display in a label.
The red dot in the center of the form is just a reference panel and has no relevance in the code.
private void f_main_MouseMove(object sender, MouseEventArgs e)
{
Point center = new Point(378, 171);
Point mouse = this.PointToClient(Cursor.Position);
lb_mouseposition.Text = $"Mouse Angle: {CalculeAngle(center, mouse)} / Distance: {CalculeDistance(center, mouse)}";
}
private double CalculeAngle(Point start, Point arrival)
{
var deltaX = Math.Pow((arrival.X - start.X), 2);
var deltaY = Math.Pow((arrival.Y - start.Y), 2);
var radian = Math.Atan2((arrival.Y - start.Y), (arrival.X - start.X));
var angle = (radian * (180 / Math.PI) + 360) % 360;
return angle;
}
private double CalculeDistance(Point start, Point arrival)
{
var deltaX = Math.Pow((arrival.X - start.X), 2);
var deltaY = Math.Pow((arrival.Y - start.Y), 2);
var distance = Math.Sqrt(deltaY + deltaX);
return distance;
}
The angle is here shown in degrees varying from 0 to 359.
I hope this helps in calculating the angle between your two points.
Related
Given an Point array and an arbitrary x,y coordinate, find the index for _points that is closest to the given coordinate.
PointD[] _points
//create a list of x,y coordinates:
for (int i = 0; i < _numberOfArcSegments + 1; i++)
{
double x1 = _orbitEllipseSemiMaj * Math.Sin(angle) - _focalDistance; //we add the focal distance so the focal point is "center"
double y1 = _orbitEllipseSemiMinor * Math.Cos(angle);
//rotates the points to allow for the LongditudeOfPeriapsis.
double x2 = (x1 * Math.Cos(_orbitAngleRadians)) - (y1 * Math.Sin(_orbitAngleRadians));
double y2 = (x1 * Math.Sin(_orbitAngleRadians)) + (y1 * Math.Cos(_orbitAngleRadians));
angle += _segmentArcSweepRadians;
_points[i] = new PointD() { x = x2, y = y2 };
}
I'm drawing an ellipse which represents an orbit. I'm first creating the point array above, then when I draw it, I (attempt) to find the point closest to where the orbiting body is.
To do this I've been attempting to calculate the angle from the center of the ellipse to the body:
public void Update()
{
//adjust so moons get the right positions (body position - focal point position)
Vector4 pos = _bodyPositionDB.AbsolutePosition - _positionDB.AbsolutePosition;
//adjust for focal point
pos.X += _focalDistance;
//rotate to the LonditudeOfPeriapsis.
double x2 = (pos.X * Math.Cos(-_orbitAngleRadians)) - (pos.Y * Math.Sin(-_orbitAngleRadians));
double y2 = (pos.X * Math.Sin(-_orbitAngleRadians)) + (pos.Y * Math.Cos(-_orbitAngleRadians));
_ellipseStartArcAngleRadians = (float)(Math.Atan2(y2, x2)); //Atan2 returns a value between -180 and 180;
}
then:
double unAdjustedIndex = (_ellipseStartArcAngleRadians / _segmentArcSweepRadians);
while (unAdjustedIndex < 0)
{
unAdjustedIndex += (2 * Math.PI);
}
int index = (int)unAdjustedIndex;
The ellipse draws fine, (the point array is correct and all is good once adjusted for viewscreen and camera offsets and zoom)
But does not start at the correct point (I'm decreasing the alpha in the color so the resulting ellipse fades away the further it gets from the body)
I've spend days trying to figure out what I'm doing wrong here and tried a dozen different things trying to figure out where my math is wrong, but I'm not seeing it.
I assume that _points should be an array of PointD;
This is the shortest way to get the closest point to your array (calcdistance should be a simple function that calculate the euclidean distance):
PointD p = _points.OrderBy(p => CalcDistance(p, gievnPoint)).First();
I have to display stl models with openGL. (SharpGL.) I'd like to set the initial view, so that the model is at the center of the screen and approximately fills it. I've calculated the bounding cube of the models and set the view like this: (sceneBox is a Rect3D - it stores the location of the left-back-bottom corner and the sizes)
// Calculate viewport properties
double left = sceneBox.X;
double right = sceneBox.X + sceneBox.SizeX;
double bottom = sceneBox.Y;
double top = sceneBox.Y + sceneBox.SizeY;
double zNear = 1.0;
double zFar = zNear + 3 * sceneBox.SizeZ;
double aspect = (double)this.ViewportSize.Width / (double)this.ViewportSize.Height;
if ( aspect < 1.0 ) {
bottom /= aspect;
top /= aspect;
} else {
left *= aspect;
right *= aspect;
}
// Create a perspective transformation.
gl.Frustum(
left / ZoomFactor,
right / ZoomFactor,
bottom / ZoomFactor,
top / ZoomFactor,
zNear,
zFar);
// Use the 'look at' helper function to position and aim the camera.
gl.LookAt(
0, 0, 2 * sceneBox.SizeZ,
sceneBox.X + 0.5 * sceneBox.SizeX, sceneBox.Y + 0.5 * sceneBox.SizeY, sceneBox.Z - 0.5 * sceneBox.SizeZ,
0, 1, 0);
This works nice with my small, hand-made test model: (it has a box size of 2*2*2 units)
This is exactly what I want. (The yellow lines show the bounding box)
But, when I load an stl model, which is about 60*60*60 units big, I get this:
It's very small and too far up.
What should I change to make it work?
Here's the full thing: https://dl.dropbox.com/u/17798054/program.zip
You can find this model in the zip as well. The quoted code is in KRGRAAT.SZE.Control.Engine.GLEngine.UpdateView()
Apparently the problem are the arguments you are using in lookAt function. If you have calculated bounding cube all you need to do is to place it in the distance (eyeZ) from the camera of
sizeX/tan(angleOfPerspective)
where sizeX is width of Quad of which cube is built, angleOfPerspective is first parameter of GlPerspective of course having centerX == posX == centreX of the front quad and centerY == posY == centreY of the front quad and frustum is not necessary
lookAt reference http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
So, to clarify Arek's answer, this is how I fixed it:
// Calculate viewport properties
double zNear = 1.0;
double zFar = zNear + 10 * sceneBox.SizeZ; // had to increase zFar
double aspect = (double)this.ViewportSize.Width / (double)this.ViewportSize.Height;
double angleOfPerspective = 60.0;
double centerX = sceneBox.X + 0.5 * sceneBox.SizeX;
double centerY = sceneBox.Y + 0.5 * sceneBox.SizeY;
double centerZ = sceneBox.Z + 0.5 * sceneBox.SizeZ;
// Create a perspective transformation.
gl.Perspective( // swapped frustum for perspective
angleOfPerspective / ZoomFactor, // moved zooming here
aspect,
zNear,
zFar);
// Use the 'look at' helper function to position and aim the camera.
gl.LookAt(
centerX, centerY, sceneBox.SizeX / Math.Tan(angleOfPerspective), // changed eye position
centerX, centerY, -centerZ,
0, 1, 0);
I've been trying to combine these two samples from David Amador:
http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/
http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/
Everything is working fine except I'm having some difficulty getting the mouse coordinates. I was able to get them for each individual sample, but my math for taking both into account seems to be wrong.
The mouse coordinates ARE correct if my virtual resolution and normal resolution are the same. It's when I do something like Resolution.SetVirtualResolution(1920, 1080)
and Resolution.SetResolution(1280, 720, false) when the coordinates slowly get out of sync as I move the camera.
Here is the code:
public static Vector2 MousePositionCamera(Camera camera)
{
float MouseWorldX = (Mouse.GetState().X - Resolution.VirtualWidth * 0.5f + (camera.position.X) * (float)Math.Pow(camera.Zoom, 1)) /
(float)Math.Pow(camera.Zoom, 1);
float MouseWorldY = ((Mouse.GetState().Y - Resolution.VirtualHeight * 0.5f + (camera.position.Y) * (float)Math.Pow(camera.Zoom, 1))) /
(float)Math.Pow(camera.Zoom, 1);
Vector2 mousePosition = new Vector2(MouseWorldX, MouseWorldY);
Vector2 virtualViewport = new Vector2(Resolution.VirtualViewportX, Resolution.VirtualViewportY);
mousePosition = Vector2.Transform(mousePosition - virtualViewport, Matrix.Invert(Resolution.getTransformationMatrix()));
return mousePosition;
}
In resolution I added this:
virtualViewportX = (_Device.PreferredBackBufferWidth / 2) - (width / 2);
virtualViewportY = (_Device.PreferredBackBufferHeight / 2) - (height / 2);
Everything else is the same as the sample code. Thanks in advance!
Thanks to David Gouveia I was able to identify the problem... My camera matrix was using the wrong math.
I'm going to post all of my code with the hopes of helping someone who is trying to do something similar.
Camera transformation matrix:
public Matrix GetTransformMatrix()
{
transform = Matrix.CreateTranslation(new Vector3(-position.X, -position.Y, 0)) * Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) * Matrix.CreateTranslation(new Vector3(Resolution.VirtualWidth
* 0.5f, Resolution.VirtualHeight * 0.5f, 0));
return transform;
}
That will also center the camera. Here's how you get the mouse coordinates combining both the Resolution class and camera class:
public static Vector2 MousePositionCamera(Camera camera)
{
Vector2 mousePosition;
mousePosition.X = Mouse.GetState().X;
mousePosition.Y = Mouse.GetState().Y;
//Adjust for resolutions like 800 x 600 that are letter boxed on the Y:
mousePosition.Y -= Resolution.VirtualViewportY;
Vector2 screenPosition = Vector2.Transform(mousePosition, Matrix.Invert(Resolution.getTransformationMatrix()));
Vector2 worldPosition = Vector2.Transform(screenPosition, Matrix.Invert(camera.GetTransformMatrix()));
return worldPosition;
}
Combined with all of the other code I posted/mentioned this should be all you need to achieve resolution independence and an awesome camera!
I want to add additional feature of my project in C#, I can already draw lines in my program but I want to detect INTERSECTING LINES of a one line drawn and display the point they've intersect. Is it possible? Thank you
My program also includes computing for Perpendicular Distance, here is the sample code:
public static Double PerpendicularDistance(Point Point1, Point Point2, Point Point)
{
Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * Point2.Y - Point1.X * Point.Y));
Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + Math.Pow(Point1.Y - Point2.Y, 2));
Double height = area / bottom * 2;
return height;
}
}
The POINT here is a class for my X and Y coordinates.
If you are trying to find the intersection of two line, then the solution is fairly trivial.
If the two line are in the form Ax + By = C:
float delta = a1*b2 - a2*b1;
if(delta == 0)
throw new ArgumentException("Lines are parallel");
float x = (b2*c1 - b1*c2)/delta;
float y = (a1*c2 - a2*c1)/delta;
My concern is comment above that says there is only one drawn line. I'm not sure what you mean. Does it mean that the app provides one line and the user the other, or are we dealing in curved lines where the line intersects itself?
I am runnng the motion detection algorithm against a video (file) and following the code sample motion detection, and trying to find the angle of each component and the overall motion. I do get a motion value back, with blobs etc., but the motion direction of each component always is always 0 degrees or 360 degrees and make no sense. What could I be doing wrong? Please help, thanks.
This is the constructor
_motionHistory = new MotionHistory(
10.0, //in second, the duration of motion history you wants to keep
0.05, //in second, parameter for cvCalcMotionGradient
0.5); //in second, parameter for cvCalcMotionGradient
The following is the code for looping through the motion components:
foreach (MCvConnectedComp comp in motionComponents)
{
//reject the components that have small area;
if (comp.area < 1) continue;
// find the angle and motion pixel count of the specific area
double angle, motionPixelCount;
_motionHistory.MotionInfo(comp.rect, out angle, out motionPixelCount);
string motion_direction = GetMotionDescriptor(comp.rect);
Console.writeline (motion_direction);
}
// find and draw the overall motion angle
double overallAngle, overallMotionPixelCount;
_motionHistory.MotionInfo(motionMask.ROI, out overallAngle, out overallMotionPixelCount);
And this where I get my motion descriptor angle
private string GetMotionDescriptor(Rectangle motionRegion)
{
float circleRadius = (motionRegion.Width + motionRegion.Height) >> 2;
Point center = new Point(motionRegion.X + motionRegion.Width >> 1, motionRegion.Y + motionRegion.Height >> 1);
int xDirection = (int)(Math.Cos(angle * (Math.PI / 180.0)) * circleRadius);
int yDirection = (int)(Math.Sin(angle * (Math.PI / 180.0)) * circleRadius);
//double movementAngle = Math.Atan(xDirection / yDirection) * 180 / Math.PI;
Point pointOnCircle = new Point(center.X + xDirection, center.Y - yDirection);
double slope = (double)(pointOnCircle.Y - center.Y)/(double)(pointOnCircle.X - center.X);
double ang = Math.Atan(slope) * 180/Math.PI;
return (ang).ToString() + " degrees";
}
aha! I figured out the reason and posting here if anyone is running into the same problem. The
_motionHistory = new MotionHistory(mhi, maxDelta, minDelta);
Should be adjusted to the frame rate and the motion. The trick lies in the 3 params
(1) motion history to keep, (2) max time delta, (3) min time delta.
They need to be adjusted in some way to reflect the motion you wish to capture.
Hope that helps.