I've created a multi-dimensional array based on the x/y coords of the perimeter of a circle. An object can be dragged along the arc (in javascript) and then 'dropped' anywhere on it. The problem is, I need to find the closest x and y coordinate to where the object is 'dropped.'
My current solution involves looping through an array and finding the closest value to x, and then looping again to find the y coordinate, but it doesn't seem very clean and there are problems with it.
Does anyone have any suggestions?
Thanks!
So, let's see. We assume a predefined set of (x, y) coordinates. You are given another point and have to find the nearest element of the array to that given point. I am going to assume "nearest" means the smallest Pythagorean or Euclidean distance from the given point to each of the other points.
The simplest algorithm is probably the best (if you want to look at others in Wikipedia, have at it). Since you didn't give us any code for the structure, I'm going to assume an array of objects, each object having an x and a y property, ditto for the given point.
var findNearestPoint = function (p, points) {
var minDist = Number.POSITIVE_INFINITY,
minPoint = -1,
i,
l,
curDist,
sqr = function(x) { return x * x; };
for (i = 0, l = points.length; i < l; i++) {
curDist = sqr(p.x - points[i].x) + sqr(p.y - points[i].y);
if (curDist < minDist) {
minDist = curDist;
minPoint = i;
}
}
return points[i];
};
(Untested, but you get the idea.)
If your arrays are created in sequential order (that is from smallest to greatest or greatest to smallest), you could use introduce a Binary Search Algorithm.
Get middle element of x array.
If x equals your value, stop and look for y, otherwise.
If x is lower, search in the lower half of the array (starting from step 1).
If x is higher, search in the upper half of the array (starting from step 1).
Then use the same formula on y. You might have to change to algorithm a bit to make it so it works with the closest matching element. Having not seen your array, I can't offer code to solve to problem.
Related
I've been trying to generate a two dimensional array of objects. Each object contains it's own internal position in the array in two variables called X and Y. When I instantiate the object, I can see through console logging that it's being instantiated with the proper X and Y values, this can also be validated through the fact that position in the array corresponds perfectly to those values.
However, when I log the final array after iterating through and saving each position in the array two an instance of the object, they have identical X coordinates, yet the Y coordinates are perfect.
let coordinates = Array(30).fill(Array(40)) // just creates an empty two dimensional array.
class Tile {
constructor(x,y){
this.x = x;
this.y = y;
}
}
for (let x = 0; x < coordinates.length; x++) {
for (let y = 0; y < coordinates[x].length; y++) {
console.log({x,y}) // logs {x: 0, y: 0} -> {x: 29, y:39}
coordinates[x][y] = new Tile(x,y)
}
}
console.log(coordinates) // logs two dimensional array with {x: 29, y:0} -> {x: 29, y:39}
I'm going mentally crazy trying to figure out why it does that. I've tried researching bindings, scope, objects instead of classes and I cannot find a way around it. I believe figuring this out will result in solving several of my problems, as I've run into other properties on the actual Tile class being randomly set despite not touching it at all. I am referring to creating a maze using deep traveling and recursion, and having each tile contain a property called "Visited" and setting it to true once it's been traversed once.
When doing that, I run into that my maze suddenly stops as it decides that every tile around it has been "visited" as they are all equal to true, yet I've never touched them.
Anything that you guys would have that would explain what I am running into would be helpful, it's no doubt something really simple and stupid.
Thank you in advance.
for (let y = 0; x < coordinates[x].length; y++) is your problem.
Your loop definitely cannot work if you are comparing to X for your Y loops, it won't ever get out.
With root-finding algorithms, you're usually just given the x value of the position of a root. I want to get the two closest points on either side of the root where these two points would have opposite signs considering that's where the roots exist (where the y value goes from + to - or the other way around)
So given an x value that is the approximate result of a root within an interval, what's the best efficient method to find the nearest two points to that root that have opposite y values.
Currently, my approach is to keep widening the offset from the roots position on either side until the y values of these two points are opposite.
Also, maybe using the precision (like 1e-6) that was used to find the root could be helpful to determine how much of an offset is needed to get passed the actual root where the signs change!
This image is sort of what I want. Blue are the two points I want that are at either side of the approximate root (which is purple). Of course the closer they are the better (without using further more iterations to get a more precise root, but instead only use the root given - we can assume that it's close enough).
I know some algorithms like bisection give the last closest brackets that could be used as these points unless the 1st iteration found the root exactly at the midpoint and the brackets are still far apart. While I'm using ridders (regula falsi) method which has a bias so one bracket usually doesn't move.
Code
let x = 3.135, y = fn(x); /* x = approximate result of root, actual root is pi */
let xmin = 3.1, xmax = 3.2;
let offset = (xmax - xmin) * .0000000002;
function getOffsetPoints(x, y, offset, fn) {
/* if root exactly 0 */
/* offset either side by 1e-15 = .000000000000001! */
if (y === 0) {
return [
[x - 1e-15, fn(x - 1e-15)],
[x + 1e-15, fn(x + 1e-15)]
]
}
let dxLeft = x - offset,
dyLeft = fn(dxLeft),
dxRight = x + offset,
dyRight = fn(dxRight);
/* maybe 3 attempts is enough - don't want to over do it with computations */
let i = 0;
while (i <= 3 && Math.sign(dyLeft) * Math.sign(dyRight) !== -1) {
offset *= 100;
dxLeft = x - offset;
dyLeft = fn(dxLeft);
dxRight = x + offset;
dyRight = fn(dxRight)
i++;
}
/* return two points at either side of root */
return [
[dxLeft, dyLeft],
[dxRight, dyRight]
]
}
function fn(x) {
return Math.tan(x);
}
EDIT: Forgot to mention that it's assumed the approximate root was already found within the interval xmin and xmax, and it does exist somewhere between that interval.
So the maximum interval will be the distance from xmin to xmax.
I guess this question is subtle as there is a trade-off between closeness (precision) and iterations (performance), and overall I'm looking for something more optimal than what I have
I presume that you refer to the floating-point representation of the numbers (because for a continuous function, the "nearest" points do not exist).
Beware that very close to a root the function evaluation loses any reliability and might not even be monotonous and there could be several nearby changes of signs, making the "root" not unique. None of the usual methods, except dichotomy, are even guaranteed to land close to a change of sign !
Anyway, if you want the nearest point of a different sign (chances of an exact zero are pretty low), you can explore on either sides by incrementing/decrementing the lower-order bits of the floating-point mantissa and evaluate the function. The best is to map an integer on the FP representation.
Values that cause a change in the exponent will need special handling (though for first experiments you can probably ignore them).
Suppose if you are given a bunch of points in (x,y) values and you need to generate points by linearly interpolate between the 2 nearest values in the x axis, what is the fastest implementation to do so?
I searched around but I was unable to find a satisfactory answer, I feel its because I wasnt searching for the right words.
For example, if I was given (0,0) (0.5 , 1) (1, 0.5), then I want to get a value at 0.7; it would be (0.7-0.5)/(1-0.5) * (0.5-1) + 1; but what data structure would allow me to find the 2 nearest key values to interpolate in between? Is a simple linear search/ binary search if I have many key values the best I could do?
The way I usually implement O(1) interpolation is by means of an additional data structure, which I call IntervalSelector that in time O(1) will give the two surrounding values of the sequence that have to be interpolated.
An IntervalSelector is a class that, when given a sequence of n abscissas builds and remembers a table that will map any given value of x to the index i such that sequence[i] <= x < sequence[i+1] in time O(1).
Note: In what follows arrays are 1 based.
The algorithm that builds the table proceeds as follow:
Find delta to be the minimum distance between two consecutive elements in the input sequence of abscissas.
Set count := (b-a)/delta + 1, where a and b are respectively the first and last of the (ascending) sequence and / stands for the integer quotient of the division.
Define table to be an Array of count elements.
For i between 1 and n set table[(sequence[j]-a)/delta + 1] := j.
Repeat every entry of table visited in 4 to the unvisited positions that come right after it.
On output, table maps j to i if (j-1)*d <= sequence[i] - a < j*d.
Here is an example:
Since elements 3rd and 4th are the closest ones, we divide the interval in subintervals of this smallest length. Now, we remember in the table the positions of the left end of each of these deta-intervals. Later on, when an input x is given, we compute the delta-interval of such x as (x-a)/delta + 1 and use the table to deduce the corresponding interval in the sequence. If x falls to the left of the ith sequence element, we choose the (i-1)th.
More precisely:
Given any input x between a and b calculate j := (x-a)/delta + 1 and i := table[j]. If x < sequence[i] put i := i - 1. Then, the index i satisfies sequence[i] <= x < sequence[i+1]; otherwise the distance between these two consecutive elements would be smaller than delta, which is not.
Remark: Be aware that if the minimum distance delta between consecutive elements in sequence is too small the table will have too many entries. The simple description I've presented here ignores these pathological cases, which require additional work.
Yes, a simple binary search should do well and will typically suffice.
If you need to get better, you might try interpolation search (has nothing to do with your value interpolation).
If your points are distributed at fixed intervals (like in your example, 0 0.5 1), you can also simply store the values in an array and access them in constant time via their index.
Background
I have a pet project that I love to overthink from time to time. The project has to do with an RC aircraft control input device. People familiar with that hobby are probably also familiar with what is known as "stick expo", which is a common feature of RC transmitters where the control sticks are either more or less sensitive near the neutral center position and become less or more sensitive as the stick moves closer to its minimum or maximum values.
I've read some papers that I don't fully understand. I clearly don't have the math background to solve this, so I'm hoping that perhaps one of you might.
Problem
I have decided to approximate the curve by taking a pre-determined number of samples and use linear interpolation to determine output values for any input values between the sample points. I'm trying to find a way to determine the most optimal set of sample points.
If you look at this example of a typical growth curve for this application, you will notice that some sections are more linear (straighter), and some are less linear (more curvy).
These samples are equally distant from each other, but they don't have to be. It would be smart to increase the sample density where there is more change and thereby increasing the resolution in the curvy segments by borrowing redundant points from the straight segments.
Is it possible to quantify the degree of error? If it is, then is it also possible to determine the optimal set of samples for a given function and a pre-determined number of samples?
Reference Code
Snippet from the class that uses a pre-calculated set of points to approximate an output value.
/* This makes the following assumptions:
* 1. The _points[] data member contians at least 2 defined Points.
* 2. All defined Points have x and y values between MIN_VALUE and MAX_VALUE.
* 3. The Points in the array are ordered by ascending values of x.
*/
int InterpolatedCurve::value( int x ) {
if( _points[0].x >= x ) { return _points[0].y; }
for( unsigned int i = 1; i < _point_count; i++ ) {
if( _points[i].x >= x ) {
return map(x, _points[i-1].x, _points[i].x,
_points[i-1].y, _points[i].y);
}
}
// This is an error condition that is not otherwise reported.
// It won't happen as long as the points are set up correctly.
return x;
}
// Example map function (borrowed from Arduino site)
long map( long x, long x1, long x2, long y1, long y2 ) {
return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}
Although my project is actually in C++, I'm using a Google spreadsheet to produce some numbers while I ponder this problem.
// x: Input value between -1 and 1
// s: Scaling factor for curve between 0 (linear) and 1 (maximum curve)
// c: Tunable constant
function expo_fn( x, s, c ) {
s = typeof s !== 'undefined' ? s : 1.0;
c = typeof c !== 'undefined' ? c : 4.0;
var k = c * ((c - 1.0) * s*s*s + s)/c + 1.0;
return ((k - 1.0) * x*x*x*x*x + x)/k;
};
The following creates a set of isometrically distributed (non-optimal) points between input values -1 and 1. These output values were expanded to integers between -16383 and 16383 for the above example spreadsheet. Factor is a value between 0 and 1 that determines the "curviness"--zero being a flat, linear curve and 1 being the least-linear curve I care to generate.
function Point( x, y ) {
this.x = x;
this.y = y;
};
function compute_points_iso( count, factor ) {
var points = [];
for( var i = 0; i < count; ++i ) {
var x = 2.0/(count - 1.0) * i - 1.0;
var y = expo_fn(x, factor);
points.push(new Point(x,y));
}
return points;
};
Relevant Academic Work
I have been studying this paper describing an algorithm for selecting significant data points, but my program doesn't quite work right yet. I will report back if I ever get this thing working.
The key here is to realize that you can bound the error on your linear interpolation in terms of the second derivative of the function. I.e. if we approximate f(x) \approx f(x_0) + f'(x_0)*(x-x_0), then the error in this approximation is less than abs[ 0.5*f''(x_0)(x-x_0)^2 ].
The outline of an iterative approach could look like this:
Construct an initial, e.g. uniformly spaced, grid
Compute the second derivative of the function on this grid.
Compute the bound on the error using the second-derivative and the inter-sample spacing
Move the samples closer together where the error is large; move them further apart where the error is small.
I'd expect this to be an iterative solution that loops on steps 2,3,4.
Most of the details are in step 4.
For a fixed number of sample points one could use the median of the error bounds to select
where finer/coarser sampling is required (i.e. those locations where the error is larger than the median error will have the sample points pulled closer together).
Let E_0 be this median of the error bounds; then we can, for each sample in the point, compute a new desired sample spacing (dx')^2=2*E_0/f''(x); then you'd need some logic to go through and change the grid spacing so that it is closer to these ideal spacings.
My answer is influenced by having used the "Self-Organizing Map" algorithm on data; this or related algorithms may be relevant for your problem. However, I can't recall ever
seeing a problem like yours where the goal is to make your estimates of the error uniform across the grid.
I have one point (hereafter referred to as the original point) on a grid, say for example, [3, 3].
I also have a set of points that are in the same horizontal and vertical lines as the original point, say, [[3,1],[3,2],[3,4],[7,3],[8,3]].
I want some function that will return an array of at most four points: the points closest to the original point in each direction (i.e. left, right, above, below). With the example above, it would return,
[[3,2],[3,4],[7,3]]
because [3,2] is the closest point on the left, [3,4] is the closest point on the right, [7,3] is the closest point above, and there are no points below. (Order of direction is not important.)
Is there an elegant and reasonably concise way to do this, using Javascript/JQuery?
I don't know JavaScript, but the following algorithm would be very simple, if you can formulate it with JavaScript.
Let (X0, Y0) be the original point.
Iterate through the array, [(X1, Y1), ..., (XN, YN)], and keep account of the minimum values of
R = Xi - X0 > 0
and
L = X0 - Xi > 0
as you proceed.
At the end of the iteration these values give you the closest points, i.e., X0 + R
and X0 - L.
Do a similar iteration on the vertical line of points.