Community and Support
»
Support
»
Feature Requests
»
Getting the height of a specifique point
Rank: Member
Groups: Registered
Joined: 8/10/2015(UTC) Posts: 11
Was thanked: 1 time(s) in 1 post(s)

After the last update i found my self putting in place a interpolation function to get more precise data out of the new heightmap.
I was wondering if a "float Map.Terrain.getHeight(float x, float z)" method or something close to get the height of any point on the map could be considered for a future update?




Rank: Administration
Groups: Administrators, Registered Joined: 5/7/2015(UTC) Posts: 42
Thanks: 2 times Was thanked: 5 time(s) in 4 post(s)

There's already a Map.Terrain.GetHeight method, which uses nearestneighbor interpolation. The heightmap resolution is 512 (i.e., 512 x 512), and since the map size is 1000 x 1000 meters, the value returned by GetHeight will be at least fairly accurate  the height of a point on the ground less than 2 meters away on the XZ plane (1000 / 512 = 1.953125). That is to say, the map doesn't have such drastic spikes or dips that happen within a 2 meter surface area that your result would be off by much. We may add an override that provides a more precise value, perhaps one that does bilinear interpolation, for example, but the call would be more expensive of course. Until then, the existing method might be good enough for most cases. If it fails to work for you, maybe post your scenario so we can figure something out. For reference, here's how the GetHeight method works right now: Code:
// Do some onetime initialization:
_heightmapCenter = Heightmap.Resolution / 2;
_resXFactor = Heightmap.Resolution / (float)Map.Size.X;
_resYFactor = Heightmap.Resolution / (float)Map.Size.Y;
...
/// <summary>
/// Gets the approximate terrain height at a position on the game map.
/// </summary>
/// <param name="position">position (Y coordinate is ignored)</param>
/// <returns>height</returns>
public float GetHeight(Vector3D position)
{
return Heightmap.Samples[
(int)Math.Round(position.Z * _resYFactor + _heightmapCenter, MidpointRounding.AwayFromZero),
(int)Math.Round(position.X * _resXFactor + _heightmapCenter, MidpointRounding.AwayFromZero)];
}
Edited by user Friday, August 28, 2015 6:23:43 AM(UTC)
 Reason: Not specified




Rank: Member
Groups: Registered
Joined: 8/10/2015(UTC) Posts: 11
Was thanked: 1 time(s) in 1 post(s)

Oups, i didn't see the Map.Terrain.GetHeight methode, i'm sorry! ( I in deed used bilinear interpolation in my code, even though it has a higher calculation cost).
Thank you!




Rank: Administration
Groups: Administrators, Registered Joined: 5/7/2015(UTC) Posts: 42
Thanks: 2 times Was thanked: 5 time(s) in 4 post(s)

Ah, OK. Do you mind sharing your interpolation method? It might be useful for others and we could compare it to what we're planning, too.




Rank: Member
Groups: Registered
Joined: 8/10/2015(UTC) Posts: 11
Was thanked: 1 time(s) in 1 post(s)

