I have a square lattice, of size LxL . In this lattice, I can have the classical 4-neighbours grid or an 8-neighbour lattice (including also the diagonals).
Given the coordinates of two points on the lattice (i1,j1) and (i2,j2), I want to compute the distance between them in the 4-neighbour grid and the 8-neighbour grid, considering also periodic boundary conditions.
For the 4-neighbour case, without periodic boundary conditions, the distance is the Manhattan distance d=|i1-i2|+|j1-j2|.
If I want to take in account the periodic boundaries, I could compute the distance several times (changing, for example, (i2,j2) by (i2,j2-L)) and take the minimum, but I am sure that there is a more efficient way to do this.
About the 8-neighbour case, I found this question: Calculate distance on a grid between 2 points (in my case, I would replace sqrt(2) by 1) but it does not solve the problem with boundary conditions.
Any pseudocode on how to compute these distances? The faster, the better.
Find cyclic coordinate difference:
dx = Abs(x1 - x2)
if dx > L/2
dx = L - dx
similar for dy
and distance in this case is known as Manhattan distance
dist = dx + dy
If diagonal move costs 1, then for 8-neighbour case solution is simple - to reach new position, one must perform maximum from dx and dy steps, but don't need more steps because moving along shorter direction is combined with moving along longer direction- diagonal moves.
dist = Max(dx, dy)
(also note that diagonal part is Min(dx, dy) and hor/vert part is Abs(dx - dy). Sum of these expressions is equal to maximum from dx, dy)
Related
I have a situation in my game. I am experimenting with terrain generation.
I have a bunch of peaks, whose position and elevation i know.
I have a point which is surrounded by all these peaks. I know its position. I am trying to calculate the elevation of this point.
I would like to calculate the height of this point, based on how close/far it is to each of these peaks, and the elevation of each of these peaks.
Example:
Peak 1 is at (0,0), with an elevation of 500
Peak 2 is at (100,100), with an elevation of 1000
Peak 3 is at (0,100), with an elevation of 750
If my point is at (99,99), i want the elevation of this point to be as close to 1000.
What is the name of this problem?
If you already have a solution to this, that too will be much appreciated.
Note: In addition, it will be helpful if the formula/equation also allows me to generate negative elevations. for example, a point midway between all the peaks could as well be under sea level. Any formula i can menatally think of usually gives me just positive results. I assume some kind of 'Slope' must be considered to allow this.
One equation i though of so far is
P1.height * (Sum of all distances - distance from P1)/(Sum of all distances) +
P2.height * (Sum of all distances - distance from P2)/(Sum of all distances) +
... Pn.height * (Sum of all distances - distance from Pn)/(Sum of all distances)
Thank you.
To draw the peaks your game needs to convert the coordinates of the peaks to screen coordinates.
Such calculation is usually done by multiplying a matrix with the vector containing the coordinates (in java AWT such matrix would be called a transform).
What you need is the inverse of that matrix so that you can apply it to your screen coordinates.
So the solution is:
get the matrix that is used for rendering the terrain
calculate the inverse matrix
apply it to your screen coordinates
And it might even be more efficient not to use the original matrix to calculate the inverse matrix but use the parameters (zero point, scale factors and rotation angle) which were used to calculate the original matrix. The same parameters can be used to calculate the inverse matrix.
If I have X amount of things (lets just randomly say 300)
Is there an algorithm that will arrange these things somewhat evenly around a central point? Like a 100 sided dice or a 3d mesh of a sphere?
Id rather have the things somewhat evenly spaced like this..
Rather than this polar way..
ps. For those interested, wondering why do I want to do this?
Well I'm doing these for fun, and after completing #7 I decided I'd like to represent the array of wires in 3d in Unity and watch them operate in a slowed down manner.
Here is a simple transformation that maps a uniform sample in the rectangle [0, 2 pi] x [-1, 1] onto a uniform sample on the sphere of radius r:
T(phi, z) = (r cos(phi) sqrt(1 - z^2), r sin(phi) sqrt(1 - zˆ2), r z)
The reason why this transformation produces uniform samples on the sphere is that the area of any region T(U) obtained by transforming the region U from the rectangle does not depend on U but on the area of U.
To prove this mathematically it is enough to verify that the norm of the vectorial product
| ∂T/∂phi x ∂T/∂z |
is constant (the area on the sphere is the integral of this vectorial product w.r.t. phi and z).
Summarizing
To produce a random sample uniformly distributed in the Sphere of radius r do the following:
Produce a random sample (phi_1, ..., phi_n) uniformly distributed in [0, 2 pi].
Produce a random sample (z_1, ..., z_n) uniformly distributed in [-1, 1].
For every pair (phi_j, z_k) calculate T(phi_j, z_k) using the formula above.
Here's a three-step approach. 1a) Make more points than you need. 1b) Remove some. 2) Adjust the rest.
1a) To make more points that you need, take any quasiregular polyhedron with sides that tessellate (triangles, squares, diamonds). Tesselate the spherical faces by subdivision, generating more vertices. For example, if you use the regular icosahedron you get geodesic domes. (Subdivide by 2, you get the dual to the C60 buckyball.) Working out exact formulas isn't hard. The number of new vertices per face is quadratic in the subdivision.
1b) Randomly remove enough points to get you down to your target number.
2) Use a force-directed layout algorithm to redistribute the vertices over the sphere. The underlying force graph is just that provided by the nearest neighbors in your underlying tesselation.
There are other ways to do step 1), such as just generating random points in any distribution. There is an advantage of starting with a quasiregular figure, though. Force-directed algorithms have a reputation for poor convergence in some cases. By starting with something that's already mostly optimal, you'll bypass most all of any convergence problems you might have.
One elegant solution I came across recently is a spherical fibonacci lattice (http://extremelearning.com.au/how-to-evenly-distribute-points-on-a-sphere-more-effectively-than-the-canonical-fibonacci-lattice/)
The nice thing about it is that you can specify the exact number of points you want
// C# Code example
Vector3[] SphericalFibonacciLattice(int n) {
Vector3[] res = new Vector3[n];
float goldenRatio = (1.0f + MathF.Sqrt(5.0f)) * 0.5f;
for(int i = 0; i < n; i++)
{
float theta = 2.0f * MathF.PI * i / goldenRatio;
float phi = MathF.Acos(1.0f - 2.0f * (i + 0.5f) / n);
Vector3 p = new Vector3(MathF.Cos(theta) * MathF.Sin(phi),
MathF.Sin(theta) * MathF.Sin(phi),
MathF.Cos(phi));
res[i] = p;
}
return res;
}
The linked article extends on this to create an even more uniform distribution, but even this basic version creates very nice results.
I have a set of lng/lat coordinates. What would be an efficient method of calculating the greatest distance between any two points in the set (the "maximum diameter" if you will)?
A naive way is to use Haversine formula to calculate the distance between each 2 points and get the maximum, but this doesn't scale well obviously.
Edit: the points are located on a sufficiently small area, measuring the area in which a person carrying a mobile device was active in the course of a single day.
Theorem #1: The ordering of any two great circle distances along the surface of the earth is the same as the ordering as the straight line distance between the points where you tunnel through the earth.
Hence turn your lat-long into x,y,z based either on a spherical earth of arbitrary radius or an ellipsoid of given shape parameters. That's a couple of sines/cosines per point (not per pair of points).
Now you have a standard 3-d problem that doesn't rely on computing Haversine distances. The distance between points is just Euclidean (Pythagoras in 3d). Needs a square-root and some squares, and you can leave out the square root if you only care about comparisons.
There may be fancy spatial tree data structures to help with this. Or algorithms such as http://www.tcs.fudan.edu.cn/rudolf/Courses/Algorithms/Alg_ss_07w/Webprojects/Qinbo_diameter/2d_alg.htm (click 'Next' for 3d methods). Or C++ code here: http://valis.cs.uiuc.edu/~sariel/papers/00/diameter/diam_prog.html
Once you've found your maximum distance pair, you can use the Haversine formula to get the distance along the surface for that pair.
I think that the following could be a useful approximation, which scales linearly instead of quadratically with the number of points, and is quite easy to implement:
calculate the center of mass M of the points
find the point P0 that has the maximum distance to M
find the point P1 that has the maximum distance to P0
approximate the maximum diameter with the distance between P0 and P1
This can be generalized by repeating step 3 N times,
and taking the distance between PN-1 and PN
Step 1 can be carried out efficiently approximating M as the average of longitudes and latitudes, which is OK when distances are "small" and the poles are sufficiently far away. The other steps could be carried out using the exact distance formula, but they are much faster if the points' coordinates can be approximated as lying on a plane. Once the "distant pair" (hopefully the pair with the maximum distance) has been found, its distance can be re-calculated with the exact formula.
An example of approximation could be the following: if φ(M) and λ(M) are latitude and longitude of the center of mass calculated as Σφ(P)/n and Σλ(P)/n,
x(P) = (λ(P) - λ(M) + C) cos(φ(P))
y(P) = φ(P) - φ(M) [ this is only for clarity, it can also simply be y(P) = φ(P) ]
where C is usually 0, but can be ± 360° if the set of points crosses the λ=±180° line. To find the maximum distance you simply have to find
max((x(PN) - x(PN-1))2 + (y(PN) - y(PN-1))2)
(you don't need the square root because it is monotonic)
The same coordinate transformation could be used to repeat step 1 (in the new coordinate system) in order to have a better starting point. I suspect that if some conditions are met, the above steps (without repeating step 3) always lead to the "true distant pair" (my terminology). If I only knew which conditions...
EDIT:
I hate building on others' solutions, but someone will have to.
Still keeping the above 4 steps, with the optional (but probably beneficial, depending on the typical distribution of points) repetition of step 3,
and following the solution of Spacedman,
doing calculations in 3D overcomes the limitations of closeness and distance from poles:
x(P) = sin(φ(P))
y(P) = cos(φ(P)) sin(λ(P))
z(P) = cos(φ(P)) cos(λ(P))
(the only approximation is that this holds only for a perfect sphere)
The center of mass is given by x(M) = Σx(P)/n, etc.,
and the maximum one has to look for is
max((x(PN) - x(PN-1))2 + (y(PN) - y(PN-1))2 + (z(PN) - z(PN-1))2)
So: you first transform spherical to cartesian coordinates, then start from the center of mass, to find, in at least two steps (steps 2 and 3), the farthest point from the preceding point. You could repeat step 3 as long as the distance increases, perhaps with a maximum number of repetitions, but this won't take you away from a local maximum. Starting from the center of mass is not of much help, either, if the points are spread all over the Earth.
EDIT 2:
I learned enough R to write down the core of the algorithm (nice language for data analysis!)
For the plane approximation, ignoring the problem around the λ=±180° line:
# input: lng, lat (vectors)
rad = pi / 180;
x = (lng - mean(lng)) * cos(lat * rad)
y = (lat - mean(lat))
i = which.max((x - mean(x))^2 + (y )^2)
j = which.max((x - x[i] )^2 + (y - y[i])^2)
# output: i, j (indices)
On my PC it takes less than a second to find the indices i and j for 1000000 points. The following 3D version is a bit slower, but works for any distribution of points (and does not need to be amended when the λ=±180° line is crossed):
# input: lng, lat
rad = pi / 180
x = sin(lat * rad)
f = cos(lat * rad)
y = sin(lng * rad) * f
z = cos(lng * rad) * f
i = which.max((x - mean(x))^2 + (y - mean(y))^2 + (z - mean(z))^2)
j = which.max((x - x[i] )^2 + (y - y[i] )^2 + (z - z[i] )^2)
k = which.max((x - x[j] )^2 + (y - y[j] )^2 + (z - z[j] )^2) # optional
# output: j, k (or i, j)
The calculation of k can be left out (i.e., the result could be given by i and j), depending on the data and on the requirements. On the other hand, my experiments have shown that calculating a further index is useless.
It should be remembered that, in any case, the distance between the resulting points is an estimate which is a lower bound of the "diameter" of the set, although it very often will be the diameter itself (how often depends on the data.)
EDIT 3:
Unfortunately the relative error of the plane approximation can, in extreme cases, be as much as 1-1/√3 ≅ 42.3%, which may be unacceptable, even if very rare. The algorithm can be modified in order to have an upper bound of approximately 20%, which I have derived by compass and straight-edge (the analytic solution is cumbersome). The modified algorithm finds a pair of points whith a locally maximal distance, then repeats the same steps, but this time starting from the midpoint of the first pair, possibly finding a different pair:
# input: lng, lat
rad = pi / 180
x = (lng - mean(lng)) * cos(lat * rad)
y = (lat - mean(lat))
i.n_1 = 1 # n_1: n-1
x.n_1 = mean(x)
y.n_1 = 0 # = mean(y)
s.n_1 = 0 # s: square of distance
repeat {
s = (x - x.n_1)^2 + (y - y.n_1)^2
i.n = which.max(s)
x.n = x[i.n]
y.n = y[i.n]
s.n = s[i.n]
if (s.n <= s.n_1) break
i.n_1 = i.n
x.n_1 = x.n
y.n_1 = y.n
s.n_1 = s.n
}
i.m_1 = 1
x.m_1 = (x.n + x.n_1) / 2
y.m_1 = (y.n + y.n_1) / 2
s.m_1 = 0
m_ok = TRUE
repeat {
s = (x - x.m_1)^2 + (y - y.m_1)^2
i.m = which.max(s)
if (i.m == i.n || i.m == i.n_1) { m_ok = FALSE; break }
x.m = x[i.m]
y.m = y[i.m]
s.m = s[i.m]
if (s.m <= s.m_1) break
i.m_1 = i.m
x.m_1 = x.m
y.m_1 = y.m
s.m_1 = s.m
}
if (m_ok && s.m > s.n) {
i = i.m
j = i.m_1
} else {
i = i.n
j = i.n_1
}
# output: i, j
The 3D algorithm can be modified in a similar way. It is possible (both in the 2D and in the 3D case) to start over once again from the midpoint of the second pair of points (if found). The upper bound in this case is "left as an exercise for the reader" :-).
Comparison of the modified algorithm with the (too) simple algorithm has shown, for normal and for square uniform distributions, a near doubling of processing time, and a reduction of the average error from .6% to .03% (order of magnitude). A further restart from the midpoint results in an a just slightly better average error, but almost equal maximum error.
EDIT 4:
I have to study this article yet, but it looks like the 20% I found with compass and straight-edge is in fact 1-1/√(5-2√3) ≅ 19.3%
Here's a naive example that doesn't scale well (as you say), as you say but might help with building a solution in R.
## lonlat points
n <- 100
d <- cbind(runif(n, -180, 180), runif(n, -90, 90))
library(sp)
## distances on WGS84 ellipsoid
x <- spDists(d, longlat = TRUE)
## row, then column index of furthest points
ind <- c(row(x)[which.max(x)], col(x)[which.max(x)])
## maps
library(maptools)
data(wrld_simpl)
plot(as(wrld_simpl, "SpatialLines"), col = "grey")
points(d, pch = 16, cex = 0.5)
## draw the points and a line between on the page
points(d[ind, ], pch = 16)
lines(d[ind, ], lwd = 2)
## for extra credit, draw the great circle on which the furthest points lie
library(geosphere)
lines(greatCircle(d[ind[1], ], d[ind[2], ]), col = "firebrick")
The geosphere package provides more options for distance calculation if that's needed. See ?spDists in sp for the details used here.
You don't tell us whether these points will be located in a sufficiently small part of the globe. For truly global sets of points, my first guess would be running a naive O(n^2) algorithm, possibly getting performance boost with some spatial indexing (R*-trees, octal-trees etc.). The idea is to pre-generate an n*(n-1) list of the triangle in the distance matrix and feed it in chunks to a fast distance library to minimize I/O and process churn. Haversine is fine, you could also do it with Vincenty's method (the greatest contributor to running time is quadratic complexity, not the (fixed number of) iterations in Vincenty's formula). As a side note, in fact, you don't need R for this stuff.
EDIT #2: The Barequet-Har-Peled algorithm (as pointed at by Spacedman in his reply) has O((n+1/(e^3))log(1/e)) complexity for e>0, and is worth exploring.
For the quasi-planar problem, this is known as "diameter of convex hull" and has three parts:
Computing convex hull with Graham's scan which is O(n*log(n)) - in fact, one should try transforming points into a transverse Mercator projection (using the centroid of the points in data set).
Finding antipodal points by Rotating Calipers algorithm - linear O(n).
Finding the largest distance among all antipodal pairs - linear search, O(n).
The link with pseudo-code and discussion: http://fredfsh.com/2013/05/03/convex-hull-and-its-diameter/
See also the discussion on a related question here: https://gis.stackexchange.com/questions/17358/how-can-i-find-the-farthest-point-from-a-set-of-existing-points
EDIT: Spacedman's solution pointed me to the Malandain-Boissonnat algorithm (see the paper in pdf here). However, this is worse or the same as the bruteforce naive O(n^2) algorithm.
I have some point on a 2D grid (x, y) and I need to find all points that are n distance away from that point. The way I'm measuring distance is by using the distance formula between the two points. Anyone know how to do this?
Edit: Just for reference, what I'm trying to do is to write some AI path finding that will maintain some distance away from a target in a system that uses grid based locations. Currently I'm using A* path finding, but I'm not sure if that matters or makes a difference since I'm kind of new to this stuff.
Here's what I would do:
First filter out all points that are further than D on either x or y. These are certainly outside the circle of radius D. This is a much simpler computation, and it can quickly eliminate a lot of work. This is a outer bounding-box optimization.
You can also use an inner bounding-box optimization. If the points are closer than D * sqrt(2)/2 on either x or y, then they're certainly within the circle of radius D. This is also cheaper than calculating the distance formula.
Then you have a smaller number of candidate points that may be within the circle of radius D. For these, use the distance formula. Remember that if D = sqrt(Δx2+Δy2), then D2 = Δx2+Δy2.
So you can skip the cost of calculating square root.
So in pseudocode, you could do the following:
for each point
begin
if test 1 indicates the point is outside the outer bounding box,
then skip this point
if test 2 indicates the point is inside the inner bounding box,
then keep this point
if test 3 indicates the point is inside the radius of the circle,
then keep this point
end
This problem is known as range query. The brute force solution is just as you described: computed the distance of all points from the reference point and return those whose distance is less than the desired range value.
The brute force algorithm is O(N^2). There are, however, more efficient algorithms that employ spatial indexes to reduce algorithm complexity and the number of distance calculations. For example, you can use a R-Tree to index your points.
Its called nearest neighbor search. More at http://en.wikipedia.org/wiki/Nearest_neighbor_search
There are open libraries for that. I have used one written for C and recommend it: http://www.cs.umd.edu/~mount/ANN/. ANN stands for Approximate Nearest Neighbor, however, you can turn the approximation off and find the exact nearest neighbors.
This wouldn't use the distance formula, but if you're looking for points exactly n distance away, perhaps you could use sin/cos?
In pseudocode:
for degrees in range(360):
x = cos(degrees) * n
y = sin(degrees) * n
print x, y
That would print every point n away in 360 degree increments.
Java implementation:
public static Set<Point> findNearbyPoints(Set<Point> pts, Point centerPt, double radius) {
Set<Point> nearbyPtsSet = new HashSet<Point>();
double innerBound = radius * (Math.sqrt(2.0) / 2.0);
double radiusSq = radius * radius;
for (Point pt : pts) {
double xDist = Math.abs(centerPt.x - pt.x);
double yDist = Math.abs(centerPt.y - pt.y);
if (xDist > radius || yDist > radius)
continue;
if (xDist > innerBound || yDist > innerBound)
continue;
if (distSq(centerPt, pt) < radiusSq)
nearbyPtsSet.add(pt);
}
return nearbyPtsSet;
}
I have two points (x1, y1) and (x2,y2) which represent the location of two entities in my space. I calculate the Euclidian distance between them using Pythagoras' theorem and everything is wonderful. However, if my space becomes finite, I want to define a new shortest distance between the points that "wraps around" the seams of the map. For example, if I have point A as (10, 10) and point B as (90,10), and my map is 100 units wide, I'd like to calculate the distance between A and B as 20 (out the right edge of the map and back into the left edge), instead of 80, which is the normal Euclidian distance.
I think my issue is that I'm using a coordinate system that isn't quite right for what I'm trying to do, and that really my flat square map is more of a seamless doughnut shape. Any suggestions for how to implement a system of this nature and convert back and forth from Cartesian coordinates would be appreciated too!
Toroidal plane? Okay, I'll bite.
var raw_dx = Math.abs(x2 - x1);
var raw_dy = Math.abs(y2 - y1);
var dx = (raw_dx < (xmax / 2)) ? raw_dx : xmax - raw_dx;
var dy = (raw_dy < (ymax / 2)) ? raw_dy : ymax - raw_dy;
var l2dist = Math.sqrt((dx * dx) + (dy * dy));
There's a correspondence here between the rollover behavior of your x and y coordinates and the rollover behavior of signed integers represented using the base's complement representation in the method of complements.
If your coordinate bounds map exactly to the bounds of a binary integer type supported by your language, you can take advantage of the two's complement representation used by nearly all current machines by simply performing the subtraction directly, ignoring overflow and reinterpreting the result as a signed value of the same size as the original coordinate. In the general case, you're not going to be that lucky, so the above dance with abs, compare and subtract is required.