4
\$\begingroup\$

I’m working on a video game where I need to display a map (in 2D) of an actual big European city (Paris, London, Madrid… that kind of big) and the player, displayed as a simple dot on the map, can take different routes while following the street lines.

To do so I extract real data from OpenStreetMap.org. Thanks to it I have access to a ton of data and geographic information, and among them I have street visual settings given as series of coordinates (long/lat converted to X/Y points using the right projection). In OpenStreetMap a street is composed of a set of points so drawing a line between these points is enough to display streets.

However it represents a huge number of points to load which means a lot of time spent processing the data which means: not ideal. For example, a big city like Paris is composed of 65.000 street points. That is huge. In order to reduce this number and still being able to draw / follow street curves I’m thinking about using a graph only composed of points implied in street intersections alongside curve equations to describe the street display. This way a street composed of 2000 points would be not much bigger than one composed of 10 points in theory.

Example

The initial technique The final goal

In this example my initial set is composed of 13 points (red crosses) to display a street. What I’m aiming to in this case is keeping only 4 points (intersections with other streets) and an actual “equation” (or something similar) between each couple of points in order to reduce the size on disk of the final map.

This is where I’m stuck. I suck at Math (and regret it every day). So I can’t figure what would be the best way to transform a series of points into a simple equation that would allow me to follow the actual street curve at runtime.

I don’t know how to do it… I’ve read things about Bezier curves, about Clothoids, Circular Arcs… but I don’t know where to start, what is the best solution here, how to convert my series of points using one of these techniques, or if it’s really the clever thing to do in order to reduce the size (in bytes) of the map…

Any help would be appreciated.

Thanks.

\$\endgroup\$
  • 3
    \$\begingroup\$ keyword "linear regression" \$\endgroup\$ – ratchet freak Oct 17 '15 at 16:42
3
\$\begingroup\$

Streets can be pretty funky, with plenty of twists and turns. This can make it hard - or impossible - to describe one by a function of the form y = f(x), where x and y are Cartesian coordinates. Polar coordinates, too, will often fail, no matter where you choose the origin. Therefore, I think your best bet is to create a parametric curve - that is, a relationship so that any point (x,y) can be represented by functions of some parameter t:

(x,y) = (f(t), g(t))

When you're doing some sort of curve fitting like this, it's best to make t proportional to the arc length s, which tells you where on the curve you are. You can then treat t as the time it takes to move along the curve with some constant velocity (usually set to 1).

Step 1: A good approximation

Let's say you have a series of ten points {p1,p2,p3,p4,p5,p6,p7,p8,p9,p10} on your grid, each one with coordinates pj=(xj,yj). You want to create a curve P(t) that contains them all. The curve starts at p1, and goes from pj to p(j+1) until it reaches p10, where it stops.

We need to figure out the time at which a person traveling on the curve reaches the next point, i.e. how far apart two points are. If they're close enough together, then a linear approximation is enough. In pseudocode:

p1 = (x1,y1)
p2 = (x2,y2)
xdiff = x2 - x1
ydiff = y2 - y1
dist = sqrt(xdiff^2+ydiff^2)

We do this for each two points. If P(t1) = p1, then P(t2 - t1) = p2, where t2 is the linear distance between p1 and p2. We can set t1 = 0, if we want, for the sake of simplicity - assuming p1 is one of the endpoints.

After we've done this for all the points, we have three sets of numbers:

T = {t1,t2,t3,t4,t5,t6,t7,t8,t9,t10}
X = {x1,x2,x3,x4,x5,x6,x7,x8,x9,x10}
Y = {y1,y2,y3,y4,y5,y6,y7,y8,y9,y10}

and so at t=tj, the curve is at point pj(xj,yj). Now we can interpolate. You can construct two Lagrange polynomials1, one each for the x and y coordinates, each in terms of t. The formula is simple enough, although it's obviously harder to do by hand.

We now have a parametric curve that describes all the points.

But wait! That still requires a lot of coefficients, and we're trying to reduce that. So why did we even do this?

Step 2: Remove some points.

Let's say we only want to use four points. That's reasonable. I'll pick the endpoints and two others: {p1,p4,p7,p10}. Now, we can do the same thing as before. In fact, we could do the same interpolation we did in Step 1, by just finding the linear distance. And that's fine if you have a curve that only deviates a little from a straight line during each segment. However, that's often not the case. By simply finding the shortest distance between p4 and p7, we'd think that the two are a lot closer together, making the curve a lot different.

Therefore, we take what we did from step one. We find the length between these two points based on our interpolated curve P that uses all ten. This can be done by just finding the arc length. I'd recommend using numerical methods for this. We then have three sets:

T = {t1',t4',t7',t10'}
X = {x1,x4,x7,x10}
Y = {y1,y4,y7,y10}

I use the primes to show that the times we've found are different from what we did in step one. They may be more accurate. Now we do the same sort of interpolation, just with four points.

We now have a parametric equation for the curve, using only four points. It's much less accurate than the first equation, but it uses much less data, and it guarantees that the curve will still pass through these four points (that's an issue with polynomial regression - only rarely will a best-fit curve go through any of the points).

Now, we could have skipped Step 1. I know, maybe you're disappointed. As I said before, we could just have used the linear distances between the four points. But that misses most of the finer details of the curve, and if you're shortening a curve from, say, 20 points to 6 points, skipping the first interpolation could really be costly.


1 A Lagrange polynomial (not parameterized) is of the form

enter image description here

where

enter image description here

Here's the reasoning behind Lagrange polynomials (in this case, there is no parameterization - y is directly a function of x). You have n points with coordinates {(x1,y1),(x2,y2), . . . ,(xn,yn)}. You want to come up with a non-parameterized function y = f(x). The simplest way to do that is to come up with a function with n terms. At each point pj, i.e. when x = xj, all but one term - let's call it the jth term - will come to zero, and the remaining term will be equal to yj. From there, it's simple to construct the second expression for any point pl, and you simply add up n terms, each corresponding to a different pl, xl and yl. This gives you the Lagrange polynomial for your set of points.

In your application of Lagrange polynomials to streets, we've done the same thing - just parametrically.

\$\endgroup\$
  • \$\begingroup\$ Holly Macaroni! It took more than a year for someone to answer, but WHAT AN ANSWER! :) Thanks for the time spent writing this piece of knowledge. I'll try to implement and will probably get back at you soon. Thanks! \$\endgroup\$ – lvictorino Mar 16 '17 at 7:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.