Points of intersection of vector with cone - intersection

I have a Vector A defined as : (Ao+t∗Ad)
I also have a Cone with vertex (cone tip) V, axis direction D, base radius R and height H.
How can I find the points of intersection between the vector and cone? I'm using glm for maths.
Here's a simple illustration:

I'm not handling all the cases where the ray intersects the cone, such as if the ray lies on the cone or if the ray is tangent to the cone, because it's not necessary in my case, but here's the solution I ended up with:
std::array<glm::vec3,2> getLine2ConeIntersection(const glm::vec3 &ap_,const glm::vec3 &ad_ , const glm::vec3 &coneBaseCntr_,const glm::vec3 &coneVertex_,float coneRadius_) const
{
std::array<glm::vec3,2> pois;
glm::vec3 axis = (coneBaseCntr_-coneVertex_);
glm::vec3 theta = (axis/glm::length(axis));
float m = pow(coneRadius_,2)/pow(glm::length(axis),2);
glm::vec3 w = (ap_-coneVertex_);
float a = glm::dot(ad_,ad_) - m*(pow(glm::dot(ad_,theta),2)) - pow(glm::dot(ad_,theta),2);
float b = 2.f*( glm::dot(ad_,w) - m*glm::dot(ad_,theta)*glm::dot(w,theta) - glm::dot(ad_,theta)*glm::dot(w,theta) );
float c = glm::dot(w,w) - m*pow(glm::dot(w,theta),2) - pow(glm::dot(w,theta),2);
float discriminant = pow(b,2) - (4.f*a*c);
if (discriminant >= 0)
{
pois[0] = (ap_+static_cast<float>(((-b) - sqrt(discriminant))/(2.f*a))*ad_);
pois[1] = (ap_+static_cast<float>(((-b) + sqrt(discriminant))/(2.f*a))*ad_);
}
return pois;
}
Where ap_ is a point on the vector and ad_ is it's direction.

Related

how do you reflect a vector over another vector?

I'm using AS3 to program some collision detection for a flash game and am having trouble figuring out how to bounce a ball off of a line. I keep track of a vector that represents the ball's 2D velocity and I'm trying to reflect it over the vector that is perpendicular to the line that the ball's colliding with (aka the normal). My problem is that I don't know how to figure out the new vector (that's reflected over the normal). I figured that you can use Math.atan2 to find the difference between the normal and the ball's vector but I'm not sure how to expand that to solve my problem.
Vector algebra - You want the "bounce" vector:
vec1 is the ball's motion vector and vec2 is the surface/line vector:
// 1. Find the dot product of vec1 and vec2
// Note: dx and dy are vx and vy divided over the length of the vector (magnitude)
var dpA:Number = vec1.vx * vec2.dx + vec1.vy * vec2.dy;
// 2. Project vec1 over vec2
var prA_vx:Number = dpA * vec2.dx;
var prA_vy:Number = dpA * vec2.dy;
// 3. Find the dot product of vec1 and vec2's normal
// (left or right normal depending on line's direction, let's say left)
var dpB:Number = vec1.vx * vec2.leftNormal.dx + vec1.vy * vec2.leftNormal.dy;
// 4. Project vec1 over vec2's left normal
var prB_vx:Number = dpB * vec2.leftNormal.dx;
var prB_vy:Number = dpB * vec2.leftNormal.dy;
// 5. Add the first projection prA to the reverse of the second -prB
var new_vx:Number = prA_vx - prB_vx;
var new_vy:Number = prA_vy - prB_vy;
Assign those velocities to your ball's motion vector and let it bounce.
PS:
vec.leftNormal --> vx = vec.vy; vy = -vec.vx;
vec.rightNormal --> vx = -vec.vy; vy = vec.vx;
The mirror reflection of any vector v from a line/(hyper-)surface with normal n in any dimension can be computed using projection tensors. The parallel projection of v on n is: v|| = (v . n) n = v . nn. Here nn is the outer (or tensor) product of the normal with itself. In Cartesian coordinates it is a matrix with elements: nn[i,j] = n[i]*n[j]. The perpendicular projection is just the difference between the original vector and its parallel projection: v - v||. When the vector is reflected, its parallel projection is reversed while the perpendicular projection is retained. So the reflected vector is:
v' = -v|| + (v - v||) = v - 2 v|| = v . (I - 2 nn) = v . R( n ), where
R( n ) = I - 2 nn
(I is the identity tensor which in Cartesian coordinates is simply the diagonal identity matrix diag(1))
R is called the reflection tensor. In Cartesian coordinates it is a real symmetric matrix with components R[i,j] = delta[i,j] - 2*n[i]*n[j], where delta[i,j] = 1 if i == j and 0 otherwise. It is also symmetric with respect to n:
R( -n ) = I - 2(-n)(-n) = I - 2 nn = R( n )
Hence it doesn't matter if one uses the outward facing or the inward facing normal n - the result would be the same.
In two dimensions and Cartesian coordinates, R (the matrix representation of R) becomes:
[ R00 R01 ] [ 1.0-2.0*n.x*n.x -2.0*n.x*n.y ]
R = [ ] = [ ]
[ R10 R11 ] [ -2.0*n.x*n.y 1.0-2.0*n.y*n.y ]
The components of the reflected vector are then computed as a row-vector-matrix product:
v1.x = v.x*R00 + v.y*R10
v1.y = v.x*R01 + v.y*R11
or after expansion:
k = 2.0*(v.x*n.x + v.y*n.y)
v1.x = v.x - k*n.x
v1.y = v.y - k*n.y
In three dimensions:
k = 2.0*(v.x*n.x + v.y*n.y + v.z*n.z)
v1.x = v.x - k*n.x
v1.y = v.y - k*n.y
v1.z = v.z - k*n.z
Finding the exact point where the ball will hit the line/wall is more involved - see here.
Calculate two components of the vector.
One component will be the projection of your vector onto the reflecting surface the other component will be the projection on to the surface's normal (which you say you already have). Use dot products to get the projections. Add these two components together by summing the two vectors. You'll have your answer.
You can even calculate the second component A2 as being the original vector minus the first component, so: A2 = A - A1. And then the vector you want is A1 plus the reflected A2 (which is simply -A2 since its perpendicular to your surface) or:
Ar = A1-A2
or
Ar = 2A1 - A which is the same as Ar = -(2A2 - A)
If [Ax,Bx] is your balls velocity and [Wx,Wy] is a unit vector representing the wall:
A1x = (Ax*Wx+Ay*Wy)*Wx;
A1y = (Ax*Wx+Ay*Wy)*Wy;
Arx = 2*A1x - Ax;
Ary = 2*A1y - Ay;

