Reputation: 249
How would I find out if a point (x,y,z) is on a line between pointA and pointB?
What I would like is a boolean function that would do this:
pointA // random THREE.Vector3
pointB // random THREE.Vector3
pointToCheck // random THREE.Vector3
var isOnLine = THREE.pointOnLine(pointA, pointB, pointToCheck)
if (isOnLine) {
console.log('point is on the line');
}
Here is an image for visualization:
Upvotes: 6
Views: 2398
Reputation: 1
This much more simple way.
function isPointOnLine (pointA, pointB, pointToCheck) {
var c = new THREE.Vector3();
c.crossVectors(pointA.clone().sub(pointToCheck), pointB.clone().sub(pointToCheck));
return !c.length(); }
THREE.isPointOnLineAndBetweenPoints = function (pointA, pointB, pointToCheck) {
if (!isPointOnLine(pointA, pointB, pointToCheck)) {
return false;
}
let d = pointA.distanceTo(pointB);
return pointA.distanceTo(pointToCheck) < d && pointB.distanceTo(pointToCheck) < d;
}
Upvotes: 0
Reputation: 298
Cross product of two vectors can help us to solve this problem.
function isPointOnLine (pointA, pointB, pointToCheck) {
var c = new THREE.Vector3();
c.crossVectors(pointA.clone().sub(pointToCheck), pointB.clone().sub(pointToCheck));
return !c.length();
}
THREE.isPointOnLineAndBetweenPoints = function (pointA, pointB, pointToCheck) {
if (!isPointOnLine(pointA, pointB, pointToCheck)) {
return false;
}
var dx = pointB.x - pointA.x;
var dy = pointB.y - pointA.y;
// if a line is a more horizontal than vertical:
if (Math.abs(dx) >= Math.abs(dy)) {
if (dx > 0) {
return pointA.x <= pointToCheck.x && pointToCheck.x <= pointB.x;
} else {
return pointB.x <= pointToCheck.x && pointToCheck.x <= pointA.x;
}
} else {
if (dy > 0 ) {
return pointA.y <= pointToCheck.y && pointToCheck.y <= pointB.y;
} else {
return pointB.y <= pointToCheck.y && pointToCheck.y <= pointA.y;
}
}
}
a call:
THREE.isPointOnLineAndBetweenPoints(new THREE.Vector3(1, 0, 0), new THREE.Vector3(2, 0, 0), new THREE.Vector3(2, 0, 0));
Use the following function if you wanna to know just whether this point is on a line or not:
isPointOnLine(new THREE.Vector3(1, 0, 0), new THREE.Vector3(2, 0, 0), new THREE.Vector3(2, 0, 0));
Upvotes: 2
Reputation: 21
You can generate the symmetric form of the equation for the three-dimensional line, plug in the points on pointToCheck, and determine if it's on the line. Here's the code:
// Pick two arbitrary points to be on the line
var pointA = new THREE.Vector3( -70, -4, -100 );
var pointB = new THREE.Vector3( 65, 22, 14 );
// Equation that takes in three points, pointA and pointB
// on a three-dimensional line and pointToCheck unknown, and
// returns true if pointToCheck is on the line and false if not
// optional param betweenCheck will additionally check if point
// is between pointA and pointB
var isOnLine = function(pointA, pointB, pointToCheck, betweenCheck) {
xVector = pointB.x - pointA.x;
yVector = pointB.y - pointA.y;
zVector = pointB.z - pointA.z;
vector = [xVector, yVector, zVector];
if (!!betweenCheck) {
// test if point is between pointA and pointB
if (pointToCheck.x < Math.min[pointA.x, pointB.x] ||
pointToCheck.x > Math.max[pointA.x, pointB.x]) {
return false;
}
if (pointToCheck.y < Math.min[pointA.y, pointB.y] ||
pointToCheck.y > Math.max[pointA.y, pointB.y]) {
return false;
}
if (pointToCheck.z < Math.min[pointA.z, pointB.z] ||
pointToCheck.z > Math.max[pointA.z, pointB.z]) {
return false;
}
}
// equation for the vector function generating this line is:
// [pointA.x, pointA.y, pointA.z] + t[vector], or
// [pointA.x + t * xVector, pointA.y + t * yVector,
// pointA.z + t * zVector], or
// parametric form:
// x = pointA.x + (t * xVector)
// y = pointA.y + (t * yVector)
// z = pointA.z + (t * zVector), or
// symmetric form:
// x - pointA.x y - pointA.y z - pointA.z
// ------------ = -------------- = --------------
// xVector yVector zVector
//
// So to test for whether pointToCheck is on line, we plug in
// its coordinates to x, y and z in the symmetric form
// and see if the equations balance
var x = (pointToCheck.x - pointA.x) / xVector;
var y = (pointToCheck.y - pointA.y) / yVector;
var z = (pointToCheck.z - pointA.z) / zVector;
var results = [x, y, z];
// Handle any axis where no change occurred by removing the
// point to check, as it's irrelevent to determining whether
// point to check is on the line.
for (var i = 0; i < 2; i++) {
if (isNaN(results[i])) {
results.splice(i, 1);
}
}
var first = results[0];
// Cycle through remaining results and make sure they are all
// the same
for (var i = 0; i < results.length; i++) {
// If any point is different, return false, as the point to
// check is not on the line
if (results[i] !== first) {
return false
}
}
// All the symmetric equations were equal (or irrelevant) and
// the pointToCheck is on the line
return true;
}
Here's some tests:
// Some quick testing on example lines (you can change the
// coords of pointA and pointB above and they will still pass)
pointsOnLine = [];
pointsOffLine = [];
pointsOnLineBetween = [];
pointsOffLineBetween = [];
var generatePoints = function() {
xVector = pointB.x - pointA.x;
yVector = pointB.y - pointA.y;
zVector = pointB.z - pointA.z;
vector = [xVector, yVector, zVector];
for (var i = 0; i < 100; i++) {
var t = parseInt(Math.random() * 100);
var direction = Math.random() < .5 ? true : false
if (!direction) {
t = -t;
}
var newPointCoords = new THREE.Vector3(
pointA.x + (xVector * t),
pointA.y + (yVector * t),
pointA.z + (zVector * t)
);
pointsOnLine.push(newPointCoords);
var newPointCoords = new THREE.Vector3(
pointA.x + (xVector * t) + parseInt(Math.random() * 100),
pointA.y + (yVector * t) - parseInt(Math.random() * 100),
pointA.z + (zVector * t) + parseInt(Math.random() * 100)
);
pointsOffLine.push(newPointCoords);
var x = ((Math.max(pointA.x, pointB.x) - Math.min(pointA.x, pointB.x)) /
2) + Math.min(pointA.x, pointB.x);
var y = ((Math.max(pointA.y, pointB.y) - Math.min(pointA.y, pointB.y)) /
2) + Math.min(pointA.y, pointB.y)
var z = ((Math.max(pointA.z, pointB.z) - Math.min(pointA.z, pointB.z)) /
2) + Math.min(pointA.z, pointB.z)
var newPointCoords = new THREE.Vector3(x, y, z);
pointsOnLineBetween.push(newPointCoords);
var x = ((Math.max(pointA.x, pointB.x) - Math.min(pointA.x, pointB.x)) /
Math.abs(t)) + Math.min(pointA.x, pointB.x);
var y = ((Math.max(pointA.y, pointB.y) - Math.min(pointA.y, pointB.y)) /
Math.abs(t) * 2) + Math.min(pointA.y, pointB.y)
var z = ((Math.max(pointA.z, pointB.z) - Math.min(pointA.z, pointB.z)) /
Math.abs(t) * 3) + Math.min(pointA.z, pointB.z)
var newPointCoords = new THREE.Vector3(x, y, z);
pointsOffLineBetween.push(newPointCoords);
}
}
generatePoints();
for (var i=0; i < pointsOnLine.length; i++) {
if (!isOnLine(pointA, pointB, pointsOnLine[i])) {
console.log('error', pointsOnLine[i]);
} else {
console.log('test passed -- point on line')
}
}
for (var i=0; i < pointsOffLine.length; i++) {
if (isOnLine(pointA, pointB, pointsOffLine[i])) {
console.log('error', pointsOffLine[i]);
} else {
console.log('test passed -- point off line')
}
}
for (var i=0; i < pointsOnLineBetween.length; i++) {
if (!isOnLine(pointA, pointB, pointsOnLineBetween[i], true)) {
console.log('error', pointsOnLineBetween[i]);
} else {
console.log('test passed -- point on line between')
}
}
for (var i=0; i < pointsOffLineBetween.length; i++) {
if (isOnLine(pointA, pointB, pointsOffLineBetween[i], true)) {
console.log('error', pointsOffLineBetween[i]);
} else {
console.log('test passed -- point off line between')
}
}
Upvotes: -1