three js get tangent/intersection of sphere and segment - three.js

I have Vector3 A and Vector3 B:
I need to know Vector3 C (intersection of sphere and segment AB).
What is the best way to get this vector?
I need only one vector, no mater about precision or range.

In pseudo-code
dAB[1] = B[1] - A[1]
dAB[2] = B[2] - A[2]
dAB[3] = B[3] - A[3]
rdAB = 1.0/sqrt(dAB[1]^2+dAB[2]^2+dAB[3]^2)
C[1] = A[1] + R*dAB[1]*rdAB
C[2] = A[2] + R*dAB[2]*rdAB
C[3] = A[3] + R*dAB[3]*rdAB
where dAB is a vector from A to B, R is a radius of the sphere, and rdAB is inverse length of the vector dAB.

You can represent point C as a affine combination of point A and B as
C = (1-t)A + tB
then, the vector OC (where O is the center of the sphere) should have magnitude R (sphere's radius). From this you can obtain a quadratic equation of t and you can solve for t easily. Note that in general you should get two t values as the infinite line defined by A and B will intersect the sphere twice. So, you should only take the t value that is between 0 and 1. There will be cases where you only have one root (in fact duplicate roots) from the quadratic equation when line AB is tangent to the sphere and have no real root at all when line AB does not intersect the sphere.

Related

Calculate if a bullet hits the balloon

I have this problem I can't figure out and need help.
The problem is about calculating how many balloons are hit by a pellet gun. Balloons positions are described by 3D coordinates (X,Y,Z) and radius R. The gunshot is defined by 3D location of the end of the barrel "p" (Px,Py,Pz) and vector "v" (Vx, Vy, Vz) describing the direction barrel is pointing to.
I've tried to implement the solution suggested here: https://math.stackexchange.com/questions/1939423/calculate-if-vector-intersects-sphere
// C = center of sphere
// r = radius of sphere
// P = point on line
// U = unit vector in direction of line
Q = P - C;
a = U*U; // should be = 1
b = 2*U*Q
c = Q*Q - r*r;
d = b*b - 4*a*c; // discriminant of quadratic
if d < 0 then solutions are complex, so no intersections
if d >= 0 then solutions are real, so there are intersections
But the problem with this is that I get intersection with balloons that are positioned behind the gun. How can I modify this algorithm in order to produce the correct result? Or is my approach maybe wrong?
You need to actually solve the quadratic equation defined by your variables a, b and c.
Often, there are math libraries to do this, something like:
(t1,t2) = QuadraticSolve(a, b, c);
You can also do it manually for each parameter:
t1 = (-b + sqrt(b*b - 4*a*c)) / (2*a)
t2 = (-b - sqrt(b*b - 4*a*c)) / (2*a)
If t1 or t2 is positive then that intersection is in front of your gun.

Find tangent points in a circle from a point

Circle center : Cx,Cy
Circle radius : a
Point from which we need to draw a tangent line : Px,Py
I need the formula to find the two tangents (t1x, t1y) and (t2x,t2y) given all the above.
Edit: Is there any simpler solution using vector algebra or something, rather than finding the equation of two lines and then solving equation of two straight lines to find the two tangents separately? Also this question is not off-topic because I need to write a code to find this optimally
Here is one way using trigonometry. If you understand trig, this method is easy to understand, though it may not give the exact correct answer when one is possible, due to the lack of exactness in trig functions.
The points C = (Cx, Cy) and P = (Px, Py) are given, as well as the radius a. The radius is shown twice in my diagram, as a1 and a2. You can easily calculate the distance b between points P and C, and you can see that segment b forms the hypotenuse of two right triangles with side a. The angle theta (also shown twice in my diagram) is between the hypotenuse and adjacent side a so it can be calculated with an arccosine. The direction angle of the vector from point C to point P is also easily found by an arctangent. The direction angles of the tangency points are the sum and difference of the original direction angle and the calculated triangle angle. Finally, we can use those direction angles and the distance a to find the coordinates of those tangency points.
Here is code in Python 3.
# Example values
(Px, Py) = (5, 2)
(Cx, Cy) = (1, 1)
a = 2
from math import sqrt, acos, atan2, sin, cos
b = sqrt((Px - Cx)**2 + (Py - Cy)**2) # hypot() also works here
th = acos(a / b) # angle theta
d = atan2(Py - Cy, Px - Cx) # direction angle of point P from C
d1 = d + th # direction angle of point T1 from C
d2 = d - th # direction angle of point T2 from C
T1x = Cx + a * cos(d1)
T1y = Cy + a * sin(d1)
T2x = Cx + a * cos(d2)
T2y = Cy + a * sin(d2)
There are obvious ways to combine those calculations and make them a little more optimized, but I'll leave that to you. It is also possible to use the angle addition and subtraction formulas of trigonometry with a few other identities to completely remove the trig functions from the calculations. However, the result is more complicated and difficult to understand. Without testing I do not know which approach is more "optimized" but that depends on your purposes anyway. Let me know if you need this other approach, but the other answers here give you other approaches anyway.
Note that if a > b then acos(a / b) will throw an exception, but this means that point P is inside the circle and there is no tangency point. If a == b then point P is on the circle and there is only one tangency point, namely point P itself. My code is for the case a < b. I'll leave it to you to code the other cases and to decide the needed precision to decide if a and b are equal.
Here's another way using complex numbers.
If a is the direction (a complex number of length 1) of the tangent point on the circle from the centre c, and d is the (real) length along the tangent to get to p, then (because the direction of the tangent is I*a)
p = c + r*a + d*I*a
rearranging
(r+I*d)*a = p-c
But a has length 1 so taking the length we get
|r+I*d| = |p-c|
We know everything but d, so we can solve for d:
d = +- sqrt( |p-c|*|p-c| - r*r)
and then find the a's and the points on the circle, one of each for each value of d above:
a = (p-c)/(r+I*d)
q = c + r*a
Hmm not really an algorithm question (people tend to mistake algorithm and equation) If you want to write a code then do (you did not specify language nor what prevents you from doing this which is the reason of close votes)... Without this info your OP is just asking for math equation which is indeed off-topic here and by answering this I risk (right-full) down-votes too (but this is/was asked a lot here with much less info and 4 reopen votes against 1 close put my decision weight on reopen and answering this anyway).
You can exploit the fact that you are in 2D as in 2D perpendicular vectors to vector a(x,y) are computed like this:
c = (-y, x)
d = ( y,-x)
c = -d
so you swap x,y and negate one (which one determines if the perpendicular vector is CW or CCW). It is really a rotation formula but as we rotate by 90deg the cos,sin are just +1 and -1.
Now normal n to any circumference point on circle lies in the line going through that point and circles center. So putting all this together your tangents are:
// normal
nx = Px-Cx
ny = Py-Cy
// tangent 1
tx = -ny
ty = +nx
// tangent 2
tx = +ny
ty = -nx
If you want unit vectors than just divide by radius a (not sure why you do not call it r like the rest of the math world) so:
// normal
nx = (Px-Cx)/a
ny = (Py-Cy)/a
// tangent 1
tx = -ny
ty = +nx
// tangent 2
tx = +ny
ty = -nx
Let's go through derivation process:
As you can see, if the interior of the square is < 0 it's because the point is interior to the circumferemce. When the point is outside of the circumference there are two solutions, depending on the sign of the square.
The rest is easy. Take atan(solution) and be carefull here with the signs, you may better do some checks.
Use (2) and then undo (1) transformations and that's all.
c# implementation of dmuir's answer:
static void FindTangents(Vector2 point, Vector2 circle, float r, out Line l1, out Line l2)
{
var p = new Complex(point.x, point.y);
var c = new Complex(circle.x, circle.y);
var cp = p - c;
var d = Math.Sqrt(cp.Real * cp.Real + cp.Imaginary * cp.Imaginary - r * r);
var q = GetQ(r, cp, d, c);
var q2 = GetQ(r, cp, -d, c);
l1 = new Line(point, new Vector2((float) q.Real, (float) q.Imaginary));
l2 = new Line(point, new Vector2((float) q2.Real, (float) q2.Imaginary));
}
static Complex GetQ(float r, Complex cp, double d, Complex c)
{
return c + r * (cp / (r + Complex.ImaginaryOne * d));
}
Move the circle to the origin, rotate to bring the point on X and downscale by R to obtain a unit circle.
Now tangency is achieved when the origin (0, 0), the (reduced) given point (d, 0) and an arbitrary point on the unit circle (cos t, sin t) form a right triangle.
cos t (cos t - d) + sin t sin t = 1 - d cos t = 0
From this, you draw
cos t = 1 / d
and
sin t = ±√(1-1/d²).
To get the tangency points in the initial geometry, upscale, unrotate and untranslate. (These are simple linear algebra operations.) Notice that there is no need to perform the direct transform explicitly. All you need is d, ratio of the distance center-point over the radius.

Polygon Algorithm

I'm trying to code a general algorithm that can find a polygon from the area swept out by a circle (red line) that follows some known path (green line), and where the circle gets bigger as it moves further down the known path. Basically, can anyone point me down a direction to solve this, please? I can't seem to nail down which tangent points are part of the polygon for any point (and thus circle) on the path.
Any help is appreciated.
Well, the easiest is to approximate your path by small segments on which your path is linear, and your circle grows linearly.
Your segments and angles will likely be small, but for the sake of the example, let's take bigger (and more obvious) angles.
Going through the geometry
Good lines for the edges of your polygon are the tangents to both circles. Note that there aren't always close to the lines defined by the intersections between the circles and the orthogonal line to the path, especially with stronger growth speeds. See the figure below, where (AB) is the path, we want the (OE) and (OF) lines, but not the (MN) one for example :
The first step is to identify the point O. It is the only point that defines a homothetic transformation between both circles, with a positive ratio.
Thus ratio = OA/OB = (radius C) / (radius C') and O = A + AB/(1-ratio)
Now let u be the vector from O to A normalized, and v a vector orthogonal to u (let us take it in the direction from A to M).
Let us call a the vector from O to E normalized, and beta the angle EOA. Then, since (OE) and (AE) are perpendicular, sin(beta) = (radius C) / OA. We also have the scalar product a.u = cos(beta) and since the norm of a is 1, a = u * cos(beta) + v * sin(beta)
Then it comes easily that with b the vector from O to F normalized, b = u * cos(beta) - v * sin(beta)
Since beta is an angle less than 90° (otherwise the growth of the circle would be so much faster than it going forward, that the second circle contains the first completely), we know that cos(beta) > 0.
Pseudo-code-ish solution
For the first and last circles you can do something closer to them -- fort the sake of simplicity, I'm just going to use the intersection between the lines I'm building and the tangent to the circle that's orthogonal to the first (or last) path, as illustrated in the first figure of this post.
Along the path, you can make your polygon arbitrarily close to the real swept area by making the segments smaller.
Also, I assume you have a function find_intersection that, given two parametric equations of two lines, returns the point of intersection between them. First of all, it makes it trivial to see if they are parallel (which they should never be), and it allows to easily represent vertical lines.
w = 1; // width of the first circle
C = {x : 0, y : 0}; // first circle center
while( (new_C, new_w) = next_step )
{
// the vector (seg_x, seg_y) is directing the segment
seg = new_C - C;
norm_seg = sqrt( seg.x * seg.x + seg.y * seg.y );
// the vector (ortho_x, ortho_y) is orthogonal to the segment, with same norm
ortho = { x = -seg.y, y = seg.x };
// apply the formulas we devised : get ratio-1
fact = new_w / w - 1;
O = new_C - seg / fact;
sin_beta = w * fact / norm_seg;
cos_beta = sqrt(1 - sin_beta * sin_beta);
// here you know the two lines, parametric equations are O+t*a and O+t*b
a = cos_beta * seg + sin_beta * ortho;
b = cos_beta * seg - sin_beta * ortho;
if( first iteration )
{
// initialize both "old lines" to a line perpendicular to the first segment
// that passes through the opposite side of the circle
old_a = ortho;
old_b = -ortho;
old_O = C - seg * (w / norm_seg);
}
P = find_intersection(old_O, old_a, O, a);
// add P to polygon construction clockwise
Q = find_intersection(old_O, old_b, O, b);
// add Q to polygon construction clockwise
old_a = a;
old_b = b;
old_O = O;
w = new_w;
C = new_C;
}
// Similarly, finish with line orthogonal to last direction, that is tangent to last circle
O = C + seg * (w / norm_seg);
a = ortho;
b = -ortho;
P = find_intersection(old_O, old_a, O, a);
// add P to polygon construction clockwise
Q = find_intersection(old_O, old_b, O, b);
// add Q to polygon construction clockwise
Let's suppose the centers are along the positive x-axis, and the lines in the envelope are y=mx and y=-mx for some m>0. The distance from (x,0) to y=mx is mx/sqrt(1+m^2). So, if the radius is increasing at a rate of m/sqrt(1+m^2) times the distance moved along the x-axis, the enveloping lines are y=mx and y=-mx.
Inverting this, if you put a circle of radius cx at the center of (x,0), then c=m/sqrt(1+m^2) so
m = c/sqrt(1-c^2).
If c=1 then you get a vertical line, and if c>1 then every point in the plane is included in some circle.
This is how you can tell how much faster than sound a supersonic object is moving from the Mach angle of the envelope of the disturbed medium.
You can rotate this to nonhorizontal lines. It may help to use the angle formulation mu = arcsin(c), where mu is the angle between the envelope and the path, and the Mach number is 1/c.

How to find out if a ray intersects a rectangle?

We have a ray that starts at point A(X, Y) and goes on forever through given point B(X, Y) != A. We have a rectangle defined by points K,L,M,N each with its (X, Y).
I wonder how to detect if our ray intersects with any point of our rectangle (get a bool, not precice coordinates)? What is algorithm for calculating such value?
Let me get this straight. You have a vector v headed off in direction (b_x - a_x, b_y - a_y) and starting at (a_x, a_y).
Consider the vector w = (b_y - a_y, a_x - b_x). It is at right angles to the first. (Verify with a dot product.) Therefore for any point (p_x, p_y) you can easily tell which side of the vector it is on by taking a dot product of (p_x - a_x, p_y - a_y) with w and looking at the sign.
So take that dot product with all 4 corners of your rectangle. If any give a 0 dot product, they are on the vector, if the signs change there is an intersection, if the sign is always the same there is no intersection.
You can use the sweep line algorithm to do so.
http://en.wikipedia.org/wiki/Sweep_line_algorithm
A less clever, but conceptually simpler approach: the ray intersects the rectangle if and only if it intersects at least one of the sides. So for each side of the rectangle, find the intersection (if any) of the line passing through the endpoints with the ray AB; then it's simply a range check to determine if that intersection lies is part of the line segment on the boundary of the rectangle, or if it is outside.
You probably want to compute the segment (if any) of the ray AB that intersects the rectangle. If your rectangle is axis-aligned, this will be easier to compute in a numerical sense, but the logic should be similar.
You can represent a directed line L as [a, b, c] such that, if point P is (X, Y):
let L(P) = a*X + b*Y + c
then, if L(P) == 0, point P is on L
if L(P) > 0, point P is to the left of L
if L(P) < 0, point P is to the right of L
Note that this is redundant in the sense that, given any k > 0, [k*a, k*b, k*c] represents the same line (this property makes it a homogeneous coordinate system). We can also represent points with homogeneous coordinates by augmenting them with a third coordinate:
2D point P = (X, Y)
-> homogeneous coordinates [x, y, w] for P are [X, Y, 1]
L(P) = L.a*P.x + L.b*P.y + L.c*P.w == a*X + b*Y + c*1
In any case, given two corners of your rectangle (say, P and Q), you can compute the homogeneous coordinates of the line through P and Q using a 3-D cross-product of their homogeneous coordinates:
homogeneous coordinates for line PQ are: [P.X, P.Y, 1] cross [Q.X, Q.Y, 1]
-> PQ.a = P.Y - Q.Y
PQ.b = Q.X - P.X
PQ.c = P.X*Q.Y - Q.X*P.Y
You can verify mathematically that points P and Q are both on the above-described line PQ.
To represent the segment of line AB that intersects the rectangle, first compute vector V = B - A, as in #btilly's answer. For homogeneous coordinates, this works as follows:
A = [A.X, A.Y, 1]
B = [B.X, B.Y, 1]
-> V = B - A = [B.X-A.X, B.Y-A.Y, 0]
for any point C on AB: homogeneous coordinates for C = u*A + v*V
(where u and v are not both zero)
Point C will be on the ray part of the line only if u and v are both non-negative. (This representation may seem obscure, compared to the usual formulation of C = A + lambda * V, but doing it this way avoids unnecessary divide-by-zero cases...)
Now, we can compute the ray intersection: we represent a segment of the line AB by the parametric [u,v] coordinates of each endpoint: { start = [start.u, start.v]; end = [end.u, end.v] }.
We compute the edges of the rectangle in the counterclockwise direction, so that points inside the rectangle are on the left/positive side (L(P)>0) of every edge.
Starting segment is entire ray:
start.u = 1; start.v = 0
end.u = 0; end.v = 1
for each counterclockwise-directed edge L of the rectangle:
compute:
L(A) = L.a*A.X + L.b*A.Y + L.c
L(V) = L.a*V.X + L.b*V.Y
L(start) = start.u * L(A) + start.v * L(V)
L(end) = end.u * L(A) + end.v * L(V)
if L(start) and L(end) are both less than zero:
exit early: return "no intersection found"
if L(start) and L(end) are both greater or equal to zero:
do not update the segment; continue with the next line
else, if L(start) < 0:
update start coordinates:
start.u := L(V)
start.v := -L(A)
else, if L(end) < 0:
update end coordinates:
end.u := -L(V)
end.v := L(A)
on normal loop exit, the ray does intersect the rectangle;
the part of the ray inside the rectangle is the segment between points:
homog_start = start.u * A + start.v * V
homog_end = end.u * A + end.v * V
return "intersection found":
intersection_start.X = homog_start.x/homog_start.w
intersection_start.Y = homog_start.y/homog_start.w
intersection_end.X = homog_end.x/homog_end.w
intersection_end.Y = homog_end.y/homog_end.w
Note that this will work for arbitrary convex polygons, not just rectangles; the above is actually a general ray/convex polygon intersection algorithm. For a rectangle, you can unroll the for-loop; and, if the rectangle is axis-aligned, you can drastically simplify the arithmetic. However, the 4-case decision in the inner loop should remain the same for each edge.

Testing whether a line segment intersects a sphere

I am trying to determine whether a line segment (i.e. between two points) intersects a sphere. I am not interested in the position of the intersection, just whether or not the segment intersects the sphere surface. Does anyone have any suggestions as to what the most efficient algorithm for this would be? (I'm wondering if there are any algorithms that are simpler than the usual ray-sphere intersection algorithms, since I'm not interested in the intersection position)
If you are only interested if knowing if it intersects or not then your basic algorithm will look like this...
Consider you have the vector of your ray line, A -> B.
You know that the shortest distance between this vector and the centre of the sphere occurs at the intersection of your ray vector and a vector which is at 90 degrees to this which passes through the centre of the sphere.
You hence have two vectors, the equations of which fully completely defined. You can work out the intersection point of the vectors using linear algebra, and hence the length of the line (or more efficiently the square of the length of the line) and test if this is less than the radius (or the square of the radius) of your sphere.
I don't know what the standard way of doing it is, but if you only want to know IF it intersects, here is what I would do.
General rule ... avoid doing sqrt() or other costly operations. When possible, deal with the square of the radius.
Determine if the starting point is inside the radius of the sphere. If you know that this is never the case, then skip this step. If you are inside, your ray will intersect the sphere.
From here on, your starting point is outside the sphere.
Now, imagine the small box that will fit sphere. If you are outside that box, check the x-direction, y-direction and z-direction of the ray to see if it will intersect the side of the box that your ray starts at. This should be a simple sign check, or comparison against zero. If you are outside the and moving away from it, you will never intersect it.
From here on, you are in the more complicated phase. Your starting point is between the imaginary box and the sphere. You can get a simplified expression using calculus and geometry.
The gist of what you want to do is determine if the shortest distance between your ray and the sphere is less than radius of the sphere.
Let your ray be represented by (x0 + it, y0 + jt, z0 + kt), and the centre of your sphere be at (xS, yS, zS). So, we want to find t such that it would give the shortest of (xS - x0 - it, yS - y0 - jt, zS - z0 - kt).
Let x = xS - x0, y = yX - y0, z = zS - z0, D = magnitude of the vector squared
D = x^2 -2*xit + (i*t)^2 + y^2 - 2*yjt + (j*t)^2 + z^2 - 2*zkt + (k*t)^2
D = (i^2 + j^2 + k^2)t^2 - (xi + yj + zk)*2*t + (x^2 + y^2 + z^2)
dD/dt = 0 = 2*t*(i^2 + j^2 + k^2) - 2*(xi + yj + z*k)
t = (xi + yj + z*k) / (i^2 + j^2 + k^2)
Plug t back into the equation for D = .... If the result is less than or equal the square of the sphere's radius, you have an intersection. If it is greater, then there is no intersection.
This page has an exact solution for this problem. Essentially, you are substituting the equation for the line into the equation for the sphere, then computes the discriminant of the resulting quadratic. The values of the discriminant indicate intersection.
Are you still looking for an answer 13 years later? Here is a complete and simple solution
Assume the following:
the line segment is defined by endpoints as 3D vectors v1 and v2
the sphere is centered at vc with radius r
Ne define the three side lengths of a triangle ABC as:
A = v1-vc
B = v2-vc
C = v1-v2
If |A| < r or |B| < r, then we're done; the line segment intersects the sphere
After doing the check above, if the angle between A and B is acute, then we're done; the line segment does not intersect the sphere.
If neither of these conditions are met, then the line segment may or may not intersect the sphere. To find out, we just need to find H, which is the height of the triangle ABC taking C as the base. First we need φ, the angle between A and C:
φ = arccos( dot(A,C) / (|A||C|) )
and then solve for H:
sin(φ) = H/|A|
===> H = |A|sin(φ) = |A| sqrt(1 - (dot(A,C) / (|A||C|))^2)
and we are done. The result is
if H < r, then the line segment intersects the sphere
if H = r, then the line segment is tangent to the sphere
if H > r, then the line segment does not intersect the sphere
Here that is in Python:
import numpy as np
def unit_projection(v1, v2):
'''takes the dot product between v1, v2 after normalization'''
u1 = v1 / np.linalg.norm(v1)
u2 = v2 / np.linalg.norm(v2)
return np.dot(u1, u2)
def angle_between(v1, v2):
'''computes the angle between vectors v1 and v2'''
return np.arccos(np.clip(unit_projection(v1, v2), -1, 1))
def check_intersects_sphere(xa, ya, za, xb, yb, zb, xc, yc, zc, radius):
'''checks if a line segment intersects a sphere'''
v1 = np.array([xa, ya, za])
v2 = np.array([xb, yb, zb])
vc = np.array([xc, yc, zc])
A = v1 - vc
B = v2 - vc
C = v1 - v2
if(np.linalg.norm(A) < radius or np.linalg.norm(B) < radius):
return True
if(angle_between(A, B) < np.pi/2):
return False
H = np.linalg.norm(A) * np.sqrt(1 - unit_projection(A, C)**2)
if(H < radius):
return True
if(H >= radius):
return False
Note that I have written this so that it returns False when either endpoint is on the surface of the sphere, or when the line segment is tangent to the sphere, because it serves my purposes better.
This might be essentially what user Cruachan suggested. A comment there suggests that other answers are "too elaborate". There might be a more elegant way to implement this that uses more compact linear algebra operations and identities, but I suspect that the amount of actual compute required boils down to something like this. If someone sees somewhere to save some effort please do let us know.
Here is a test of the code. The figure below shows several trial line segments originating from a position (-1, 1, 1) , with a unit sphere at (1,1,1). Blue line segments have intersected, red have not.
And here is another figure which verifies that line segments that stop just short of the sphere's surface do not intersect, even if the infinite ray that they belong to does:
Here is the code that generates the image:
import matplotlib.pyplot as plt
radius = 1
xc, yc, zc = 1, 1, 1
xa, ya, za = xc-2, yc, zc
nx, ny, nz = 4, 4, 4
xx = np.linspace(xc-2, xc+2, nx)
yy = np.linspace(yc-2, yc+2, ny)
zz = np.linspace(zc-2, zc+2, nz)
n = nx * ny * nz
XX, YY, ZZ = np.meshgrid(xx, yy, zz)
xb, yb, zb = np.ravel(XX), np.ravel(YY), np.ravel(ZZ)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for i in range(n):
if(xb[i] == xa): continue
intersects = check_intersects_sphere(xa, ya, za, xb[i], yb[i], zb[i], xc, yc, zc, radius)
color = ['r', 'b'][int(intersects)]
s = [0.3, 0.7][int(intersects)]
ax.plot([xa, xb[i]], [ya, yb[i]], [za, zb[i]], '-o', color=color, ms=s, lw=s, alpha=s/0.7)
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = np.outer(np.cos(u), np.sin(v)) + xc
y = np.outer(np.sin(u), np.sin(v)) + yc
z = np.outer(np.ones(np.size(u)), np.cos(v)) + zc
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='k', linewidth=0, alpha=0.25, zorder=0)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.tight_layout()
plt.show()
you sorta have to work that the position anyway if you want accuracy. The only way to improve speed algorithmically is to switch from ray-sphere intersection to ray-bounding-box intersection.
Or you could go deeper and try and improve sqrt and other inner function calls
http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection

Resources