I have 2 vectors, each defined by 2 Point3D (origin and direction). I need to find out the point of their intersection.
A little bit of help is always welcome.
I will post my function, which gives me wrong output.
public static CurvIntersect3D Intersect2Linii3D (Vector3D dr1, Vector3D dr2) {
CurvIntersect3D result = new CurvIntersect3D(0, null);
double x = Math3D.VectorNorm3D(dr1.getDirectie());
double t = Math3D.VectorNorm3D(dr2.getDirectie());
double cosa = (dr1.getDirectie().getX()*dr2.getDirectie().getX() + dr1.getDirectie().getY()*dr2.getDirectie().getY() + dr1.getDirectie().getZ()*dr2.getDirectie().getZ()) / (t*x);
Punct3D p1 = dr1.getOrigine();
Punct3D p2 = new Punct3D(), p3 = new Punct3D();
for (int i=0; i<3; i++)
{
p2.set(i, dr1.getOrigine().get(i) + dr1.getDirectie().get(i));
p3.set(i, dr1.getOrigine().get(i) + dr2.getDirectie().get(i));
}
Matrici.Matrice3x3 rot = Math3D.GetMatriceRotatie(p1, p2, p3);
Punct3D orig = new Punct3D();
for (int i=0; i<3; i++)
orig.set(i, rot.getElement(i, 0) * (dr2.getOrigine().getX()-dr1.getOrigine().getX()) +
rot.getElement(i, 1) * (dr2.getOrigine().getY()-dr1.getOrigine().getY()) +
rot.getElement(i, 2) * (dr2.getOrigine().getZ()-dr1.getOrigine().getZ()));
x = orig.getY() - orig.getZ()* cosa / Math.sqrt(1 - cosa*cosa);
p1 = new Punct3D();
for (int i=0; i<3; i++)
p1.set(i, dr1.getOrigine().get(i) + x*dr1.getDirectie().get(i));
result.setCount(1);
result.add(p1);
return result;
}
CurvIntersec3D is a structure that stores the array of points and its length.
As mentioned before the two lines may not meet at a single point. The best you can do in general is find the point on line1 closest to line2 and vise versa. Connect those two points to create the common normal direction.
Given two lines passing through 3D points r1=[r1x,r1y,r1z] and r2=[r2x,r2y,r2z] and having unit directions e1=[e1x,e1y,e1z] and e2=[e2x,e2y,e2z] you can find the points on the line which are closest to the other line like this:
Find the direction projection u=Dot(e1,e2)=e1x*e2x+e1y*e2y+e1z*e2z
If u==1 then lines are parallel. No intersection exists.
Find the separation projections t1=Dot(r2-r1,e1) and t2=Dot(r2-r1,e2)
Find distance along line1 d1 = (t1-u*t2)/(1-u*u)
Find distance along line2 d2 = (t2-u*t1)/(u*u-1)
Find the point on line1 p1=Add(r1,Scale(d1,e1))
Find the point on line2 p2=Add(r2,Scale(d2,e2))
Note: You must have the directions as unit vectors, Dot(e1,e1)=1 and Dot(e2,e2)=1.
The function Dot() is the vector dot product. The function Add() adds the components of vectors, and the function Scale() multiplies the components of the vector with a number.
Good luck.
Are you sure that your lines have intersection?
If it is guaranteed, then the problem is rather simple: Get parametric equations of lines, solve a system of two linear equations like these:
A_X0+t*A_Dir_X = B_X0+u*B_DirX , where X0 is base point, and Dir is direction vector (take into account any pair of coordinates with non-zero cross product)
If not, then it is necessary to calculate a distance between two skew lines at first. If the distance is zero, then we could find intersection point.
Related
I know how to get distance between points, however I want to get distance between 2 objects where each object has several points. (See illustration below.)
I want to calculate distance between object A and object B based on their points with Euclidean Distance.
Can I use euclidean distance for my problem?
Example Equation in Java: Math.SQRT(Math.sqr(y2-y1) + Math.sqr(x2-x1));
The maybe best way might be (as #Erica already suggested) to take the distance as the sum of the distances of the closest points, but beware, this is NOT SYMMETRIC, hence not a real distance in the mathematician way. To gain symmetric you might add it with the same sum of the other object, this will yield a mathematician distance method.
Another way would be to index the points and take the distance of the same points (when you know, there are always the same amount of points). This has the drawback, that the same points with different index is another object (you might indicate it with the distance to root and anti-clockwise for same distance to negate that effect). This also yields a mathematician distance method.
Code example for first one (one side):
double distance = 0;
for(Point x : A.getPoints()){
double distOfX = 0;
for(Point y : B.getPoints()){
double tempDist = Math.pow(x.getX()-y.getX(),2)+Math.pow(x.getY()-y.getY(),2);
distOfX = tempDist>distOfX?tempDist:distOfX;
}
distance += Math.sqrt(distOfX);
}
And for the second case (after indicating):
double distance = 0;
if(A.getPoints().length != B.getPoints().length)
distance = -1;
else{
for(int i=0; i<A.getPoints().length; i++){
distance += Math.sqrt( Math.pow(A.getPoints()[i].getX()-B.getPoints()[i].getX(),2)+Math.pow(A.getPoints()[i].getY()-B.getPoints()[i].getY(),2));
}
}
try this method:
// GET DISTANCE METHOD
//Calculate the distance between two points base on their coordinates
public float getDistance(float X_1, float Y_1, float X_2, float Y_2) {
//define the output distance
float Distance;
//calculate the distance
Distance = (float) Math.sqrt(Math.pow((X_1 - X_2),2) + Math.pow((Y_1 - Y_2),2));
//output the distance
return Distance;
}
I wanna to produce a Pie Chart on a Hexagon. There are probably several solutions for this. In the picture are my Hexagon and two Ideas:
My Hexagon (6 vertices, 4 faces)
How it should look at the end (without the gray lines)
Math: Can I get some informations from the object to dynamically calculate new vertices (from the center to each point) to add colored faces?
Clipping: On a sphere a Pie-Chart is easy, maybe I can clip the THREE Object (WITHOUT SVG.js!) so I just see the Hexagon with the clipped Chart?
Well the whole clipping thing in three.js is already solved here : Object Overflow Clipping Three JS, with a fiddle that shows it works and all.
So I'll go for the "vertices" option, or rather, a function that, given a list of values gives back a list of polygons, one for each value, that are portions of the hexagon, such that
they all have the centre point as a vertex
the angle they have at that point is proportional to the value
they form a partition the hexagon
Let us suppose the hexagon is inscribed in a circle of radius R, and defined by the vertices :
{(R sqrt(3)/2, R/2), (0,R), (-R sqrt(3)/2, R/2), (-R sqrt(3)/2, -R/2), (0,-R), (R sqrt(3)/2, -R/2)}
This comes easily from the values cos(Pi/6), sin(Pi/6) and various symmetries.
Getting the angles at the centre for each polygon is pretty simple, since it is the same as for a circle. Now we need to know the position of the points that are on the hexagon.
Note that if you use the symmetries of the coordinate axes, there are only two cases : [0,Pi/6] and [Pi/6,Pi/2], and you then get your result by mirroring. If you use the rotational symmetry by Pi/3, you only have one case : [-Pi/6,Pi/6], and you get the result by rotation.
Using rotational symmetry
Thus for every point, you can consider it's angle to be between [-Pi/6,Pi/6]. Any point on the hexagon in that part has x=R sqrt(3)/2, which simplifies the problem a lot : we only have to find it's y value.
Now we assumed that we know the polar coordinate angle for our point, since it is the same as for a circle. Let us call it beta, and alpha its value in [-Pi/6,Pi/6] (modulo Pi/3). We don't know at what distance d it is from the centre, and thus we have the following system :
Which is trivially solved since cos is never 0 in the range [-Pi/6,Pi/6].
Thus d=R sqrt(3)/( 2 cos(alpha) ), and y=d sin(alpha)
So now we know
the angle from the centre beta
it's distance d from the centre, thanks to rotational symmetry
So our point is (d cos(beta), d sin(beta))
Code
Yeah, I got curious, so I ended up coding it. Sorry if you wanted to play with it yourself. It's working, and pretty ugly in the end (at least with this dataset), see the jsfiddle : http://jsfiddle.net/vb7on8vo/5/
var R = 100;
var hexagon = [{x:R*Math.sqrt(3)/2, y:R/2}, {x:0, y:R}, {x:-R*Math.sqrt(3)/2, y:R/2}, {x:-R*Math.sqrt(3)/2, y:-R/2}, {x:0, y:-R}, {x:R*Math.sqrt(3)/2, y:-R/2}];
var hex_angles = [Math.PI / 6, Math.PI / 2, 5*Math.PI / 6, 7*Math.PI / 6, 3*Math.PI / 2, 11*Math.PI / 6];
function regions(values)
{
var i, total = 0, regions = [];
for(i=0; i<values.length; i++)
total += values[i];
// first (0 rad) and last (2Pi rad) points are always at x=R Math.sqrt(3)/2, y=0
var prev_point = {x:hexagon[0].x, y:0}, last_angle = 0;
for(i=0; i<values.length; i++)
{
var j, theta, p = [{x:0,y:0}, prev_point], beta = last_angle + values[i] * 2 * Math.PI / total;
for( j=0; j<hexagon.length; j++)
{
theta = hex_angles[j];
if( theta <= last_angle )
continue;
else if( theta >= beta )
break;
else
p.push( hexagon[j] );
}
var alpha = beta - (Math.PI * (j % 6) / 3); // segment 6 is segment 0
var d = hexagon[0].x / Math.cos(alpha);
var point = {x:d*Math.cos(beta), y:d*Math.sin(beta)};
p.push( point );
regions.push(p.slice(0));
last_angle = beta;
prev_point = {x:point.x, y:point.y};
}
return regions;
}
This is a big one for any math/3d geometry lovers. Thank you in advance.
Overview
I have a figure created by extruding faces around twisting spline curves in space. I'm trying to place a "loop" (torus) oriented along the spline path at a given segment of the curve, so that it is "aligned" with the spline. By that I mean the torus's width is parallel to the spline path at the given extrusion segment, and it's height is perpendicular to the face that is selected (see below for picture).
Data I know:
I am given one of the faces of the figure. From that I can also glean that face's centroid (center point), the vertices that compose it, the surrounding faces, and the normal vector of the face.
Current (Non-working) solution outcome:
I can correctly create a torus loop around the centroid of the face that is clicked. However, it does not rotate properly to "align" with the face. See how they look a bit "off" below.
Here's a picture with the material around it:
and here's a picture with it in wireframe mode. You can see the extrusion segments pretty clearly.
Current (Non-working) methodology:
I am attempting to do two calculations. First, I'm calculating the the angle between two planes (the selected face and the horizontal plane at the origin). Second, I'm calculating the angle between the face and a vertical plane at the point of origin. With those two angles, I am then doing two rotations - an X and a Y rotation on the torus to what I hope would be the correct orientation. It's rotating the torus at a variable amount, but not in the place I want it to be.
Formulas:
In doing the above, I'm using the following to calculate the angle between two planes using their normal vectors:
Dot product of normal vector 1 and normal vector 2 = Magnitude of vector 1 * Magnitude of vector 2 * Cos (theta)
Or:
(n1)(n2) = || n1 || * || n2 || * cos (theta)
Or:
Angle = ArcCos { ( n1 * n2 ) / ( || n1 || * || n2 || ) }
To determine the magnitude of a vector, the formula is:
The square root of the sum of the components squared.
Or:
Sqrt { n1.x^2 + n1.y^2 + n1.z^2 }
Also, I'm using the following for the normal vectors of the "origin" planes:
Normal vector of horizontal plane: (1, 0, 0)
Normal vector of Vertical plane: (0, 1, 0)
I've thought through the above normal vectors a couple times... and I think(?) they are right?
Current Implementation:
Below is the code that I'm currently using to implement it. Any thoughts would be much appreciated. I have a sinking feeling that I'm taking a wrong approach in trying to calculate the angles between the planes. Any advice / ideas / suggestions would be much appreciated. Thank you very much in advance for any suggestions.
Function to calculate the angles:
this.toRadians = function (face, isX)
{
//Normal of the face
var n1 = face.normal;
//Normal of the vertical plane
if (isX)
var n2 = new THREE.Vector3(1, 0, 0); // Vector normal for vertical plane. Use for Y rotation.
else
var n2 = new THREE.Vector3(0, 1, 0); // Vector normal for horizontal plane. Use for X rotation.
//Equation to find the cosin of the angle. (n1)(n2) = ||n1|| * ||n2|| (cos theta)
//Find the dot product of n1 and n2.
var dotProduct = (n1.x * n2.x) + (n1.y * n2.y) + (n1.z * n2.z);
// Calculate the magnitude of each vector
var mag1 = Math.sqrt (Math.pow(n1.x, 2) + Math.pow(n1.y, 2) + Math.pow(n1.z, 2));
var mag2 = Math.sqrt (Math.pow(n2.x, 2) + Math.pow(n2.y, 2) + Math.pow(n2.z, 2));
//Calculate the angle of the two planes. Returns value in radians.
var a = (dotProduct)/(mag1 * mag2);
var result = Math.acos(a);
return result;
}
Function to create and rotate the torus loop:
this.createTorus = function (tubeMeshParams)
{
var torus = new THREE.TorusGeometry(5, 1.5, segments/10, 50);
fIndex = this.calculateFaceIndex();
//run the equation twice to calculate the angles
var xRadian = this.toRadians(geometry.faces[fIndex], false);
var yRadian = this.toRadians(geometry.faces[fIndex], true);
//Rotate the Torus
torus.applyMatrix(new THREE.Matrix4().makeRotationX(xRadian));
torus.applyMatrix(new THREE.Matrix4().makeRotationY(yRadian));
torusLoop = new THREE.Mesh(torus, this.m);
torusLoop.scale.x = torusLoop.scale.y = torusLoop.scale.z = tubeMeshParams['Scale'];
//Create the torus around the centroid
posx = geometry.faces[fIndex].centroid.x;
posy = geometry.faces[fIndex].centroid.y;
posz = geometry.faces[fIndex].centroid.z;
torusLoop.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(posx, posy, posz));
torusLoop.geometry.computeCentroids();
torusLoop.geometry.computeFaceNormals();
torusLoop.geometry.computeVertexNormals();
return torusLoop;
}
I found I was using an incorrect approach to do this. Instead of trying to calculate each angle and do a RotationX and a RotationY, I should have done a rotation by axis. Definitely was over thinking it.
makeRotationAxis(); is a function built into three.js.
So I'm trying to write code that sees if a ray intersects a flat circular disk and I was hoping to get it checked out here. My disk is always centered on the negative z axis so its normal vector should be (0,0, -1).
The way I'm doing it is first calculate the ray-plane intersection and then determining if that intersection point is within the "scope" of the disk.
In my code I am getting some numbers that seem off and I am not sure if the problem is in this method or if it is possibly somewhere else. So if there is something wrong with this code I would appreciate your feedback! =)
Here is my code:
float d = z_intercept; //This is where disk intersects z-axis. Can be + or -.
ray->d = Normalize(ray->d);
Point p(0, 0, d); //This is the center point of the disk
Point p0(0, 1, d);
Point p1(1, 0, d);
Vector n = Normalize(Cross(p0-p, p1-p));//Calculate normal
float diameter = DISK_DIAMETER; //Constant value
float t = (-d-Dot(p-ray->o, n))/Dot(ray->d, n); //Calculate the plane intersection
Point intersection = ray->o + t*ray->d;
return (Distance(p, intersection) <= diameter/2.0f); //See if within disk
//This is my code to calculate distance
float RealisticCamera::Distance(Point p, Point i)
{
return sqrt((p.x-i.x)*(p.x-i.x) + (p.y-i.y)*(p.y-i.y) + (p.z-i.z)*(p.z-i.z));
}
"My disk is always centered on the negative z axis so its normal vector should be (0,0, -1)."
This fact simplifies calculations.
Degenerated case: ray->d.z = 0 -> if ray->o.z = d then ray lies in disk plane, check as 2Dd, else ray is parallel and there is no intersection
Common case: t = (d - ray->o.z) / ray->d.z
If t has positive value, find x and y for this t, and check x^2+y^2 <= disk_radius^2
Calculation of t is wrong.
Points on the ray are:
ray->o + t * ray->d
in particular, coordinate z of a point on the ray is:
ray->o.z() + t * ray->d.z()
Which must be equal to d. That comes out
t = ( d - ray->o.z() ) / ray->d.z()
I have exported some hair particules from Blender (a hairstyle). These are composed of several lines (GL_LINES). My openGL program displays these particules without any problem. Now I just want to apply light properties on these particules. Blender does not export the normals vectors so I need to compute them by myself. I know the following rule :
If we define a line segment as [AB] in two dimensions,
we have dx = xB - xA and dy = yB - yA, then the normals are N1(-dy, dx) and N2(dy, -dx).
I hope I did not make any mistake.
But I don't know the rule for a 3D space line segment definition if I add the z dimention in my line segment coordinates (for instance A(5, 2, 3) and B(0, 0, -5)).
Does anyone can help me?
Since Aki forgot that comments aren't answers:
Lines in 3D space don't have a normal. Technically, lines in 2D space don't have a normal either; they have two normals.
There are an infinite number of directions that are perpendicular to a line in 3D space. All of these normals are in the same plane, but with different directions. Without some more advanced algorithm (likely based on adjacent lines), there is no way to pick one of these normals over another.
If you assume that you can get two vectors to begin with, and it looks like that's what you are saying, call them v, w, to get a normal vector take the cross product. It's not a bad idea to normalize v, w to begin with, depending on the situation. The cross product can be given by:
v x w =(v_2w_3 - v_3w_2, v_3x_1 - v_1w_3, v_1w_2 - v_3w_1),
Here v_i is the ith component of v and so on. The numbers next to each other represent multiplication. You, of course, have plus or minus this vector giving two possibilities.
I had a similar question, and even used the indefinite article "a". Some have suggested there is no norm to a 3D line segment by saying there is an infinite number of them. Yet, miss the indefinite article "a" --- which I assume could mean any 1 of infinite.
What happens when someone does not have two vectors to start with?
vector is the unit vector of the line segment or vector.
create a rotation matrix around vector to obtain 1 of infinite norms
It took some time, but using Eigen template library and 10000 random test samples. Here is the code:
#include <Eigen/Core>
#include <Eigen/Geometry>
Eigen::MatrixXd samples = Eigen::MatrixXd::Random(10000, 3); // 3x3 Matrix filled with random numbers between (-1,1)
for (int i = 0; i < 10000; ++i)
{
Eigen::Vector3d vector(samples(i, 0), samples(i, 1), samples(i, 2));
vector.normalize();
Eigen::Vector3d zaxis(0, 0, 1);
Eigen::Vector3d xaxis = zaxis.cross(vector);
xaxis.normalize();
Eigen::Vector3d yaxis = vector.cross(xaxis);
yaxis.normalize();
Eigen::Matrix3d m;
m(0, 0) = xaxis(0);
m(0, 1) = yaxis(0);
m(0, 2) = vector(0);
m(1, 0) = xaxis(1);
m(1, 1) = yaxis(1);
m(1, 2) = vector(1);
m(2, 0) = xaxis(2);
m(2, 1) = yaxis(2);
m(2, 2) = vector(2);
// one of two easy points to use to get 1 of infinite norms --- the other being (1, 0, 0)
Eigen::Vector3d point(0, 1, 0);
point = m * point;
point.normalize();
auto norm = point.cross(vector);
norm.normalize(); // 1 of an infinite number of norms
auto check = norm.dot(vector); // verify with dot product
if (std::abs(check) >= 1e-12)
{
//complain
}
}