To establish the path between two points, use the points p
and q
, where v = p - q
. Any point M
on the path must meet the vector equation:
M = (1 - lambda) * p + lambda * q
for any lambda
in the range 0 to 1
. To generate a random point on the path, generate a random lambda
and apply it in the equation above:
// Define p and q as instances of THREE.Vector3
function pointOnPath(p, q) {
var lambda = Math.random();
var scaledp = (new THREE.Vector3()).copy(p).multiplyScalar(1 - lambda);
var scaleq = (new THREE.Vector3()).copy(q).multiplyScalar(lambda);
var result = (new THREE.Vector3()).addVectors(scaledp, scaleq);
return result;
}
Next, adjust the coordinates with a small radius to encircle the path. This is done by adding a small vector offset. How do we calculate this vector?
The sought-after vector lies on a plane perpendicular to the line connecting p
and q
. There are infinite vectors meeting this condition, two examples being e1 = (v.y, -v.x, 0)
and e2 = (v.z, 0, -v.x)
. Any vector of the form lambda * e1 + mu * e2
will be perpendicular to v
. Therefore, generating random lambda
and mu
is all that's needed.
NOTE: lambda
and mu
must fall within the range of [-1; 1], rather than [0; 1]. Since the offset vector will be normalized, the interval [-0.5; 0.5] will suffice as normalization will map it to [-1; 1].
function getVectorOffset(p, q, radius) {
var v = (new THREE.Vector3()).subVectors(q, p);
v.normalize();
var e1 = new THREE.Vector3(v.y, -v.x, 0),
e2 = new THREE.Vector3(v.z, 0, -v.x);
e1.normalize();
e2.normalize();
var lambda = Math.random() - 0.5,
mu = Math.random() - 0.5;
var offset = e1.multiplyScalar(lambda).add(e2.multiplyScalar(mu));
offset.normalize();
offset.multiplyScalar(radius) // multiply the computed offset by the desired radius for circling
return offset;
}
Finally, to derive your desired point:
function pointOnHotDog(p, q, radius) {
return pointOnPath(p, q).add(getVectorOffset(p, q, radius));
}
Take a look at the working jsfiddle