For school, I have recently started creating my own raytracer. However, I've hit a snag with either computing the viewing rays, or checking for an intersection between a triangle and a ray. As far as I can tell, the computations seem to be executed correctly, as I place my camera in the origin and have it face the -z axis towards an object right in front of it, allowing for simple vector maths by hand. Everything seems to check out, but nothing gets painted on the screen.
I will post the code I am using the calculate the viewing rays.
public Ray generateRay(float nX, float nY , Point2f coordinates)
{
// Compute l, r, b and t.
Vector3f temp = VectorHelper.multiply(u, nX/2.0f);
float r = temp.x + Position.x;
temp = VectorHelper.multiply(u, -nX/2.0f);
float l = temp.x + Position.x;
temp = VectorHelper.multiply(v, nY/2.0f);
float t = temp.y + Position.y;
temp = VectorHelper.multiply(v, -nY/2.0f);
float b = temp.y + Position.y;
// Compute the u and v coordinates.
float uCo = (l + (r - l) * (coordinates.x + 0.5f)/nX);
float vCo = (b + (t - b) * (coordinates.y + 0.5f)/nY);
// Compute the ray's direction.
Vector3f rayDirection = VectorHelper.multiply(w, -FocalLength);
temp = VectorHelper.add(VectorHelper.multiply(u, uCo), VectorHelper.multiply(v, vCo));
rayDirection = VectorHelper.add(rayDirection, temp);
rayDirection = VectorHelper.add(rayDirection, Position);
rayDirection = VectorHelper.normalize(VectorHelper.add(rayDirection, temp));
// Create and return the ray.
return new Ray(Position, rayDirection);
}
The following code is what I use to calculate an intersection. It uses Cramer's Rule to solve the matrix equation.
public static Point3f rayTriangleIntersection(
Ray ray, Point3f vertexA, Point3f vertexB, Point3f vertexC)
{
// Solve the linear system formed by the ray and the parametric surface
// formed by the points of the triangle.
// | a d g | | B | | j |
// | b e h | * | Y | = | k |
// | c f i | * | t | = | l |
// The following uses Cramer's rule to that effect.
float a = vertexA.x - vertexB.x; float d = vertexA.x - vertexC.x; float g = ray.getDirection().x;
float b = vertexA.y - vertexB.y; float e = vertexA.y - vertexC.y; float h = ray.getDirection().y;
float c = vertexA.z - vertexB.z; float f = vertexA.z - vertexC.z; float i = ray.getDirection().z;
float j = vertexA.x - ray.getOrigin().x;
float k = vertexA.y - ray.getOrigin().y;
float l = vertexA.z - ray.getOrigin().z;
// Compute some subterms in advance.
float eihf = (e * i) - (h * f);
float gfdi = (g * f) - (d * i);
float dheg = (d * h) - (e * g);
float akjb = (a * k) - (j * b);
float jcal = (j * c) - (a * l);
float blkc = (b * l) - (k * c);
// Compute common division number.
float m = (a * eihf) + (b * gfdi) + (c * dheg);
// Compute unknown t and check whether the point is within the given
// depth interval.
float t = -((f * akjb) + (e * jcal) + (d * blkc)) / m;
if (t < 0)
return null;
// Compute unknown gamma and check whether the point intersects the
// triangle.
float gamma = ((i * akjb) + (h * jcal) + (g * blkc)) / m;
if (gamma < 0 || gamma > 1)
return null;
// Compute unknown beta and check whether the point intersects the
// triangle.
float beta = ((j * eihf) + (k * gfdi) + (l * dheg)) / m;
if (beta < 0 || beta > (1 - gamma))
return null;
// Else, compute the intersection point and return it.
Point3f result = new Point3f();
result.x = ray.getOrigin().x + t * ray.getDirection().x;
result.y = ray.getOrigin().y + t * ray.getDirection().y;
result.z = ray.getOrigin().z + t * ray.getDirection().z;
return result;
}
My question is rather simple. What am I doing wrong? I've looked and debugged this code to death and cannot single out the errors, google offers little more than the theory I already have in the book I am using. Also, the code is still rather rough as I'm just focusing on getting it to work before cleaning it up.
Thanks in advance,
Kevin
Hard to say precisely what is going wrong. Especially since you aren't using descriptive variable names (what are nX, nY etc.??)
Here are some tips:
First make sure it's not a bug in your display code. Fake an intersection to prove that you get visible output when you hit something, e.g. make all rays in the bottom right of the screen hit an axis-aligned plane or something similar so that you can easily verify the co-ordinates
Try a ray/sphere intersection first. It's easier than a ray/triangle intersection.
Consider using vector/matrix operations rather than computing all the components by hand. It's too easy to make a mistake in many lines of jumbled letters.
If you have a scale problem (e.g. the object is too small) then double-check your conversions between world and screen co-ordinates. World co-ordinates will be in the range of small double numbers (0.2 ....5.0 for example) while screen co-ordinates should be pixel locations according to your view size (0 .. 1024 for example). You should be doing most of your maths in world co-ordinates, only converting from/to screen co-ordinates at the beginning and the end of your rendering code.
Step through the top level raytracing code in a debugger and make sure that you are producing rays in sensible directions for each screen co-ordinate(especially the corners of the screen)
Check that your camera direction is pointing towards the target object. It is quite an easy mistake to have it looking in exactly the opposite direction!
Example set-up that should work:
Camera position [0 0 4]
Object position [0 0 0]
Camera DIRECTION [0 0 -1] (note the minus if you want it to look towards the origin!)
UP vector [0 0.75 0]
RIGHT vector [+/-1 0 0]
Then your ray direction should be something like (for a pixel [screenX, screenY]):
ray = DIRECTION + (2*(screenX / screenWidth)-1)*RIGHT + (1-2*(screenY/screenHeight))*UP
ray = normalize(ray)
Related
I'm making a game with libGDX in Java. I'm trying to make a collision detection. As you can see in the image, I have a line which is a wall and a player with specified radius. The desired position is the next location which the player is trying to be in. But because there is a wall, he's placed in the Actual Position which is on the Velocity vector, but more closer to the prev location. I'm trying to figure out how can I detect that closer position?
My attempt:
private void move(float deltaTime) {
float step;
beginMovementAltitude();
if (playerComponent.isWalking())
step = handleAcceleration(playerComponent.getSpeed() + playerComponent.getAcceleration());
else step = handleDeacceleration(playerComponent.getSpeed(), playerComponent.getAcceleration());
playerComponent.setSpeed(step);
if (step == 0) return;
takeStep(deltaTime, step, 0);
}
private void takeStep(float deltaTime, float step, int rotate) {
Vector3 position = playerComponent.getCamera().position;
float x = position.x;
float y = position.y;
int radius = playerComponent.getRadius();
auxEnvelope.init(x, x + radius, y, y + radius);
List<Line> nearbyLines = lines.query(auxEnvelope);
float theta;
int numberOfIntersections = 0;
float angleToMove = 0;
Gdx.app.log(step + "", "");
for (Line line : nearbyLines) {
VertexElement src = line.getSrc();
VertexElement dst = line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z, rotate);
float nextX = x + (step * deltaTime) * (auxVector3.x);
float nextY = y + (step * deltaTime) * playerComponent.getCamera().direction.y;
float dis = Intersector.distanceLinePoint(src.getX(), src.getY(), dst.getX(), dst.getY(), nextX, nextY);
boolean bodyIntersection = dis <= 0.5f;
auxVector21.set(src.getX(), src.getY());
auxVector22.set(dst.getX(), dst.getY());
auxVector23.set(nextX, nextY);
if (bodyIntersection) {
numberOfIntersections++;
if (numberOfIntersections > 1) {
return;
}
theta = auxVector22.sub(auxVector21).nor().angle();
float angle = (float) (180.0 / MathUtils.PI * MathUtils.atan2(auxVector23.y - position.y, auxVector23.x - position.x));
if (angle < 0) angle += 360;
float diff = (theta > angle) ? theta - angle : angle - theta;
if (step < 0) step *=-1;
angleToMove = (diff > 90) ? theta + 180 : theta;
}
}
if (numberOfIntersections == 0) {
moveCameraByWalking(deltaTime, step, rotate);
} else {
moveCameraInDirection(deltaTime, step, angleToMove);
}
}
The idea is to find intersection of path of object center and the line moved by radius of the circle, see that picture.
At first, you need to find a normal to the line. How to do it, depends on how the line is defined, if it's defined by two points, the formula is
nx = ay - by
ny = bx - ax
If the line is defined by canonical equation, then coefficients at x and y define normal, if I remembered correctly.
When normal is found, we need to normalize it - set length to 1 by dividing coordinates by vector length. Let it be n.
Then, we will project starting point, desired point and randomly chosen point on line to n, treating them as radius vectors.
Projection of vector a to vector b is
project (a, b) = scalar_product (a, b) / length (b)**2 * b
but since b is n which length equals 1, we will not apply division, and also we want to only find length of the result, we do not multiply by b. So we only compute scalar product with n for each of three aforementioned points, getting three numbers, let s be the result for starting point, d for desired point, l for chosen point on the line.
Then we should modify l by radius of the circle:
if (s < d) l -= r;
else if (s > d) l += r;
If s = d, your object moves in parallel along the line, so line can't obstruct its movement. It's highly improbable case but should be dealt with.
Also, that's important, if l was initially between s and d but after modifying is no longer between then, it's a special case you may want to handle (restrict object movement for example)
Ather that, you should compute (d - s) / (l - s).
If the result is greater or equals 1, the object will not reach the line.
If the result is between 0 and 1, the line obstructs movement and the result indicates part of the path the object will complete. 0.5 means that object will stop halfway.
If the result is negative, it means the line is behind the object and will not obstruct movement.
Note that when using floating point numbers the result will not be perfectly precise, that's why we handle that special case. If you want to prevent this from happening at all, organize loop and try approximations until needed precision is reached.
my math isnt too great but im trying to learn though..
What im trying to do is give my games missiles a helix rocket effect, but i dont know how to work the Sin and Cos to make the helix play out in the right direction..
This is a 3D game by the way:
The problem is, depending on which direction the missile faces, the helix looks warped or flat..
Whats the best way to mathematically calculate a helix based on the missiles X,Y,Z/direction?, ive been trying to figure it out for a long time :/
Thanks alot!
double x = radius * Math.cos(theta);
double y = radius * Math.sin(theta);
double z = radius * Math.cos(theta);
location.add(x,y,z);
missile.shootFlame(location,2);
location.subtract(x,y,z);
Basis vectors
you need the overall direction of missile as 3D vector let call it W. From it you need to get 2 another vectors U,V which are all perpendicular to each other. To get them you can exploit cross product. So:
make W unit vector
Just W = W/|W| so:
l=sqrt(Wx*Wx+Wy*Wy+Wz*Wz);
Wx/=l;
Wy/=l;
Wz/=l;
choose U as any direction non parallel to W
so start with U=(1.0,0.0,0.0) and if U==W choose U=(0.0,1.0,0.0). If you got anything to lock to use that as U direction so the coordinate system will not rotate with time (like Up,North,Sun ...)
U should be unit so if not normalize it just like in #1
compute V
It should be perpendicular to U,W so use cross product:
V = W x U
Cross product of unit vectors is also unit vector so no need to normalize.
recompute U
As we choose the U manually we need to make sure it is also perpendicular to V,W so:
U = V x W
Now we have 3 perpendicular basis vectors where U,V lies in plane of the helix screws and W is the overall movement direction.
If you do not know how to compute the cross product see:
Understanding 4x4 homogenous transform matrices look for [edit2].
Now the Helix is easy:
Defines
so we have U,V,W on top of that we need radius r [units], movement speed v [units/s], angular speed o [rad/s] time t>=0.0 [s] and start position P0.
Helix equation
What we need is equation returning actual position for time so:
ang = o*t;
P(t) = P0 + U*r*cos(ang) + V*r*sin(ang) + W*v*t;
rewritten to scalars:
ang = o*t;
x = P0x + Ux*r*cos(ang) + Vx*r*sin(ang) + Wx*v*t;
y = P0y + Uy*r*cos(ang) + Vy*r*sin(ang) + Wy*v*t;
z = P0z + Uz*r*cos(ang) + Vz*r*sin(ang) + Wz*v*t;
[edit1] as you are incompetent to copy paste and or changing my code correctly...
Vector w = loc.getDirection();
double wX = w.getX();
double wY = w.getY();
double wZ = w.getZ();
double l = Math.sqrt((wX * wX) + (wY * wY) + (wZ * wZ));
wX = wX / l;
wY = wY / l;
wZ = wZ / l;
w = new Vector(wX,wY,wZ); // you forget to change W and use it latter ...
Vector u = new Vector(0, 1.0, 0);
if (Math.abs(wX)<1e-3) // if U and W are the same chose different U
if (Math.abs(wZ)<1e-3)
u = new Vector(1.0, 0.0, 0);
Vector v = w.crossProduct(u);
u = v.crossProduct(w);
double radius = 10; // helix radius [units]
double speed = 2.00; // movement speed [unit/s]
double omega = 0.628; // angular speed [rad/s]
//double omega = 36.0; // angular speed [deg/s]
for (double i = 0; i < 100; i += 1.0) // time [s]
{
double angle = omega * i; // actual screw position [rad] or [deg]
double x = u.getX() * radius * Math.cos(angle) + v.getX() * radius * Math.sin(angle) + wX * speed * i;
double y = u.getY() * radius * Math.cos(angle) + v.getY() * radius * Math.sin(angle) + wY * speed * i;
double z = u.getZ() * radius * Math.cos(angle) + v.getZ() * radius * Math.sin(angle) + wZ * speed * i;
loc.add(x,y,z); // What is this? should not you set the x,y,z instead of adding?
//do work
loc.subtract(x,y,z); // what is this?
}
This should provide you with helix points with traveled linear distance
speed*imax = 2.0*100.0 = 200.0 units
And screws:
omega*imax/(2*Pi) ~= 0.628*100.0/6.28 ~= 10 screws // in case of sin,cos want [rad]
omega*imax/360.0 = 36.0*100.0/360 = 10.0 screws // in case of sin,cos want [deg]
Do not forget to rem in/out the correct omega line (I choose [rad] as that is what I am used that my math libs use). Not sure If I translated to your environment correctly there may be bugs like abs has different name or u = new Vector(1.0, 0.0, 0); can be done on intermediate or declaration of variable only etc which I do not know as I do not code in it.
I'm programming a software renderer in Java, and am trying to use Z-buffering for the depth calculation of each pixel. However, it appears to work inconsistently. For example, with the Utah teapot example model, the handle will draw perhaps half depending on how I rotate it.
My z-buffer algorithm:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
Method for calculating the z value of a point, given a triangle and the ray origin:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
Method for calculating if the ray origin is within a projected triangle:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
Method for calculating surface normal of a triangle:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
Example of the incorrectly drawn teapot:
What am I doing wrong? I feel like it must be some small thing. Given that the triangles draw at all, I doubt it's the pointWithinTriangle method. Backface culling also appears to work correctly, so I doubt it's that. The most likely culprit to me is the zValueOfPoint method, but I don't know enough to know what's wrong with it.
My zValueOfPoint method was not working correctly. I'm unsure why :( however, I changed to a slightly different method of calculating the value of a point in a plane, found here: http://forum.devmaster.net/t/interpolation-on-a-3d-triangle-using-normals/20610/5
To make the answer here complete, we have the equation of a plane:
A * x + B * y + C * z + D = 0
Where A, B, and C are the surface normal x/y/z values, and D is -(Ax0 + By0 + Cz0).
x0, y0, and z0 are taken from one of the vertices of the triangle. x, y, and z are the coordinates of the point where the ray intersects the plane. x and y are known values (rayOrigin.x, rayOrigin.y) but z is the depth which we need to calculate. From the above equation we derive:
z = -A / C * x - B / C * y - D
Then, copied from the above link, we do:
"Note that for every step in the x-direction, z increments by -A / C, and likewise it increments by -B / C for every step in the y-direction.
So these are the gradients we're looking for to perform linear interpolation. In the plane equation (A, B, C) is the normal vector of the plane.
It can easily be computed with a cross product.
Now that we have the gradients, let's call them dz/dx (which is -A / C) and dz/dy (which is -B / C), we can easily compute z everywhere on the triangle.
We know the z value in all three vertex positions.
Let's call the one of the first vertex z0, and it's position coordinates (x0, y0). Then a generic z value of a point (x, y) can be computed as:"
z = z0 + dz/dx * (x - x0) + dz/dy * (y - y0)
This found the Z value correctly and fixed my code. The new zValueOfPoint method is:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double dzdx = -A / C;
double dzdy = -B / C;
double rayZ = triangle.getV1().z * modelViewer.getModelScale() + dzdx * (rayOrigin.x - triangle.getV1().projectPoint(modelViewer).x) + dzdy * (rayOrigin.y - triangle.getV1().projectPoint(modelViewer).y);
return rayZ;
}
We can optimize this by only calculating most of it once, and then adding dz/dx to get the z value for the next pixel, or dz/dy for the pixel below (with the y-axis going down). This means that we cut down on calculations per polygon significantly.
this must be really slow
so much redundant computations per iteration/pixel just to iterate its coordinates. You should compute the 3 projected vertexes and iterate between them instead look here:
triangle/convex polygon rasterization
I dislike your zValueOfPoint function
can not find any use of x,y coordinates from the main loops in it so how it can compute the Z value correctly ?
Or it just computes the average Z value per whole triangle ? or am I missing something? (not a JAVA coder myself) in anyway it seems that this is your main problem.
if you Z-value is wrongly computed then Z-Buffer can not work properly. To test that look at the depth buffer as image after rendering if it is not shaded teapot but some incoherent or constant mess instead then it is clear ...
Z buffer implementation
That looks OK
[Hints]
You have too much times terms like x + getWidth()/2 why not compute them just once to some variable? I know modern compilers should do it anyway but the code would be also more readable and shorter... at least for me
I start off with only two points and an angle that belongs to both points. The only part I have left is the last Point and I don't want to brute force my way through this. So far I have all of the info listed below.
Point A: given
Point B: given
Point C: (?, ?)
Angle A: given (at Point A), same as Angle B
Angle B: given (at Point B), same as Angle A
Angle C: 180 - Angle*2~ (at Point C)
Side AB: distance(Point~A & Point~B)
Side AC: (Side~AB * Math.sin(Angle~A)) / Math.sin(Angle~C)
Side BC: (Side~AB * Math.sin(Angle~B)) / Math.sin(Angle~C)
The Code I have so far is pretty much just this:
(tip: p is a Point, a is an Angle, d is a Side; 1 is A, 2 is B, 3 is C. I know my code is hard to read but it's my first draft.)
public static Point solve(Point p1, Point p2, double angle)
{
//known
double a1 = angle;
double a2 = angle;
double d12 = p1.distance(p2);
//mathed
double a3 = 180 - (angle*2);
double d13 = (d12*Math.sin(a1))/Math.sin(a3);
double d23 = (d12*Math.sin(a2))/Math.sin(a3);
//mathed, mathed.
Point p3 = null;
return p3;
}
Let's P is center of AB segment, P = (A + B) / 2
Then PC vector is perpendicular to AP, and the length of PC is |PC| = |AP| / Tg(angle), Tg = Tan = tangent
Let's Tg(angle) = t
First condition (dot product of perp vectors): PCx*APx+PCy*APy=0
Second one (squared lengths): t^2*(PCx*PCx+PCy*PCy) = APx*APx+APy*APy
Solution of this system (2 solutions, C point might be at the different sides of AB line):
PCx = +- APy/t
PCy = -+ APx/t
Be care: signs should be opposite!
And finally:
Cx = Px + PCx = Ax/2 + Bx/2 +- Ctg(angle)/2 * (Ay + By)
Cy = Py + PCy = Ay/2 + By/2 -+ Ctg(angle)/2 * (Ax + Bx)
first point:
Cx1 = Ax/2 + Bx/2 + Ctg(angle)/2 * (Ay + By);
Cy1 = Ay/2 + By/2 - Ctg(angle)/2 * (Ax + Bx);
second point:
Cx2 = Ax/2 + Bx/2 - Ctg(angle)/2 * (Ay + By);
Cy2 = Ay/2 + By/2 + Ctg(angle)/2 * (Ax + Bx)
If you draw a line perpendicular to AB through the center of AB, it will intersect point C. Call the point where the line intersects the segment AB D. Translate this line to the x-axis, D to the origin, and AD to the y-axis
^ y
|
| A
o
|\
| \
| \
| \ C
o----o-----> x
D
Once you calculate the length DC, projecting C back into the original coordinate space should be a snap.
Angle C = 90 - Angle A
AC * cos Angle C = DC
DC = AC * cos (90 - Angle A)
I hope this works. On an example of P1 = (-10,0), P2 = (10, 0), Angle = 45 degrees; I got (0, +-10) has the final answer, is this correct?
Mid Point = ( (x1+x2)/2, (y1+y2)/2)
Slope Angle = arcTan(m) = arcTan((y2-y1) / (x2-x1))
Perpendicular Angle = Slope Angle +- 90
Distance = (distance(P1 & Mid Point)/sin(90-Angle)) * sin(Angle)
P3 = (cos(Perpendicular Angle)*Distance + Mid Point.x , sin(Perpendicular Angle)*Distance + mid Point.y)
The way I got this was a unit circle with an R of Distance, then go to the perpendicular angles and use cos for x and sin for y.
I got the distance by the law of sines on half the triangle (P1, Mid Point, P3) where MidPoint is the 90 degree.
Please give your advice on this, Thanks ~vzybilly~
I have an array of points, as well as two more points (A and B). The last two points form a line, and I'm trying to find which of the points in my array are furthest from the line. How would I do this in Java?
I'm wondering if it's something along the lines of finding the distance from A and B, but that doesn't sit well in my head.
Additional info:
I think it's a line segment. Given this is QuickHull, I don't know if it makes a difference.
I've never been the greatest when it comes to math and formulas, so more explanation is better. Thanks!
Note that each 3 points [a,b,p] for each p in the array form a trianle, whose area is denoted by: (ab) * h /2 [where h is the distance from p to ab]
You can compute the area these trianles create, and select the minimal. Since ab is constant for all - it guarantees that the trianle with the minimal area will also have the minimal h.
You can find it [the area of each triangle] using
T=(1/2)* abs((x_a - x_p) * (y_b-y_a) - (x_a - x_b)* (y_p - y_a))
[where x_a,x_b,x_p and y_a,y_b,y_p are the x,y coordinates of a,b,p respectively].
Though I find this method very elegant, I believe there are better
ways to do it.
ArrayList<Point> points=new ArrayList();//YOUR POINTS
Point a=new Point(1,1);
Point b=new Point(1,1);
Point ABcenter=new Point((a.x+b.x)/2,(a.y+b.y)/2);//THE CENTER OF THE A AND B POINTS ,USE A OR B IF YOU WANT
int furthestid=0;
float furthestdis=0;
for(int c=0;c<points.size();c++)
{
if(calculate_distance(ABcenter.x,ABcenter.y,points.get(c).x,points.get(c).y)>furthestdis)
{
furthestid=c;
}
}
//closestid now contains the id of the furthest point ,use it like this points.get(c).x ...
public static double calculate_distance (float x1,float y1,float x2 ,float y2){
return Math.sqrt((((x1-x2) * (x1-x2)) + ((y1- y2) * (y1- y2))));
}
I'm assuming you mean the Euclidean distance. If you're working in the plane, then the answer is simple.
First, compute the equation of the line in the form
ax + by + c = 0
In slope-intercept form, this is the same as
y = (-a/b)x + (-c/b)
Now compute the distance from any point (p,q) to the line by
|a*p + b*q + c| / (a^2 + b^2)^(1/2)
For more than 2 dimensions, it's probably easiest to think in terms of parametrized vectors. This means think of points on the line as
p(t) = (A1 + (B1-A1)*t, A2 + (B2-A2)*t, ..., An + (Bn-An)*t)
where the two points are A = (A1,...,An) and B = (B1,...,Bn). Let X = (X1,...,Xn) be any other point. Then the distance between X and p(t), the point on the line corresponding to t, is the square root of
[(A1-X1) + (B1-A1)t]^2 + ... + [(An-Xn) + (Bn-An)t]^2
The distance to the line is the distance to p(t) where t is the unique value minimizing this distance. To compute that, just take the derivative with respect to t and set it to 0. It's a very straightforward problem from here, so I'll leave that bit to you.
If you want a further hint, then check out this link for the 3-dimensional case which reduces nicely.
If the problem is as you have stated it, you can't do much better then computing the distance for each point and choosing the smallest of these.
However you can simplify the calculation of the distance a bit by using a generalized line equation for the line passing through A and B. This would be an equation of the form ax + by + c = 0
You can compute such equation for a line passing through two arbitrary points quite easily:
x * (A.y - B.y) + y * (B.x - A.x) + A.x * B.y - A.y * B.x,
i.e. a = A.y - B.y, b = B.x - A.x and c = A.x * B.y - A.y * B.x
Now that you have computed such equation for the line, you can compute the distance from an arbitrary point P in the plane to the line a * x + b * y + c by substituting x and y with the coordinates of P:
abs(a * P.x + b * P.y + c) / sqrt(a * a + b * b). But as the denominator will be the same for all points, you may igonore it and simply choose the point for which abs(a * P.x + b * P.y + c) is smallest
Here is a link that explains how to compute 2-d distance to a line once you have it's generalized equation.
I'm assuming you talking about line segment not line. First you should find your points distance from your line segment, and you can do it, as the way suggested in this similar question, after that find minimum/maximum distance over all inputs.
Edit: Also from this top coder article you can find distance simply:
//Compute the dot product AB ⋅ BC
int dot(int[] A, int[] B, int[] C){
AB = new int[2];
BC = new int[2];
AB[0] = B[0]-A[0];
AB[1] = B[1]-A[1];
BC[0] = C[0]-B[0];
BC[1] = C[1]-B[1];
int dot = AB[0] * BC[0] + AB[1] * BC[1];
return dot;
}
//Compute the cross product AB x AC
int cross(int[] A, int[] B, int[] C){
AB = new int[2];
AC = new int[2];
AB[0] = B[0]-A[0];
AB[1] = B[1]-A[1];
AC[0] = C[0]-A[0];
AC[1] = C[1]-A[1];
int cross = AB[0] * AC[1] - AB[1] * AC[0];
return cross;
}
//Compute the distance from A to B
double distance(int[] A, int[] B){
int d1 = A[0] - B[0];
int d2 = A[1] - B[1];
return sqrt(d1*d1+d2*d2);
}
//Compute the distance from AB to C
//if isSegment is true, AB is a segment, not a line.
double linePointDist(int[] A, int[] B, int[] C, boolean isSegment){
double dist = cross(A,B,C) / distance(A,B);
if(isSegment){
int dot1 = dot(A,B,C);
if(dot1 > 0)return distance(B,C);
int dot2 = dot(B,A,C);
if(dot2 > 0)return distance(A,C);
}
return abs(dist);
}
I think code has self explanation, if you are familiar with basic geometry, but if you aren't familiar, you should to read the article, if there is any problem for you we can help you.