Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Find height update #80

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions MapViewer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,23 +299,16 @@ LRESULT CALLBACK GuiWindowProc(HWND hWnd, UINT message, WPARAM wParam,
}

auto const& prev_hop = path[path.size() - 2];
float height;
if (gNavMesh->FindHeight(prev_hop, hit.X, hit.Y, height))
{
std::stringstream ss;
ss << "Destination: " << hit.X << ", " << hit.Y
<< ", " << hit.Z
<< " FindHeight returns: " << height << "\n";
std::stringstream ss;
ss << "Destination: " << hit.X << ", " << hit.Y
<< ", " << hit.Z << "\n";

std::vector<float> heights;
if (gNavMesh->FindHeights(hit.X, hit.Y, heights))
for (auto const& h : heights)
ss << "Possible correct values: " << h << "\n";
std::vector<float> heights;
if (gNavMesh->FindHeights(hit.X, hit.Y, heights))
for (auto const& h : heights)
ss << "Possible correct values: " << h << "\n";

OutputDebugStringA(ss.str().c_str());
}
else
OutputDebugStringA("No height found");
OutputDebugStringA(ss.str().c_str());
}
else
{
Expand Down Expand Up @@ -791,8 +784,18 @@ void SearchZValues()
result << "Heights at (" << posX << ", " << posY << "):\n";
for (auto const h : output)
{
result << h << "\n";
gRenderer->AddSphere({posX, posY, h}, 0.75f);
const math::Vertex pos {posX, posY, h};
unsigned int zone, area;

result << h;

if (gNavMesh->ZoneAndArea(pos, zone, area))
result << " Zone: " << zone << " Area: " << area;
else
result << " ZoneAndArea failed";
result << "\n";

gRenderer->AddSphere(pos, 0.75f);
}

MessageBoxA(nullptr, result.str().c_str(), "Z Search Results", 0);
Expand Down
90 changes: 38 additions & 52 deletions pathfind/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,25 @@ bool Map::FindPath(const math::Vertex& start, const math::Vertex& end,
for (auto i = 0; i < pathLength; ++i)
math::Convert::VertexToWow(&pathBuffer[i * 3], output[i]);

return true;
// for the last point, let us refine the z. we know that the value
// returned from Detour will be within MeshSettings::DetailSampleMaxError
// yards above or below. to begin with, we shift that error range upwards
// so we know that we are above the true value.
output[pathLength - 1].Z += MeshSettings::DetailSampleMaxError;

// nudge it up by the smallest possible amount to make sure we are OVER
// the correct value and not exactly at it
output[pathLength - 1].Z = std::nextafter(output[pathLength - 1].Z,
output[pathLength - 1].Z + 1.f);

auto const endTile =
GetTile(output[pathLength - 1].X, output[pathLength - 1].Y);

// if for some reason we fail, fail hard!
return !!endTile &&
FindNextZ(endTile, output[pathLength - 1].X,
output[pathLength - 1].Y, output[pathLength - 1].Z, true,
output[pathLength - 1].Z);
}

const Tile* Map::GetTile(float x, float y) const
Expand All @@ -594,8 +612,8 @@ const Tile* Map::GetTile(float x, float y) const
math::Convert::WorldToTile({x, y, 0.f}, tileX, tileY);
else
{
tileX = (m_globalWmoOriginY - y) / MeshSettings::TileSize;
tileY = (m_globalWmoOriginX - x) / MeshSettings::TileSize;
tileX = static_cast<int>((m_globalWmoOriginY - y) / MeshSettings::TileSize);
tileY = static_cast<int>((m_globalWmoOriginX - x) / MeshSettings::TileSize);
}

auto const tile = m_tiles.find({tileX, tileY});
Expand Down Expand Up @@ -813,55 +831,6 @@ bool Map::FindRandomPointAroundCircle(const math::Vertex& centerPosition,
return true;
}


bool Map::FindHeight(const math::Vertex& source, float x, float y, float& z) const
{
// ray cast along navmesh from source to target
float recastSource[3];
math::Convert::VertexToRecast(source, recastSource);

constexpr float extents[] = {1.f, 1.f, 1.f};

dtPolyRef startRef;
if (m_navQuery.findNearestPoly(recastSource, extents, &m_queryFilter,
&startRef, nullptr) != DT_SUCCESS)
return false;

float recastTarget[3];
// use the source Z as an initial guess
math::Convert::VertexToRecast({x, y, source.Z}, recastTarget);

dtPolyRef hit_path[100];
dtRaycastHit hit;
hit.path = hit_path;
hit.maxPath = sizeof(hit_path) / sizeof(hit_path[0]);

if (m_navQuery.raycast(startRef, recastSource, recastTarget, &m_queryFilter,
0, &hit) != DT_SUCCESS)
return false;

if (!hit.pathCount)
return false;

// if we reach here, it means we have a path and know the poly ref for
// the poly where the ray hit. so let's use that reference and query
// the height at the requested x,y.
if (m_navQuery.getPolyHeight(hit.path[hit.pathCount - 1], recastTarget,
&z) != DT_SUCCESS)
return false;

auto const tile = GetTile(x, y);

if (!tile)
return false;

// take the imprecise z value from the mesh, and return the precise value
if (!FindNextZ(tile, x, y, z, true, z))
return false;

return true;
}

bool Map::FindHeights(float x, float y, std::vector<float>& output) const
{
auto const tile = GetTile(x, y);
Expand Down Expand Up @@ -938,6 +907,23 @@ bool Map::ZoneAndArea(const math::Vertex& position, unsigned int& zone,
area = adtArea;
}

// if both queries failed, try a ray facing up instead
if (!rayResult && !adtResult)
{
math::Ray upRay {
{position.X, position.Y, position.Z},
{position.X, position.Y, tile->m_bounds.getMaximum().Z}};

if (RayCast(upRay, tiles, false, &localZone, &localArea))
{
zone = localZone;
area = localArea;
return true;
}

// if it fails, fall through to below
}

assert(rayResult || adtResult);

return rayResult || adtResult;
Expand Down
16 changes: 3 additions & 13 deletions pathfind/Map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,9 @@ class Map
std::vector<math::Vertex>& output,
bool allowPartial = false) const;

// for finding height(s) at a given (x, y), there are two scenarios:
// 1: we want to find exactly one z for a given path which has this (x, y)
// as a hop. in this case, there should only be one correct value,
// and it is the value that would be achieved by walking either from the
// previous hop to this one, or from this hop to the next one.
// 2: for a given (x, y), we want to find all possible z values
//
// NOTE: if your usage is outside of both of these scenarios, you are
// probably doing something wrong
bool FindHeight(const math::Vertex& source, float x, float y,
float& z) const; // scenario one
bool FindHeights(float x, float y,
std::vector<float>& output) const; // scenario two
// WARNING: I'm not sure why you need this function, and therefore may
// remove it. If someone needs it, could you please let me know?
bool FindHeights(float x, float y, std::vector<float>& output) const;

bool ZoneAndArea(const math::Vertex& position, unsigned int& zone,
unsigned int& area) const;
Expand Down
27 changes: 0 additions & 27 deletions pathfind/pathfind_c_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,33 +278,6 @@ PathfindResultType pathfind_find_heights(pathfind::Map* const map,
}
}