Of course: It's kind of messy, as i don't if the values of the heightmap come from the "middle" of the pixel or the corner or if its the average heigth or anything else. By this i mean don't know if heigthMap[0,0] is the heigth at coordonate (0,0) or the average/middle/(or whatever it is) heigth of the bottomleft "box" witch has a side of 1/512 * 1000 meters. So there may be a slight offset. Code: public float getHeight(Vector3D position)
{
// Here i supposed that heigthMape[x,y] value came from the center of the box,
//the 0.5 come from there
float y = (float)(position.X + _origine.X)/ _width * _heightMap.Resolution  0.5f,
x = (float)(position.Z + _origine.Z)/ _height * _heightMap.Resolution  0.5f;
int x2 = (int)Math.Ceiling(x),
x1 = (int)Math.Floor(x),
y2 = (int)Math.Ceiling(y),
y1 = (int)Math.Floor(y);
// Making sure to keep into index range > the points on the outer edges will be
// interpolated from only 2 pts. See below
if (x1 < 0)
x1++;
if (x2 > _heightMap.Resolution  1)
x2;
if (y1 < 0)
y1++;
if (y2 > _heightMap.Resolution  1)
y2;
if (x1 == x2 && y1 == y2)
return _heightMap.Samples[x1, y1];
else if (x1 == x2)
return _heightMap.Samples[x1, y1] * (y2  y) +
_heightMap.Samples[x1, y2] * (y  y1) /
(y2  y1);
else if (y1 == y2)
return _heightMap.Samples[x1, y1] * (x2  x) +
_heightMap.Samples[x2, y1] * (x  x1) /
((x2  x1));
else
return (_heightMap.Samples[x1, y1] * (x2  x) * (y2  y) +
_heightMap.Samples[x2, y1] * (x  x1) * (y2  y) +
_heightMap.Samples[x1, y2] * (x2  x) * (y  y1) +
_heightMap.Samples[x2, y2] * (x  x1) * (y  y1)) /
((x2  x1) * (y2  y1));
}
Basically this comes straigth from wikipedia: https://en.wikipedia.org.../Bilinear_interpolation. I just added the tweaked formulas for it to work on the edges. PS: And yes the divisions are useless in this case. Edited by user Friday, August 28, 2015 9:04:02 AM(UTC)
 Reason: Not specified




Rank: Administration
Groups: Administrators, Registered Joined: 5/7/2015(UTC) Posts: 42
Thanks: 2 times Was thanked: 5 time(s) in 4 post(s)

Looks great. I think you need to add parentheses around the addition operations so it happens before the division, when averaging just two points, same as you do when averaging four. Also, why not just divide by the constants 2 and 4 in those places, like this? Code:
if (x1 == x2 && y1 == y2)
return _heightMap.Samples[x1, y1];
else if (x1 == x2)
return (_heightMap.Samples[x1, y1] * (y2  y) +
_heightMap.Samples[x1, y2] * (y  y1)) / 2;
else if (y1 == y2)
return (_heightMap.Samples[x1, y1] * (x2  x) +
_heightMap.Samples[x2, y1] * (x  x1)) / 2;
else
return (_heightMap.Samples[x1, y1] * (x2  x) * (y2  y) +
_heightMap.Samples[x2, y1] * (x  x1) * (y2  y) +
_heightMap.Samples[x1, y2] * (x2  x) * (y  y1) +
_heightMap.Samples[x2, y2] * (x  x1) * (y  y1)) / 4;
}
Edited by user Friday, August 28, 2015 9:48:46 AM(UTC)
 Reason: Not specified




Rank: Member
Groups: Registered
Joined: 8/10/2015(UTC) Posts: 11
Was thanked: 1 time(s) in 1 post(s)

My bad for the parenthesis. And unless i'm wrong, (x2  x1) * (y2  y1) always does 1 and do does the other dividers, so i can write: Code:if (x1 == x2 && y1 == y2)
return _heightMap.Samples[x1, y1];
else if (x1 == x2)
return (_heightMap.Samples[x1, y1] * (y2  y) +
_heightMap.Samples[x1, y2] * (y  y1));
else if (y1 == y2)
return (_heightMap.Samples[x1, y1] * (x2  x) +
_heightMap.Samples[x2, y1] * (x  x1));
else
return (_heightMap.Samples[x1, y1] * (x2  x) * (y2  y) +
_heightMap.Samples[x2, y1] * (x  x1) * (y2  y) +
_heightMap.Samples[x1, y2] * (x2  x) * (y  y1) +
_heightMap.Samples[x2, y2] * (x  x1) * (y  y1));




Rank: Administration
Groups: Administrators, Registered Joined: 5/7/2015(UTC) Posts: 42
Thanks: 2 times Was thanked: 5 time(s) in 4 post(s)

Ah, right, OK. I think we'll have an interpolation option for the GetHeight method eventually so people can choose which one they want to use. Edited by user Friday, August 28, 2015 5:57:46 PM(UTC)
 Reason: Not specified




Community and Support
»
Support
»
Feature Requests
»
Getting the height of a specifique point
Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You can vote in polls in this forum.