the relation of the bezier Curve and ellipse?

I want to draw a oval in html5 canvas,and i found a good method for it in stackoverflow.but I have another quesition.
function drawEllipse(ctx, x, y, w, h) {
var kappa = 0.5522848;
ox = (w / 2) * kappa, // control point offset horizontal
oy = (h / 2) * kappa, // control point offset vertical
xe = x + w, // x-end
ye = y + h, // y-end
xm = x + w / 2, // x-middle
ym = y + h / 2; // y-middle
ctx.beginPath();
ctx.moveTo(x, ym);
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
ctx.closePath();
ctx.stroke();
}
the method in the above link has use bezierCurveTo to draw a ellipse,but it has draw bezierCurveTo 4 times. but I think just 2 bezierCurveTo can draw a ellipse.like this:
but i'm weak in Mathematics,could someone tell me the relationship of "the control point" and "the oval point" please? or we must draw four bezier Curve to draw a oval?
thanks everybody
My background isn't in mathematics so if I'm wrong I'm sure someone will correct me, but from my understanding we can draw a pretty good approximation of an ellipse with just two cubic bezier curves but the coordinates will be a little tricky.
To answer your question about the relation between the oval point and the control points I think it best be answered by watching this video from the point I've selected if you're familiar with interpolation or from the beginning if you are not. Don't worry it is short.
One problem we're probably going to run into is that when we start from the top and do a bezierCurveTo the bottom of the ellipse with the corners of the rectangle (of the same width and height) as the control points, the ellipses width is going to be smaller than the rectangle. .75 times the size we want. So we can just scale the control points accordingly.
Our control point's x would be adjusted like so (assuming width is the width of the ellipse and we're dividing by two to get its offset from the origin)
var cpx = (width / .75) / 2;
Put together a visualization where you can play with the width and height and see the drawn ellipse.
The red ellipse is how we wanted it to be drawn, with the inner one how it would be drawn if we didnt reposition the control points. The lines illustrate De Casteljau's algorithm that was shown in the video.
Here's a screenshot of the visualization
You only need two cubic bezier curves to draw an ellipse. Here's a simplified version of DerekR's code that uses the original function arguments that you provided--assuming you want x and y to be the center of the ellipse:
jsFiddle
function drawEllipse(ctx, x, y, w, h) {
var width_over_2 = w / 2;
var width_two_thirds = w * 2 / 3;
var height_over_2 = h / 2;
ctx.beginPath();
ctx.moveTo(x, y - height_over_2);
ctx.bezierCurveTo(x + width_two_thirds, y - height_over_2, x + width_two_thirds, y + height_over_2, x, y + height_over_2);
ctx.bezierCurveTo(x - width_two_thirds, y + height_over_2, x - width_two_thirds, y - height_over_2, x, y -height_over_2);
ctx.closePath();
ctx.stroke();
}
Big thanks to BKH.
I used his code with two bezier curves to complete my ellipse drawing with any rotation angle. Also, I created an comparison demo between ellipses drawn by bezier curves and native ellipse() function (for now implemented only in Chrome).
function drawEllipseByBezierCurves(ctx, x, y, radiusX, radiusY, rotationAngle) {
var width_two_thirds = radiusX * 4 / 3;
var dx1 = Math.sin(rotationAngle) * radiusY;
var dy1 = Math.cos(rotationAngle) * radiusY;
var dx2 = Math.cos(rotationAngle) * width_two_thirds;
var dy2 = Math.sin(rotationAngle) * width_two_thirds;
var topCenterX = x - dx1;
var topCenterY = y + dy1;
var topRightX = topCenterX + dx2;
var topRightY = topCenterY + dy2;
var topLeftX = topCenterX - dx2;
var topLeftY = topCenterY - dy2;
var bottomCenterX = x + dx1;
var bottomCenterY = y - dy1;
var bottomRightX = bottomCenterX + dx2;
var bottomRightY = bottomCenterY + dy2;
var bottomLeftX = bottomCenterX - dx2;
var bottomLeftY = bottomCenterY - dy2;
ctx.beginPath();
ctx.moveTo(bottomCenterX, bottomCenterY);
ctx.bezierCurveTo(bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY);
ctx.bezierCurveTo(topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY);
ctx.closePath();
ctx.stroke();
}
You will find this explained slightly more math-based in http://pomax.github.io/bezierinfo/#circles_cubic, but the gist is that using a cubic bezier curve for more than a quarter turn is usually not a good idea. Thankfully, using four curves makes finding the required control points rather easy. Start off with a circle, in which case each quarter circle is (1,0)--(1,0.55228)--(0.55228,1)--(0,1) with scaled coordinates for your ellipse. Draw that four times with +/- signs swapped to effect a full circle, scale the dimensions to get your ellipse, and done.
If you use two curves, the coordinates become (1,0)--(1,4/3)--(-1,4/3)--(-1,0), scaled for your ellipse. It may still look decent enough in your application, it depends a bit on how big your drawing ends up being.
It can be mathematically proven, that circle can not be made with Bézier curve of any degree. You can make "almost circle" by approximating it.
Say you want to draw a quarter of circle around [0,0]. Cubic bézier coordinates are:
[0 , 1 ]
[0.55, 1 ]
[1 , 0.55]
[1 , 0 ]
It is a very good approximation. Transform it linearly to get an ellpise.

