How can I find a line through 3D points? - javascript

This is easier explained with pictures. I have these green points:
And I want to get a few points along this red line:
This is a top view, but I have complete XYZ coordinates for each point. I also have which vertex is connected to which other vertex.
It almost seems like you could just take the midpoint of each of those green edges and draw a line through them but you can see how that wouldn't really work near the end.
Is there an algorithm I can use to find a line of best fit through these 3D points?
I'm using Three.js if that makes a difference.

This task is equal to noise suppression.
the simplest algorithm (end of array will not be filtered):
double array[];
int count, depth;
// 1 < depth < count
for (int i = 0; i < count - depth; i++)
{
double sum = 0;
for (int j = 0; j < depth; j++)
{
sum += array[i + j];
}
array[i] = sum / depth;
}
You can find more info googling Median Filter and Noise Suppression

Related

How can I plot 4 vertexes using a nested loop?

I'm trying to make a visualizer and I have to draw 4 vertexes while using math to make each vertex so they can react with the music. Rather than just typing all 4 of them out and plotting them I would like to use a nested for loop to do this. I was testing using a regular ellipse with the translate function in p5.js and the translate seems to be translating itself and not just changing the values to how I would want it.
for (var i = 1; i <= 2; i++)
{
for (var j = 1; j <= 2; j++)
{
translate(200 * i,200 * j);
ellipse(0,0,100)
}
}
translate does not set a translation, but concatenates the current transformation matrix with the new translation. Therefore you need to push the transformation matrix before appending the new translation and pop the matrix after drawing the geometry:
for (var i = 1; i <= 2; i++) {
for (var j = 1; j <= 2; j++) {
push()
translate(200 * i, 200 * j)
ellipse(0, 0, 100)
pop()
}
}

How to generate a line with exact number of points?

