I have the following code to determine the intersection of two 2D lines. It's not working and I'm not sure why; I've been copying code from multiple sources without much change.
The lines extend infinitely from a given midpoint. The "vector()" referenced in the below code is a 2D vector of magnitude 1.0 that indicates the direction in which the line extends (the line also extends in the negative direction, it's not a ray).
Earlier, I was using this method for determining the intersection: Intersection point of two lines (2 dimensions)
After that gave me wrong results, I went with the method on Wikipedia.
float x1 = line1.location().x();
float y1 = line1.location().y();
float x2 = x1 + line1.vector().x();
float y2 = y1 + line1.vector().y();
float x3 = line2.location().x();
float y3 = line2.location().y();
float x4 = x3 + line2.vector().x();
float y4 = y3 + line2.vector().y();
float d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
if(d == 0) // If parallel, defaults to the average location of the lines.
return new Vector2f((x1 + x3) * 0.5f, (y1 + y3) * 0.5f);
else
{
float a = (x1 * y2) - (y1 * x2);
float b = (x3 * y4) - (y3 * x4);
return new Vector2f(((a * (x3 - x4)) - ((x1 - x2) * b)) / d,
((a * (y3 - y4)) - ((y1 - y2) * b)) / d);
}
Two examples of how it is wrong (The orange dot is the returned point of intersection):q
It returns a point along the primary line, but it doesn't return a point on the second. the same bugs happen in both methods, so I'm really not sure what I'm doing wrong.
How can I fix this?
EDIT: Actually, this code works fine; my visualization code had an error.
I believe you've confused what the location() and vector() methods return. Unless i'm mistaken the location().x() gives you a point on the line created by the vector while vector().x() gives you the magnitude of the x value of the vector. (e.g. a horizontal has a vector().y() of 0)
You are adding the magnitude of the vector to the starting point. Instead try multiplying the starting point by the magnitude
float x2 = x1 * line1.vector().x();
float y2 = y1 * line1.vector().y();
As it turns out, the code was working; my visualization code had a bug in it. My bad.
Related
I have a point (x1, y1, z1) in a 3D dimensional space
And a line (x2,y2,z2)(x3,y3,z3)
I want to find the shortest distance between the line and the dot.
I already found mathematical equations for this, but I am not a mathematician, and i failed to understand the different variables in the equation and apply them to Java/Android.
I have searched and viewed the similar questions here and almost everywhere, but there were no example in any programming language.
After spending the night learning some spacial math, I could finally convert the equations to Java code:
public static float betweenPointAndLine(float[] point, float[] lineStart, float[] lineEnd){
float[] PointThing = new float[3];
float[] TotalThing = new float[3];
PointThing[0] = lineStart[0] - point[0];
PointThing[1] = lineStart[1] - point[1];
PointThing[2] = lineStart[2] - point[2];
TotalThing[0] = (PointThing[1]*lineEnd[2] - PointThing[2]*lineEnd[1]);
TotalThing[1] = -(PointThing[0]*lineEnd[2] - PointThing[2]*lineEnd[0]);
TotalThing[2] = (PointThing[0]*lineEnd[1] - PointThing[1]*lineEnd[0]);
float distance = (float) (Math.sqrt(TotalThing[0]*TotalThing[0] + TotalThing[1]*TotalThing[1] + TotalThing[2]*TotalThing[2]) /
Math.sqrt(lineEnd[0] * lineEnd[0] + lineEnd[1] * lineEnd[1] + lineEnd[2] * lineEnd[2] ));
return distance;
}
public static double distance(double x1, double y1, double z1,
double x2, double y2, double z2,
double x3, double y3, double z3) {
double b = Math.sqrt(Math.pow((x2 - x3), 2)
+ Math.pow((y2 - y3), 2)
+ Math.pow((z2 - z3), 2));
double S = Math.sqrt(Math.pow((y2 - y1) * (z3 - z1) - (z2 - z1) * (y3 - y1), 2) +
Math.pow((z2 - z1) * (x3 - x1) - (x2 - x1) * (z3 - z1), 2) +
Math.pow((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1), 2)) / 2;
return 2 * S / b;
}
public void move(){
double angle;
for(int i = 0; i < planets.size(); i++){
if(Math.abs(Math.sqrt(Math.pow(ship.locX - (planets.get(i).locX + planets.get(i).radi), 2) + Math.pow(ship.locY - (planets.get(i).locY + planets.get(i).radi), 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets to determine whether the ship is within the influence of the planet.
angle = ((Math.atan2((planets.get(i).locX + planets.get(i).radi) - ship.locX, (planets.get(i).locY + planets.get(i).radi) - ship.locY)) / Math.PI) + 1;
//The problematic math equation.
Produces a double from 0 to 2, 0 being when ship.locY < planets.get(i).locY && ship.locX == (planets.get(i).locX - planets.get(i).radi). (when relative X = 0 and relative Y < 0.)
if(ship.locX > (planets.get(i).locX + planets.get(i).radi)){xm += Math.cos(angle) * planets.get(i).gravrate;}
else{xm -= Math.cos(angle) * planets.get(i).gravrate;}
if(ship.locY > (planets.get(i).locY + planets.get(i).radi)){ym += Math.sin(angle) * planets.get(i).gravrate;}
else{ym -= Math.sin(angle) * planets.get(i).gravrate;}
}
}
This uses the data to modify the X and Y velocities of the spacecraft.
This equation works for the majority of an orbit, but under certain circumstances has an issue in which the spacecraft undergoes a retrograde force, slowing it. Shortly afterward it begins to be repelled by the planetary body, which after a short period begins attracting it again. When the spacecraft reaches the original position at which this occurred, it begins to move in the opposite direction of its original orbit.
This continues to occur until the spacecraft begins a wavelike motion.
Is there a way to solve this, or am I simply using the wrong equation? I've been attempting to fix this for about two weeks now. I have no education in physics nor calculus at this point in time, so my understanding is limited.
Edit: The comments had questions about my math, so I'll attempt to answer them here. From what I know about atan2, it produces a number from -pi to pi. I divide by pi to produce a number from -1 to 1, then add 1 to produce 0 to 2. I then use this number as a radian measurement. My knowledge of radians (unit circle) is that a circle's radian measure is 0 to 2pi.
Edit 2: The following code has very different math but produces the desired results, save for issues of repelling rather than attracting when approaching the North and South 'poles' of the planet.
public void move(){
double angle;
double x1, x2, y1, y2;
for(int i = 0; i < planets.size(); i++){
x1 = ship.locX;
y1 = ship.locY;
x2 = planets.get(i).locX + planets.get(i).radi;
y2 = planets.get(i).locY + planets.get(i).radi;
if(Math.abs(Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets
angle = (y2 - y1)/(x2 - x1); //Gets slope of line between points.
if(angle > 0){
if(y1 > y2){
xm += Math.cos(angle) * planets.get(i).gravrate;
ym += Math.sin(angle) * planets.get(i).gravrate;
}else{
xm -= Math.cos(angle) * planets.get(i).gravrate;
ym -= Math.sin(angle) * planets.get(i).gravrate;
}
}
else{
if(y1 > y2){
xm -= Math.cos(angle) * planets.get(i).gravrate;
ym -= Math.sin(angle) * planets.get(i).gravrate;
}else{
xm += Math.cos(angle) * planets.get(i).gravrate;
ym += Math.sin(angle) * planets.get(i).gravrate;}
}
}
}
I wrote it up very quickly to see if using the slope of the line rather than that strange atan2 equation would help. Apparently it did. I also made the code a bit more readable in this section.
The following code fixed my issue. I was overcomplicating my math equations as I usually do. Took me three weeks of Googling, asking people with degrees in physics and mathematics, and reading Javadocs before I figured that one out. Turns out how atan2 works is simply different from how I thought it worked and I was improperly using it.
The solution was simplifying the atan2 equation beforehand and removing the unnecessary additions.
x1 = ship.locX;
y1 = ship.locY;
x2 = planets.get(i).locX + planets.get(i).radi;
y2 = planets.get(i).locY + planets.get(i).radi;
if(Math.abs(Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets
angle = Math.atan2((y2 - y1),(x2 - x1)); //Converts the difference to polar coordinates and returns theta.
xm -= Math.cos(angle) * planets.get(i).gravrate; //Converts theta to X/Y
ym -= Math.sin(angle) * planets.get(i).gravrate; //velocity values.
}
I am writing a game. I need to know how to rotate point a around point b by a given number of degrees. I am writing this in java and it is going to be part of my class, Point.
double x1 = point.x - center.x;
double y1 = point.y - center.y;
double x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle));
double y2 = x1 * Math.sin(angle) + y1 * Math.cos(angle));
point.x = x2 + center.x;
point.y = y2 + center.y;
This approach uses rotation matrices. "point" is your point a, "center" is your point b.
I am having an issue with my program; currently it rotates around a set point, and can rotate models around it. Of course, this is a problem as I want it to be a first-person perspective, and currently, it rotates around a point in front of the viewer, instead of the perspective of the viewer. Here is the trigonometric calculations:
protected void drawWireframe(Graphics g) {
double theta = Math.PI * -azimuth / 180.0D;
double phi = Math.PI * elevation / 180.0D;
float cosT = (float) Math.cos(theta);
float sinT = (float) Math.sin(theta);
float cosP = (float) Math.cos(phi);
float sinP = (float) Math.sin(phi);
float cosTcosP = cosT * cosP;
float cosTsinP = cosT * sinP;
float sinTcosP = sinT * cosP;
float sinTsinP = sinT * sinP;
float near = 6.0F;
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < tiles.size(); i++) {
Point[] points = new Point[vertices.length];
for (int j = 0; j < points.length; j++) {
float x0 = -(tiles.get(i).getX() + xmod + vertices[j]
.getX());
float y0 = (tiles.get(i).getY() + ymod + vertices[j].getY());
float z0 = -(tiles.get(i).getZ() + zmod + vertices[j]
.getZ());
float x1 = cosT * x0 + sinT * z0;
float y1 = -sinTsinP * x0 + cosP * y0 + cosTsinP * z0;
float z1 = cosTcosP * z0 - sinTcosP * x0 - sinP * y0;
if (z1 + near > 0) {
x1 = x1 * near / (z1 + near);
y1 = y1 * near / (z1 + near);
points[j] = new Point((int) (Math.max(getWidth(),
getHeight()) / 2 - (Math.max(getWidth(),
getHeight()) / near) * x1), (int) (Math.max(
getWidth(), getHeight()) / 2 - (Math.max(
getWidth(), getHeight()) / near) * y1));
}
}
}
}
How would I go about moving the rotational point without actually modifying the xmod, ymod and zmod (these are used for movements like jumping, walking, running, crouching... etc)
I know how to figure out how to get the new x, y and z positions, I just don't know how to apply them; if I add them to the mods, it creates a weird loop-d-loop. If I add them to the x1, y1, z1's it doesn't cover the z not rotating from the perspective.
To change the rotation point, you effectively need three transforms:
Translate the coordinate system so that the rotation point becomes the origin.
Perform a rotation around the origin
Translate the coordinate system back again.
This can be factored a number of ways, but that's the basic priniciple: translate->rotate->translate.
The way you "move the rotation point" of an object is by translating the object so that the rotation point is at the origin; do the rotation; then translate the object back. All of this is done in memory, between frames - the user never actually sees the object moving to the origin and back.
By the way, all this stuff is significantly easier if you understand vectors and matrix transformations - as you've seen yourself, without them the code can get out of hand.
Using vectors/matrices, all your code above could be reduced to only a few lines.
Hi
this a part of my code :
I have a list which its size is three and I consider that 2 last items are in one line (p and q) I need to get the angle between the first item of this list and these two points (p,q)
private Point partition(List<Point> list, Point p, Point q) {
double x1 = p.getX();
double x2 = q.getX();
double y1 = p.getY();
double y2 = q.getY();
double pQ = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
for (int i = 0; i < list.size()-2; i++) {
double pointX = list.get(i).getX();
double pointY = list.get(i).getY();
double pointQ = Math.sqrt((x2 - pointX) * (x2 - pointX) + (y2 - pointY) * (y2 - pointY));
double pointP = Math.sqrt((pointX - x1) * (pointX - x1) + (pointY - y1) * (pointY - y1));
double angle = Math.acos((pQ * pQ - pointP * pointP - pointQ * pointQ) /(- 2 * pointP * pointQ));
System.out.println(angle);
}
but instead of printing an angle for the first item it will print :(first item is not in the line of two last items).
1.6288442476732894
those points that print this result are :
[X :143.0 Y: 217.0, X :93.0 Y: 163.0, X :193.0 Y: 165.0]
please help me thanks.
EDITED : really it makes me confused .in such a way it will print this value ,sorry all !!!
Your arccos is bad, you need a parenthesis and a - :
arccos((pQ^2 - pointP^2 - pointQ^2)/(-2 * pointP * pointQ))
see How to calculate an angle from three points?
NaN is a special double value meaning "not a number". It is generated as a result of some "bad" calculations:
dividing 0 by 0
dividing infinity by infinity (any combination of positive and negative)
multiplying 0 by infinity, either positive and negative, and vice-versa
adding negative and positive infinity
subtracting negative from positive infinity, and vice-versa
the square root of a negative number
the logarithm of a negative number
the inverse sine or cosine of a number not between -1 and 1
any calculation involving one or more NaN values.
Check the result of the argument to the inverse cosine function (acos). I bet it is off the valid range.