get skew or rotation value from affine transformation matrix

I'm trying to get the skew values out of a transformation matrix in a flash movie clip. The transformation matrix is represented by
a b tx
c d ty
0 0 1
I have no information on what kind of transformation is performed and which comes first. I do know that in flash, you may only rotate OR skew a movie clip (correct me if I am wrong). I can get scale values from scaleX and scaleY properties of the movie clip. I believe translation does not quite matter i can just equate tx and ty to zero.
so my question has 2 parts. How do I determine if a skew or a rotation had been applied, and how do I get the respective values?
The 2D rotation matrix is
cos(theta) -sin(theta)
sin(theta) cos(theta)
so if you have no scaling or shear applied,
a = d
and
c = -b
and the angle of rotation is
theta = asin(c) = acos(a)
If you've got scaling applied and can recover the scaling factors sx and sy, just divide the first row by sx and the second by sy in your original transformation matrix and then recover the rotation angle as above.
If you've got a shear (skew) applied anywhere in there, I'm with the previous commenters, it might not be possible except in very limited cases (such as shear in only one known direction at a time and in a known order).
You need to do a polar decomposition. This Wikipedia article explains how it works:
http://en.wikipedia.org/wiki/Polar_decomposition
Here is the code I wrote for my own program using the OpenCV library.
const double PI = 3.141592653;
cv::Mat rotationOutput = cv::Mat::zeros(warp00.size(),CV_64F);
cv::Mat_<double>::iterator rotIter = rotationOutput.begin<double>();
cv::Mat_<double>::iterator warp00Iter = warp00.begin<double>();
cv::Mat_<double>::iterator warp01Iter = warp01.begin<double>();
cv::Mat_<double>::iterator warp10Iter = warp10.begin<double>();
cv::Mat_<double>::iterator warp11Iter = warp11.begin<double>();
for(; warp00Iter != warp00.end<double>(); ++warp00Iter, ++warp01Iter, ++warp10Iter,
++warp11Iter, ++rotIter){
cv::Matx22d fMatrix(*warp00Iter,*warp01Iter, *warp10Iter, *warp11Iter);
cv::Matx22d cMatrix;
cv::Matx22d cMatSqrt(0.,0.,0.,0.);
cv::mulTransposed(fMatrix, cMatrix, true);
cv::Matx21d eigenVals;
cv::Matx22d eigenVecs;
if((cMatrix(0,0) !=0.) && (cMatrix(1,1) !=0.)){
if(cv::eigen(cMatrix,true,eigenVals,eigenVecs)){
cMatSqrt = eigenVecs.t()*
cv::Matx22d(sqrt(eigenVals(0,0)),0.,0.,sqrt(eigenVals(1,0)))*eigenVecs;
}
}
cv::Matx22d rMat = fMatrix*cMatSqrt.inv();
*rotIter = atan(rMat(1,0)/rMat(0,0));
}
warp00, warp01, warp10 and warp11 contains the first 4 params of the affine transform (translation params warp02 and warp12 are not needed). IN your case it would be a,b,c,d.
You'll notice in the wikipedia article that you need to compute the square root of a matrix. The only way to do so is by computing the eigen values, then compute their square roots and rotate the diagonal matrix back to the original coordinate system.
It's complicated, but it is the only way to compute the rotations when you have an affine transform.
In my case, I only cared about the rotations, so my code won't give you the skew.
The term for this is matrix decomposition. Here is a solution that includes skew as described by Frédéric Wang.
Works when transforms are applied in this order: skew, scale, rotate, translate.
function decompose_2d_matrix(mat) {
var a = mat[0];
var b = mat[1];
var c = mat[2];
var d = mat[3];
var e = mat[4];
var f = mat[5];
var delta = a * d - b * c;
let result = {
translation: [e, f],
rotation: 0,
scale: [0, 0],
skew: [0, 0],
};
// Apply the QR-like decomposition.
if (a != 0 || b != 0) {
var r = Math.sqrt(a * a + b * b);
result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
result.scale = [r, delta / r];
result.skew = [Math.atan((a * c + b * d) / (r * r)), 0];
} else if (c != 0 || d != 0) {
var s = Math.sqrt(c * c + d * d);
result.rotation =
Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
result.scale = [delta / s, s];
result.skew = [0, Math.atan((a * c + b * d) / (s * s))];
} else {
// a = b = c = d = 0
}
return result;
}
First, you can do both skew and rotate, but you have to select the order first. A skew matrix is explained here, to add a skew matrix to a transformation you create a new matrix and do yourTransformMatrix.concat(skewMatrix);
I can't currently say if you can retrieve values for transformation in terms of "rotation angle", "skew_X angle", "skew_Y angle", "translation_X","translation_Y", this in general is a nonlinear equation system which might not have a solution for a specific matrix.

