Path: blob/master/modules/navigation_2d/2d/nav_region_builder_2d.cpp
10278 views
/**************************************************************************/1/* nav_region_builder_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "nav_region_builder_2d.h"3132#include "../nav_map_2d.h"33#include "../nav_region_2d.h"34#include "../triangle2.h"35#include "nav_region_iteration_2d.h"3637using namespace Nav2D;3839void NavRegionBuilder2D::build_iteration(NavRegionIterationBuild2D &r_build) {40PerformanceData &performance_data = r_build.performance_data;4142performance_data.pm_polygon_count = 0;43performance_data.pm_edge_count = 0;44performance_data.pm_edge_merge_count = 0;45performance_data.pm_edge_connection_count = 0;46performance_data.pm_edge_free_count = 0;4748_build_step_process_navmesh_data(r_build);4950_build_step_find_edge_connection_pairs(r_build);5152_build_step_merge_edge_connection_pairs(r_build);5354_build_update_iteration(r_build);55}5657void NavRegionBuilder2D::_build_step_process_navmesh_data(NavRegionIterationBuild2D &r_build) {58Vector<Vector2> _navmesh_vertices = r_build.navmesh_data.vertices;59Vector<Vector<int>> _navmesh_polygons = r_build.navmesh_data.polygons;6061if (_navmesh_vertices.is_empty() || _navmesh_polygons.is_empty()) {62return;63}6465PerformanceData &performance_data = r_build.performance_data;66Ref<NavRegionIteration2D> region_iteration = r_build.region_iteration;6768const Transform2D ®ion_transform = region_iteration->transform;69LocalVector<Nav2D::Polygon> &navmesh_polygons = region_iteration->navmesh_polygons;7071const int vertex_count = _navmesh_vertices.size();7273const Vector2 *vertices_ptr = _navmesh_vertices.ptr();74const Vector<int> *polygons_ptr = _navmesh_polygons.ptr();7576navmesh_polygons.resize(_navmesh_polygons.size());7778real_t _new_region_surface_area = 0.0;79Rect2 _new_region_bounds;8081bool first_vertex = true;8283for (uint32_t i = 0; i < navmesh_polygons.size(); i++) {84Polygon &polygon = navmesh_polygons[i];85polygon.id = i;86polygon.owner = region_iteration.ptr();87polygon.surface_area = 0.0;8889Vector<int> polygon_indices = polygons_ptr[i];9091int polygon_size = polygon_indices.size();92if (polygon_size < 3) {93continue;94}9596const int *indices_ptr = polygon_indices.ptr();9798bool polygon_valid = true;99100polygon.vertices.resize(polygon_size);101102{103real_t _new_polygon_surface_area = 0.0;104105for (int j(2); j < polygon_size; j++) {106const Triangle2 triangle = Triangle2(107region_transform.xform(vertices_ptr[indices_ptr[0]]),108region_transform.xform(vertices_ptr[indices_ptr[j - 1]]),109region_transform.xform(vertices_ptr[indices_ptr[j]]));110111_new_polygon_surface_area += triangle.get_area();112}113114polygon.surface_area = _new_polygon_surface_area;115_new_region_surface_area += _new_polygon_surface_area;116}117118for (int j(0); j < polygon_size; j++) {119int vertex_index = indices_ptr[j];120if (vertex_index < 0 || vertex_index >= vertex_count) {121polygon_valid = false;122break;123}124125const Vector2 point_position = region_transform.xform(vertices_ptr[vertex_index]);126polygon.vertices[j] = point_position;127128if (first_vertex) {129first_vertex = false;130_new_region_bounds.position = point_position;131} else {132_new_region_bounds.expand_to(point_position);133}134}135136if (!polygon_valid) {137polygon.surface_area = 0.0;138polygon.vertices.clear();139ERR_FAIL_COND_MSG(!polygon_valid, "Corrupted navigation mesh set on region. The indices of a polygon are out of range.");140}141}142143region_iteration->surface_area = _new_region_surface_area;144region_iteration->bounds = _new_region_bounds;145146performance_data.pm_polygon_count = navmesh_polygons.size();147}148149Nav2D::PointKey NavRegionBuilder2D::get_point_key(const Vector2 &p_pos, const Vector2 &p_cell_size) {150const int x = static_cast<int>(Math::floor(p_pos.x / p_cell_size.x));151const int y = static_cast<int>(Math::floor(p_pos.y / p_cell_size.y));152153PointKey p;154p.key = 0;155p.x = x;156p.y = y;157return p;158}159160Nav2D::EdgeKey NavRegionBuilder2D::get_edge_key(const Vector2 &p_vertex1, const Vector2 &p_vertex2, const Vector2 &p_cell_size) {161EdgeKey ek(get_point_key(p_vertex1, p_cell_size), get_point_key(p_vertex2, p_cell_size));162return ek;163}164165void NavRegionBuilder2D::_build_step_find_edge_connection_pairs(NavRegionIterationBuild2D &r_build) {166PerformanceData &performance_data = r_build.performance_data;167168const Vector2 &map_cell_size = r_build.map_cell_size;169Ref<NavRegionIteration2D> region_iteration = r_build.region_iteration;170LocalVector<Nav2D::Polygon> &navmesh_polygons = region_iteration->navmesh_polygons;171172HashMap<EdgeKey, EdgeConnectionPair, EdgeKey> &connection_pairs_map = r_build.iter_connection_pairs_map;173connection_pairs_map.clear();174175region_iteration->internal_connections.clear();176region_iteration->internal_connections.resize(navmesh_polygons.size());177178region_iteration->external_edges.clear();179180int free_edges_count = 0;181182for (Polygon &poly : region_iteration->navmesh_polygons) {183for (uint32_t p = 0; p < poly.vertices.size(); p++) {184const int next_point = (p + 1) % poly.vertices.size();185const EdgeKey ek = get_edge_key(poly.vertices[p], poly.vertices[next_point], map_cell_size);186187HashMap<EdgeKey, EdgeConnectionPair, EdgeKey>::Iterator pair_it = connection_pairs_map.find(ek);188if (!pair_it) {189pair_it = connection_pairs_map.insert(ek, EdgeConnectionPair());190performance_data.pm_edge_count += 1;191++free_edges_count;192}193EdgeConnectionPair &pair = pair_it->value;194if (pair.size < 2) {195// Add the polygon/edge tuple to this key.196Connection new_connection;197new_connection.polygon = &poly;198new_connection.edge = p;199new_connection.pathway_start = poly.vertices[p];200new_connection.pathway_end = poly.vertices[next_point];201202pair.connections[pair.size] = new_connection;203++pair.size;204if (pair.size == 2) {205--free_edges_count;206}207208} else {209// The edge is already connected with another edge, skip.210ERR_FAIL_COND_MSG(pair.size >= 2, "Navigation region synchronization error. More than 2 edges tried to occupy the same map rasterization space. This is a logical error in the navigation mesh caused by overlap or too densely placed edges.");211}212}213}214215performance_data.pm_edge_free_count = free_edges_count;216}217218void NavRegionBuilder2D::_build_step_merge_edge_connection_pairs(NavRegionIterationBuild2D &r_build) {219PerformanceData &performance_data = r_build.performance_data;220221Ref<NavRegionIteration2D> region_iteration = r_build.region_iteration;222223HashMap<EdgeKey, EdgeConnectionPair, EdgeKey> &connection_pairs_map = r_build.iter_connection_pairs_map;224225for (const KeyValue<EdgeKey, EdgeConnectionPair> &pair_it : connection_pairs_map) {226const EdgeConnectionPair &pair = pair_it.value;227if (pair.size == 2) {228// Connect edge that are shared in different polygons.229const Connection &c1 = pair.connections[0];230const Connection &c2 = pair.connections[1];231region_iteration->internal_connections[c1.polygon->id].push_back(c2);232region_iteration->internal_connections[c2.polygon->id].push_back(c1);233performance_data.pm_edge_merge_count += 1;234235} else {236ERR_FAIL_COND_MSG(pair.size != 1, vformat("Number of connection != 1. Found: %d", pair.size));237238const Connection &connection = pair.connections[0];239240ConnectableEdge ce;241ce.ek = pair_it.key;242ce.polygon_index = connection.polygon->id;243ce.edge = connection.edge;244ce.pathway_start = connection.pathway_start;245ce.pathway_end = connection.pathway_end;246247region_iteration->external_edges.push_back(ce);248}249}250}251252void NavRegionBuilder2D::_build_update_iteration(NavRegionIterationBuild2D &r_build) {253ERR_FAIL_NULL(r_build.region);254// Stub. End of the build.255}256257258