PathfindResultType pathfind_find_height(pathfind::Map* const map, float start_x,
float start_y, float start_z,
float stop_x, float stop_y,
float* const stop_z)
{
try
{
math::Vertex start {start_x, start_y, start_z};
float result;
if (map->FindHeight(start, stop_x, stop_y, result))
{
*stop_z = result;
return static_cast<PathfindResultType>(Result::SUCCESS);
}

return static_cast<PathfindResultType>(Result::UNKNOWN_HEIGHT);
}
catch (utility::exception& e)
{
return static_cast<PathfindResultType>(e.ResultCode());
}
catch (...)
{
return static_cast<PathfindResultType>(Result::UNKNOWN_EXCEPTION);
}
}

PathfindResultType pathfind_line_of_sight(pathfind::Map* map,
float start_x, float start_y, float start_z,
float stop_x, float stop_y, float stop_z,
Expand Down
10 changes: 0 additions & 10 deletions pathfind/pathfind_c_bindings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,6 @@ PathfindResultType pathfind_find_heights(pathfind::Map* const map, float x, floa
unsigned int buffer_length,
unsigned int* const amount_of_heights);

/*
Returns the `stop_z` for the path between `start_x`, `start_y`, `start_z`
and `stop_x`, `stop_y`.
This is the value that would be achieved by walking from start to stop.
*/
PathfindResultType pathfind_find_height(pathfind::Map* const map, float start_x,
float start_y, float start_z,
float stop_x, float stop_y,
float* const stop_z);

/*
Calculates whether there is line of sight between `start_x`, `start_y`, `start_z`
and `stop_x`, `stop_y`, `stop_z`.
Expand Down
19 changes: 0 additions & 19 deletions pathfind/python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,6 @@ py::list python_query_heights(const pathfind::Map& map, float x, float y)
return result;
}

std::optional<float> python_query_z(const pathfind::Map& map, float start_x, float start_y, float start_z,
float stop_x, float stop_y)
{
float result;
if (!map.FindHeight({start_x, start_y, start_z}, stop_x, stop_y, result))
return {};
return result;
}

bool los(const pathfind::Map& map, float start_x, float start_y, float start_z,
float stop_x, float stop_y, float stop_z, bool doodads)
Expand Down Expand Up @@ -179,17 +171,6 @@ Returns a list of points if a path was found, otherwise an empty list.)del",
py::arg("x"),
py::arg("y")
)
.def("query_z",
&python_query_z,
R"del(Returns the `stop_z` value for a given `start_x`, `start_y`, `start_z` and `stop_x`, `stop_y`.

This is the value that would be achieved by walking from start to stop.)del",
py::arg("start_x"),
py::arg("start_y"),
py::arg("start_z"),
py::arg("stop_x"),
py::arg("stop_y")
)
.def("get_zone_and_area",
&get_zone_and_area,
"Returns the zone and area values for a specific coordinate.",
Expand Down
21 changes: 7 additions & 14 deletions test/manual_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_build_data(wow_data, nav_data, jobs):
bvh_file_count = mapbuild.build_bvh(wow_data, nav_data, jobs)
build_time = time.time() - start

min_bvh_count = 800
min_bvh_count = 230
if bvh_file_count < min_bvh_count:
raise RuntimeError('Expected %d BVH files, found only %d' % (
min_bvh_count, bvh_file_count))
Expand Down Expand Up @@ -110,6 +110,11 @@ def test_use_data(nav_data):
assert zone == 1497 and area == 1497

print('Undercity area check succeeded')

# This WMO is rotated around all axis and serves as a check that the translation is working well
azeroth.load_adt_at(-1173.688, -2046.505)
z_values = azeroth.query_heights(-1173.688, -2046.505)
assert len(z_values) == 2 and approximate(z_values[0], 37.323)

def main():
parser = argparse.ArgumentParser()
Expand All @@ -136,23 +141,11 @@ def main():
test_use_data(args.navdata)
finally:
if args.build_nav_data:
print('Removing temporary directory')
shutil.rmtree(args.navdata)

return 0

if __name__ == '__main__':
sys.exit(main())
wow_data = os.getenv('NAM_WOW_DATA')
if wow_data is None:
wow_data = r'f:\wow 1.12.1\data'

if wow_data is not None and not os.path.isdir(wow_data):
raise RuntimeError('Data dir %s does not exist' % wow_data)

existing_mesh_data = os.getenv('NAM_MESH_DATA')

if existing_mesh_data is not None and not \
os.path.isdir(existing_mesh_data):
raise RuntimeError('NAM_MESH_DATA %s does not exist' % existing_mesh_data)

unittest.main()
13 changes: 7 additions & 6 deletions test/smoke_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,16 @@ def compute_path_length(path):

print("Should-pass doodad LoS check succeeded")

query_z = map_data.query_z(16232.7373, 16828.2734, 37.1330833, 16208.6, 16830.7)
path = map_data.find_path(16232.7373, 16828.2734, 37.1330833, 16208.6, 16830.7, 37)

if query_z is None:
raise Exception("Query Z failed with None")
if path is None:
raise Exception("Z correction in find_path failed")

if not approximate(query_z, 36.86227):
raise Exception("Query Z failed with {}".format(query_z))
final_z = path[-1][2]
if not approximate(final_z, 36.86227):
raise Exception("Z correction test failed with {}".format(final_z))

print("Query Z succeeded")
print("Z correction succeeded")

map_data = pathfind.Map(temp_dir, "bladesedgearena")
map_data.load_adt_at(6225, 250)
Expand Down
Loading