Daniel Zemljic
Daniel Zemljic

Reputation: 453

3D line hits a 3D point?

I want to create a function wich knows if a line hits a point. Is there any function like that? I also want to set the size of my 3D-points in centimetre and dont know how to do that.

I appreciate your help.

For example: enter image description here

Assuming that the points have an radius and the lines wouldnt hit the point exact in the middle, is the a function that shows me if a line hit the point?

Upvotes: 1

Views: 1370

Answers (2)

Karthik Karyamapudi
Karthik Karyamapudi

Reputation: 11

What you are looking for is an algorithm to find intersections between a line and a sphere. This is a problem commonly found in graphics programming, and there are a lot of articles that probably explain it a lot better than I could. There is one at http://www.lighthouse3d.com/tutorials/maths/ray-sphere-intersection/

The basic idea is that you project the sphere onto the line, and then solve the resulting right triangle , formed by the point of intersection, the sphere's center, and the projected point, using the Pythagorean theorem.

Here is the code I used in my pathtracing renderer:

hitdata intersectwith(Sphere sphere)
{
    d3Vector projected;

    float t = V.dot(sphere.pos.subtract(O));
    projected = V.normalize().scalarmultiply(t); //the projected vector
    float distnce = (projected.subtract(sphere.pos.subtract(O))).magnitude();
    //the length between the center of your sphere and the projected point
    hitdata outdata; // a class containing the results of the intersection
    outdata.hit = false;
    outdata.t = 110;
    if(t<=0)
    {
        return outdata;
    }
    if(distnce<sphere.r)
    {// the line is less distant from the center of the sphere than the surface
        outdata.hit = true;
        float deltaT = sqrtf((sphere.r*sphere.r)-(distnce*distnce));//Pythagorean theorem
        outdata.coord = O.add(V.scalarmultiply(t-deltaT));
        //calculating intersection coordinates
        outdata.normal = outdata.coord.subtract(sphere.pos);
        outdata.normal = outdata.normal.normalize();//calculating surface normals
        outdata.material = sphere.material;
        outdata.t = t-deltaT;
    }
    return outdata;
}

Upvotes: 0

Arpegius
Arpegius

Reputation: 5887

Ok, I have classical solution that work in any dimensions.

First of all, you got sphere and a line, and you need to have good model of them. Sphere is easy you just have a Vector .center and .diameter.

class Sphere:
    def __init__( sphere, center, diameter ):
       sphere.center=Vector(center)
       sphere.diameter=float(diameter)

Line could be more problematic for beginners because it could be defined in many ways. The most useful comes from parametric equation, you have a direction in Vector .direction and some staring point .center. We assume that .direction is unit length, and .center is the nearest point on line from (0,0). In most cases we need to create a line, having to points Vectors:

def line_on_two_points( A, B ):
    return Line( direction= Vector(B)-A, center=A )

So we have to fix the direction and center in the constructor. .direction is easy to fix wee need just to make it unit length. To find .center, we need scalar projection. Here is as vector to D: The nearest point on line from (0,0)

Having .direction as unit length A to B and center as from C to A, we could init our line as:

class Line:
   def __init__( line, direction, center ):
        line.direction= Vector(direction) / length(direction)
        line.center= center - line.direction*dot(center,line.direction)

If we don't have a line, just two points we could just do:

#class Sphere:
def colide_line_on_two_points( sphere, A, B ):
    line=line_on_two_points( A-sphere.center, B-sphere.center)
    return length(line.center) < sphere.diameter

But when we have a line we try to optimize it as:

#class Sphere:
def colide_line( sphere, line ):
    return line.distance_to(sphere.center) < sphere.diameter

The .distance_to() function is a bit tricky:

Vector from line to point

#class Line:

   def vector_to( line, P ):
       return line.center + line.direction * dot(line.direction,P) - P

   def distance_to( line, P ):
       return length( line.center + line.direction * dot(line.direction,P) - P )

   def move_to( line, P ):
       line.center += line.direction * dot(line.direction,P) - P

The last but not least is the Vector type, I try numpy, but it's rather slow for 2D,3D:

from numpy import array as Vector
from numpy import dot
from numpy.linalg import norm as length

Upvotes: 2

Related Questions