AS3 - Y Velocity 6.123031769111886E-17

When given 0,0 to 0,5, the y velocity becomes that number and breaks my code. I know I must have done something wrong as I just copy and pasted code (since I am horrible at maths)..
This is how I calculate the numbers:
var radian = Math.atan2(listOfNodes[j].y - listOfNodes[i].y,listOfNodes[j].x - listOfNodes[i].x);
var vy = Math.cos(radian);
var vx = Math.sin(radian);
Thanks
There i am assuming the velocity vector is FROM 0,0 TO 0,5. And 0,0 is i and 0,5 is j.
In that case the velocity vector is only along y and the y component should be 5 and x component 0. It is coming as opposite because,
cos(radian) whould be x velocity component and sin(radian) the y compunent.
And the number 6.123031769111886E-17 is actually returned in place of 0.
Look at the following figure:
Also as can be seen from the figure you do not need the trigonometric computations at all.
You can simply get the x and y components as follows:
// y2 - y1
var vy = listOfNodes[j].y - listOfNodes[i].y;
// x2 - x1
var vx = listOfNodes[j].x - listOfNodes[i].x;
This will avoid the floating point inaccuracy caused by the trig finctions due to which you are seeing 6.123031769111886E-17 instead of 0.
You only need to use atan2 if you actually need the angle θ in your code.
Update:
Well if you need only unit (normalized) vector's components you can divide the vx and vy with the length of the original vector. Like this:
// y2 - y1
var vy = listOfNodes[j].y - listOfNodes[i].y;
// x2 - x1
var vx = listOfNodes[j].x - listOfNodes[i].x;
// vector magnitude
var mag = Math.sqrt(vx * vx + vy * vy);
// get unit vector components
vy /= mag;
vx /= mag;
Using the above you will get the exactly the same results as you are getting from trig sin and cos functions.
But if you still need to use the original code and want to make 6.12...E-17 compare to 0, you can use the epsilon technique for comparing floats. So you can compare any value within epsilon's range from 0, using flllowing code:
function floatCompare(a:Number, b:Number, epsilon:Number):Boolean{
return (a >= (b - epsilon) && a <= (b + epsilon));
}
// To check for zero use this code, here i'm using 0.0001 as epsilon
if(floatCompare(vx, 0, 0.0001)){
// code here
}
So any deviation in the range of [b-epsilon, b+epsilon] would successfully compare to b. This is essential in case of floating point arithmetic.

