Reputation: 31559
I have a one dimensional gird. its spacing is a floating point. I have a point with floating point coordinate as well. I need to find its distance to the closest grid point.
For example:
0.12
|
*
|---------|---------|---------|---------|---------|
0 0.1 0.2 0.3 0.4 0.5
The result would be -0.02
since the closest point is behind it.
However if it was
-0.66
|
*
|---------|---------|---------|---------|---------|
-1 -0.8 -0.6 -0.4 -0.2 0
The result will be 0.06
. As you can see its in floating point and can be negative.
I tried the following:
float spacing = ...;
float point = ...;
while(point >= spacing) point -= spacing;
while(point < 0) point += spacing;
if(std::abs(point - spacing) < point) point -= spacing;
It works, but I'm sure there is a way without loops
Upvotes: 6
Views: 2029
Reputation: 38118
Much, much more generally, for arbitrary spacing, dimensions, and measures of distance (metric), the structure you're looking for would be a Voronoi Diagram.
Upvotes: 0
Reputation: 6579
Let us first compute the nearest points on the left and right as follows:
leftBorder = spacing * floor(point/spacing);
rightBorder = leftBorder + spacing;
Then the distance is straightforward:
if ((point - leftBorder) < (rightBorder - point))
distance = leftBorder - point;
else
distance = rightBorder - point;
Note that, we could find the nearest points alternatively by ceiling:
rightBorder = spacing * ceil(point/spacing);
leftBorder = rightBorder - spacing;
Upvotes: 7
Reputation: 7989
Here is my first blush attempt, note that this is not tested at all.
float remainder = fmod(point, spacing); // This is the fractional difference of the spaces
int num_spaces = point/spacing; // This is the number of "spaces" down you are, rounded down
// If our fractional part is greater than half of the space length, increase the number of spaces.
// Not sure what you want to do when the point is equidistant to both grid points
if(remainder > .5 * spacing)
{
++num_spaces;
}
float closest_value = num_spaces*spacing;
float distance = closest_value - point;
Upvotes: 2
Reputation: 4428
You should just round the number using this:
float spacing = ...;
float point = ...;
(point > 0.0) ? floor(point + spacing/2) : ceil(point - spacing/2);
Upvotes: 0
Reputation: 66912
std::vector<float> spacing = ...;
float point = ...;
float result;
Since you say the spacing isn't (linear), I would cache the sums:
std::vector<float> sums(1, 0.0);
float sum=0;
for(int i=0; i<spacing.size(); ++i)
sums.push_back(sum+=spacing[i]);
//This only needs doing once.
//sums needs to be in increasing order.
Then do a binary search to find the point to the left:
std::vector<float>::iterator iter;
iter = std::lower_bound(sums.begin(), sums.end(), point);
Then find the result from there:
if (iter+1 == sums.end())
return point-*iter;
else {
float midpoint = (*iter + *(iter+1))/2;
if (point < midpoint)
result = point - *iter;
else
result = *(iter+1) - point;
}
[EDIT] Don't I feel silly. You said the spacing wasn't constant. I interpreted that as not-linear. But then your sample code is linear, just not a compile-time constant. My bad. I'll leave this answer as a more general solution, though your (linear) question is solvable much faster.
Upvotes: 2