I have to generate a path from a dataset of n points.
I am plotting a cubic spline through the points in this dataset.
The generated path must contain an exact number of projected path-points.
My problem is not with the plotting of the curve but rather with the distribution of the path-points along the x-axis to yield a path that is made up of an exact number of path-points. This is why I have reduced the following example to a one dimensional array of points through which a straight line should be plotted. Each point in the dataset should represent the beginning of a curve segment (even though the curve is really a line because of the simplification).
My current naive approach is not exact ie it does not yield a path that contains the specified number of points (it's off by 4-5 points depending on the density of the dataset and the specified targetLength).
I think I'll have to use linear interpolation to get an exact result but I don't know how. Can anyone help or point me in the right direction?
Naive approach (javascript):
// Array with floating point values constrained between 0 - 1
// Think of each value as the beginning of a line segment.
const dataset = [0, 0.123, 0.3432, 0.454, 0.56, 0.8334, 0.987, 1];
// Path should have this many points
const targetLength = 1024;
// Step distance between points
const delta = 1 / targetLength;
// The path array we're generating
const path = [];
// For each point (segment)
for (let i = 0; i < dataset.length - 1; i++) {
const x1 = dataset[i]; // current point
const x2 = dataset[i + 1]; // next point
const xd = x2 - x1 - delta; // dist between current and next point(-delta)
// For each step in the segment generate a path-point
for (let k = 0; k <= xd; k += delta) {
// For this example we're only pushing the x-value onto the array.
// In the real implementation I'm calculating a y-value to plot a curve
// and push an array of [x, y] onto the dataset.
path.push(dataset[i] + k);
}
}
// expect: path.length === targetLength
console.log(path.length);
In the above example I expect path.length to equal targetLength (1024).
I could take the generated path as a whole and interpolate the entire array but I think I'm looking for a smarter way to generate the path in the first place. Any help is greatly appreciated!
It really looks like what you want is just this:
for (let i=0; i<targetLength; ++i) {
path.push(i / (targetLength-1));
}
... because this is what you are approximating, and it actually makes sense for some kinds of cubic spline interpolation. You wouldn't normally need to store these path points, however, because they are so easy to calculate.

Fixing normals in custom threejs capsule geometry

In an effort to learn a little bit more about custom geometry in three.js, I tried adapting Paul Bourke's capsule geometry example.
With my custom capsule geometry, I am currently having two issues:
The middle face normals are not oriented properly.
There is a hard seam along the side. (EDIT: fixed by deliberately computing the face normals. updated code in the gist)
And maybe one bonus question that has been lingering on my mind:
What might a general strategy be to add vertex loops in that middle segment?
I'm really happy with the geometry in general, but would anyone be able to give me some direction on how to address these issues? I feel like the normal issue in the middle segment must be the orientation of the faces, and here is the related face construction snippet:
for(let i = 0; i <= N/2; i++){
for(let j = 0; j < N; j++){
let vec = new THREE.Vector4(
i * ( N + 1 ) + j ,
i * ( N + 1 ) + ( j + 1 ) ,
( i + 1 ) * ( N + 1 ) + ( j + 1 ) ,
( i + 1 ) * ( N + 1 ) + j
);
let face_1 = new THREE.Face3(vec.x,vec.y,vec.z);
let face_2 = new THREE.Face3(vec.x,vec.z,vec.w);
geometry.faces.push(face_1);
geometry.faces.push(face_2);
}
}
CapsuleGeometry.js
The shading/normal seam is there because you have probably explicitly defined a hard edge there.
When you run your loops to generate the vertices, you probably duplicate the starting position. If you start at 0, and go all the way to 2PI, 0==2PI. When you weave the triangles, you probably tell the lest one to use the 2PI instead of 0 and even though they are in the same position, as far as triangles are concerned, they point to different vertices, and are thus not connected.
for(let i = 0; i <= N/4; i++){ //change to i < N
for(let j = 0; j <= N; j++){
If you tell the last triangle in the loop to point to the beginning vertex you will make a continous surface that geometry.computeVertexNormals() can smooth out.
You can also just compute these normals directly. All the normals can be obtained in these case from the vertex positions of the original sphere before expanding it.

JavaScript Math.sqrt performance

Through code profiling, I have found the Math.sqrt function specifically to be a major bottleneck in a large doubly-nested loop that runs every timestep in my program. Is there any way to improve its performance? Should I inline some kind of iterative calculation, or lookup table-based calculation?
Any help would be greatly appreciated!
I cannot replace it with a squares calculation instead, since it is not a comparison.
EDIT: The relevant portion of the code looks roughly as follows
var width = 2000;
var height = 2000;
function update() {
for (var j = 0; j < height; ++j) {
for (var i = 0; i < width; ++i) {
array[i][j] = Math.sqrt(/* some expression involving i and j */);
}
}
}
var fps = 60;
setInterval(update, 1000 / fps);
As your iterating in a 2-dimensional array you can reduce the iterations by ~2.
For instance :
if your expression is i x j, and your array is 3-3 size starting from 0 your going to compute in your loop :
0*1 AND 1*0
0*2 AND 2*0
1*2 AND 2*1
which is the same
0x0 1x0 2x0
0x1 1x1 2x1
0x2 1x2 2x2

Circle Collision Detection HTML5 Canvas

I want to check if circles are colliding with each other.
I know I can do this by getting a distance between the two centers of the circles and subtracting the radius of each circle from that distance and seeing if 'distance' is > 1.
How can I do this efficiently though with say, 1000 circles? Maybe I can somehow get the nearest 20 circles or something like that and check these? I don't know how I would begin to go about that efficiently though either..
Any ideas?
Here is an example:
http://experiments.lionel.me/blocs/
Before you start calculating exact differences in distances, you can at least compare the x/y positions of the centers v.s. the radii. That information is implicitly available in the circle and requires just some simple comparisons and addition/subtraction.
That'll let you compare the simple distances in x/y between all the circle pairs, and throw away any that are obviously not collision candidates, e.g.
abs(x2 - x1) > (r2 + r1)
abs(y2 - y1) > (r2 + r1)
... if the distance in X or Y between the circle centers is greater than the sum of the radii, then they cannot be colliding.
Once you've whittled down the possible colliders, THEN you do the formal exact cartesian distance, which is where the 'heavy' multiplication/division stuff comes in.
Consider storing the coordinates of the circles' centers in a quad tree, then you would only need to check whether the circle intersects with other circles in that quadrant or adjacent quadrants.
The one caveat is that you need to sure the quad tree's leaf nodes have a minimal diameter of the radius of your largest circle, otherwise you will have to check more than just adjacent nodes for intersection.
http://en.wikipedia.org/wiki/Quadtree
If your circles are well scattered, then a simple optimization you can do is to store your circles sorted on the x or y axis, then you only need to check with circles who's x or y coordinate is within the radius of the circle.
The efficiency is going to be concerned with the speed of the algorithms you are using, for instance the speed of the square root algorithm that you calculate the distance with, and your data structures will determine the efficiency of memory, in addition to algorithms. Another way to speed up the calculations would be to reduce the precision of the distance calculations.
The best method to detect if the circles are colliding is, as you said, to store the circles' center coordinates and radius in variables and compute whether or not the distance between the centers is equivalent to 0 when the radii are subtracted.
I highly recommend Keith Peter's AdvancED ActionScript 3.0 Animation book, where you can find the concrete implementation of Quadtree algorithm in Actionscript.
Here are the basic steps:
First create a two dimensional grid and scatter all the balls randomly across the field.
private function createGrids():void {
_grids = new Array();
for (var i:int = 0; i< stage.stageWidth / GRID_SIZE; i++) {
_grids[i] = new Array();
for (var j:int = 0; j< stage.stageHeight / GRID_SIZE; j++) {
_grids[i][j] = new Array();
}
}
}
Assign balls to grid cells
private function assignBallsToGrid():void {
for (var i:int = 0; i< numBalls; i++) {
var ball:Ball = Ball(_balls[i]);
var xpos:int = Math.floor(ball.x / GRID_SIZE);
var ypos:int = Math.floor(ball.y / GRID_SIZE);
_grids[xpos][ypos].push(ball);
}
}
Check if two balls are colliding in a single cell, then check the balls in adjacent cells. As Charles Ma mentioned the only consideration here the grid cells dimension must be greater or equal to the largest ball diameter.
private function checkOneCell(x1:Number, y1:Number):void {
var _cell:Array = _grids[x1][y1] as Array;
for (var i:int = 0; i< _cell.length-1; i++) {
var ballA:Ball = _cell[i] as Ball;
for (var j:int = i+1; j< _cell.length; j++) {
var ballB:Ball = _cell[j] as Ball;
checkCollision(ballA, ballB);
}
}
}
private function checkTwoCell(x1:Number, y1:Number, x2:Number, y2:Number):void {
if (x2 < 0) { return }
if (x2 >= _grids.length) { return }
if (y2 >= _grids[x2].length) { return }
var _cell0:Array = _grids[x1][y1] as Array;
var _cell1:Array = _grids[x2][y2] as Array;
for (var i:int = 0; i< _cell0.length; i++) {
var ballA:Ball = _cell0[i] as Ball;
for (var j:int = 0; j< _cell1.length; j++) {
var ballB:Ball = _cell1[j] as Ball;
checkCollision(ballA, ballB);
}
}
}
private function checkCollision(ballA:Ball, ballB:Ball):void {
var dx:Number = ballB.x - ballA.x;
var dy:Number = ballB.y - ballA.y;
var dist:Number = Math.sqrt(dx*dx + dy*dy);
if (dist < ballB.radius + ballA.radius) {
// do something
}
}
Here is how it looks like the main method:
private function checkBallsCollision():void {
for (var i:int = 0; i< _grids.length; i++) {
for (var j:int = 0; j< _grids[i].length; j++) {
checkOneCell(i, j);
checkTwoCell(i, j, i+1, j);
checkTwoCell(i, j, i, j+1);
checkTwoCell(i, j, i-1, j);
checkTwoCell(i, j, i+1, j+1);
}
}
}
NOTE:
The code is written in Actionscript but can be implemented quite easily in Javascript.

Categories