Find the last co-ordinate of isosceles triangle given coordinates of base and altitude

I have no clue about trigonometry, despite learning it in school way back when, and I figure this should be pretty straightforward, but trawling through tons of trig stuff on the web makes my head hurt :) So maybe someone could help me...
The title explains exactly what I want to do, I have a line:
x1,y1 and x2,y2
and want a function to find x3,y3 to complete an isosceles triangle, given the altitude.
Just to be clear, the line x1,y2 -> x2,y2 will be the base, and it will not be aligned any axis (it will be at a random angle..)
Does anyone have a simple function for this??
construct a normal to the vector (x1,y1)->(x2,y2). place it at the midpoint ((x1+x2)/2,(y1+y2)/2) and go out a distance h.
the normal will look like (-(y2-y1),x2-x1). make this a unit vector (http://en.wikipedia.org/wiki/Unit_vector).
add h times this unit vector to the midpoint.
The third point is on the perpendicular bisector of your base, and is altitude units away from the line.
Calculate the midpoint of the base by averaging the x and y coordinates.
Calculate the slope of your altitude: -dx/dy (perpendicular to dy/dx). You now have your line (point and slope).
y - my = -dx/dy * (x - mx)
Substitute your variables in the distance formula: d = sqrt(dx^2 + dy^2)
d = sqrt((x - mx)^2 + (y - my)^2)
d = sqrt((x - mx)^2 + (-dx/dy * (x - mx))^2)
d^2 = (x - mx)^2 + (-dx/dy * (x - mx))^2
d^2 - (x - mx)^2 = (-dx/dy * (x - mx))^2
±sqrt(d^2 - (x - mx)^2) = -dx/dy * (x - mx)
±sqrt(d^2 - (x - mx)^2) * dy/dx = x - mx
±sqrt(d^2 - (x - mx)^2) * dy/dx + mx = x
x = ±sqrt(d^2 - (x - mx)^2) * dy/dx + mx
Calculate the other variable (y here) using your line equation (from #2).
You now have two points; pick whichever you want...
In pseudocode:
dx = x1 - x2
midpoint = ((x1 + x2) / 2, (y1 + y2) / 2)
slope = -dx / (y1 - y2)
x = sqrt(altitude*altitude - dx*dx) / slope + midpoint.x
y = slope * (x - midpoint.x) + midpoint.y
This is probably not the most optimal method. Not sure if it even works. xD
Al I can remember is that an isosceles triangle will have sides of equal length, and equal angles at the base. If you have the height, then you have the final coordinate because this will be the point of intersection, right?