Start to clean up quad and graph node

This commit is contained in:
Benau 2016-09-04 11:56:03 +08:00
parent 35ce9a39ce
commit 21dc569f70
35 changed files with 867 additions and 1028 deletions

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

@ -457,7 +457,7 @@ void SlipStream::update(float dt)
}
// Real test: if in slipstream quad of other kart
if(m_target_kart->getSlipstream()->m_slipstream_quad
->pointInQuad(m_kart->getXYZ()))
->pointInside(m_kart->getXYZ()))
{
is_sstreaming = true;
break;

@ -26,6 +26,7 @@
#include "karts/abstract_kart.hpp"
#include "modes/linear_world.hpp"
#include "utils/random_generator.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
@ -63,7 +64,7 @@ Bowling::Bowling(AbstractKart *kart)
{
unsigned int sector = ((LinearWorld*)World::getWorld())->
getTrackSector(kart->getWorldKartId()).getCurrentGraphNode();
quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal();
quadNormal = QuadGraph::get()->getNode(sector).getNormal();
}
else
quadNormal = btVector3(.0f, 1.0f, .0f);

@ -25,6 +25,8 @@
#include "modes/easter_egg_hunt.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/vec3.hpp"

@ -32,8 +32,9 @@
#include "modes/linear_world.hpp"
#include "network/network_config.hpp"
#include "network/race_event_manager.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/battle_graph.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@ -162,7 +163,7 @@ ItemManager::ItemManager()
m_items_in_quads = new std::vector<AllItemTypes>;
// Entries 0 to n-1 are for the quads, entry
// n is for all items that are not on a quad.
m_items_in_quads->resize(QuadSet::get()->getNumberOfQuads()+1);
m_items_in_quads->resize(QuadGraph::get()->getNumNodes()+1);
}
else
{
@ -227,7 +228,7 @@ void ItemManager::insertItem(Item *item)
// If the item is on the driveline, store it at the appropriate index
if(graph_node > -1)
{
int sector = QuadGraph::get()->getNode(graph_node).getQuadIndex();
int sector = QuadGraph::get()->getNode(graph_node).getNodeIndex();
(*m_items_in_quads)[sector].push_back(item);
}
else // otherwise store it in the 'outside' index

@ -29,6 +29,8 @@
#include "modes/linear_world.hpp"
#include "physics/btKart.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done
@ -97,7 +99,8 @@ RubberBall::RubberBall(AbstractKart *kart)
// initialises the current graph node
TrackSector::update(getXYZ());
Vec3 normal = QuadGraph::get()->getQuadOfNode(getCurrentGraphNode()).getNormal();
const Vec3& normal =
QuadGraph::get()->getNode(getCurrentGraphNode()).getNormal();
TerrainInfo::update(getXYZ(), -normal);
initializeControlPoints(m_owner->getXYZ());
@ -133,7 +136,7 @@ void RubberBall::initializeControlPoints(const Vec3 &xyz)
// left or right when firing the ball off track.
getNextControlPoint();
m_control_points[2] =
QuadGraph::get()->getQuadOfNode(m_last_aimed_graph_node).getCenter();
QuadGraph::get()->getNode(m_last_aimed_graph_node).getCenter();
// This updates m_last_aimed_graph_node, and sets m_control_points[3]
getNextControlPoint();
@ -234,7 +237,7 @@ void RubberBall::getNextControlPoint()
m_last_aimed_graph_node = next;
m_length_cp_2_3 = dist;
const Quad &quad =
QuadGraph::get()->getQuadOfNode(m_last_aimed_graph_node);
QuadGraph::get()->getNode(m_last_aimed_graph_node);
m_control_points[3] = quad.getCenter();
} // getNextControlPoint

@ -25,7 +25,7 @@
#include "karts/kart_properties.hpp"
#include "karts/controller/ai_properties.hpp"
#include "modes/linear_world.hpp"
#include "tracks/track.hpp"
#include "tracks/quad_graph.hpp"
#include "utils/constants.hpp"

@ -45,6 +45,7 @@
#include "modes/linear_world.hpp"
#include "race/race_manager.hpp"
#include "states_screens/race_result_gui.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@ -214,7 +215,7 @@ void EndController::handleSteering(float dt)
0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f )
{
const int next = m_next_node_index[m_track_node];
target_point = QuadGraph::get()->getQuadOfNode(next).getCenter();
target_point = QuadGraph::get()->getNode(next).getCenter();
#ifdef AI_DEBUG
Log::debug("end_controller.cpp", "- Outside of road: steer to center point.");
#endif
@ -274,7 +275,7 @@ void EndController::findNonCrashingPoint(Vec3 *result)
target_sector = m_next_node_index[sector];
//direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter()
direction = QuadGraph::get()->getNode(target_sector).getCenter()
- m_kart->getXYZ();
float len=direction.length_2d();
@ -301,7 +302,7 @@ void EndController::findNonCrashingPoint(Vec3 *result)
if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(sector).getPathWidth()*0.5f )
{
*result = QuadGraph::get()->getQuadOfNode(sector).getCenter();
*result = QuadGraph::get()->getNode(sector).getCenter();
return;
}
}

@ -224,10 +224,7 @@ void SkiddingAI::update(float dt)
// This is used to enable firing an item backwards.
m_controls->m_look_back = false;
m_controls->m_nitro = false;
//Vec3 gravity = m_kart->getBody()->getGravity();
//Log::info("Sector", "%f %f %f %d", gravity[0], gravity[1], gravity[2],m_track_node);
// Don't do anything if there is currently a kart animations shown.
if(m_kart->getKartAnimation())
return;
@ -378,7 +375,7 @@ void SkiddingAI::update(float dt)
m_controls->m_fire = true;
}
}
/*And obviously general kart stuff*/
AIBaseLapController::update(dt);
} // update
@ -481,11 +478,11 @@ void SkiddingAI::handleSteering(float dt)
if( fabsf(side_dist) >
0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f )
{
steer_angle = steerToPoint(QuadGraph::get()->getQuadOfNode(next)
steer_angle = steerToPoint(QuadGraph::get()->getNode(next)
.getCenter());
#ifdef AI_DEBUG
m_debug_sphere[0]->setPosition(QuadGraph::get()->getQuadOfNode(next)
m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next)
.getCenter().toIrrVector());
Log::debug(getControllerName().c_str(),
"Outside of road: steer to center point.");
@ -622,10 +619,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
#ifdef AI_DEBUG
m_item_sphere->setVisible(false);
#endif
// Angle of line from kart to aim_point
float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(),
aim_point->getZ()-m_kart->getXYZ().getZ());
// Angle to aim_point
Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ();
// Make sure we have a valid last_node
@ -642,9 +636,9 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
const float max_item_lookahead_distance = 30.f;
while(distance < max_item_lookahead_distance)
{
int q_index= QuadGraph::get()->getNode(node).getQuadIndex();
int n_index= QuadGraph::get()->getNode(node).getNodeIndex();
const std::vector<Item *> &items_ahead =
ItemManager::get()->getItemsInQuads(q_index);
ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++)
{
evaluateItems(items_ahead[i], kart_aim_direction,
@ -659,14 +653,9 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
m_avoid_item_close = items_to_avoid.size()>0;
core::line2df line_to_target(aim_point->getX(),
aim_point->getZ(),
m_kart->getXYZ().getX(),
m_kart->getXYZ().getZ());
core::line3df line_to_target_3d((*aim_point).toIrrVector(),
core::line3df line_to_target_3d((*aim_point).toIrrVector(),
m_kart->getXYZ().toIrrVector());
// 2) If the kart is aiming for an item, but (suddenly) detects
// some close-by items to avoid (e.g. behind the item, which was too
// far away to be considered earlier, or because the item was switched
@ -792,7 +781,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// so that it can potentially become a permanent target.
Vec3 xyz = item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node)
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)
.getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -840,7 +829,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
bool SkiddingAI::hitBadItemWhenAimAt(const Item *item,
const std::vector<const Item *> &items_to_avoid)
{
core::line3df to_item(m_kart->getXYZ().toIrrVector(),
core::line3df to_item(m_kart->getXYZ().toIrrVector(),
item->getXYZ().toIrrVector());
for(unsigned int i=0; i<items_to_avoid.size(); i++)
{
@ -873,11 +862,10 @@ bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point)
// Project the item's location onto the plane of the current quad.
// This is necessary because the kart's aim point may not be on the track
// in 3D curves. So we project the item's location onto the plane in which
// the kart is. The current quad provides a good estimate of the kart's plane.
// the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = m_item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node)
.getNormal();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -936,12 +924,9 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
// Check if we would drive left of the leftmost or right of the
// rightmost point - if so, nothing to do.
//core::vector2df left(items_to_avoid[index_left_most]->getXYZ().getX(),
// items_to_avoid[index_left_most]->getXYZ().getZ());
Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getQuadOfNode(node_index).getNormal();
Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal();
Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end;
@ -959,11 +944,9 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
}
else
{
//core::vector2df right(items_to_avoid[index_right_most]->getXYZ().getX(),
// items_to_avoid[index_right_most]->getXYZ().getZ());
Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getQuadOfNode(node_index).getNormal();
Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal();
Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end;
@ -1121,11 +1104,10 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
// the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = item->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node)
.getNormal();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
float angle_to_item = (projected_xyz - m_kart->getXYZ())
.angle(kart_aim_direction);
@ -1879,23 +1861,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
*last_node = m_next_node_index[m_track_node];
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
const Quad &q = QuadGraph::get()->getQuadOfNode(*last_node);
const GraphNode &g = QuadGraph::get()->getNode(*last_node);
// Index of the left and right end of a quad.
const unsigned int LEFT_END_POINT = 0;
const unsigned int RIGHT_END_POINT = 1;
core::line2df left (xz, q[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, q[RIGHT_END_POINT].toIrrVector2d());
core::line2df left (xz, g[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, g[RIGHT_END_POINT].toIrrVector2d());
#if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
const Vec3 eps1(0,0.5f,0);
m_curve[CURVE_LEFT]->clear();
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_LEFT]->addPoint(q[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(g[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->clear();
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(g[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
#endif
#if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
@ -1908,13 +1890,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
while(1)
{
unsigned int next_sector = m_next_node_index[*last_node];
const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector);
const GraphNode &g_next = QuadGraph::get()->getNode(next_sector);
// Test if the next left point is to the right of the left
// line. If so, a new left line is defined.
if(left.getPointOrientation(q_next[LEFT_END_POINT].toIrrVector2d())
if(left.getPointOrientation(g_next[LEFT_END_POINT].toIrrVector2d())
< 0 )
{
core::vector2df p = q_next[LEFT_END_POINT].toIrrVector2d();
core::vector2df p = g_next[LEFT_END_POINT].toIrrVector2d();
// Stop if the new point is to the right of the right line
if(right.getPointOrientation(p)<0)
break;
@ -1930,10 +1912,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// Test if new right point is to the left of the right line. If
// so, a new right line is defined.
if(right.getPointOrientation(q_next[RIGHT_END_POINT].toIrrVector2d())
if(right.getPointOrientation(g_next[RIGHT_END_POINT].toIrrVector2d())
> 0 )
{
core::vector2df p = q_next[RIGHT_END_POINT].toIrrVector2d();
core::vector2df p = g_next[RIGHT_END_POINT].toIrrVector2d();
// Break if new point is to the left of left line
if(left.getPointOrientation(p)>0)
break;
@ -1955,7 +1937,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// 0.5f*(left.end.Y+right.end.Y));
//*result = ppp;
*result = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
*result = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPointNew
//-----------------------------------------------------------------------------
@ -1992,10 +1974,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
target_sector = m_next_node_index[*last_node];
//direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter()
direction = QuadGraph::get()->getNode(target_sector).getCenter()
- m_kart->getXYZ();
float len=direction.length_2d();
float len=direction.length();
unsigned int steps = (unsigned int)( len / m_kart_length );
if( steps < 3 ) steps = 3;
@ -2024,20 +2006,28 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node).getPathWidth()*0.5f )
{
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node)
*aim_position = QuadGraph::get()->getNode(*last_node)
.getCenter();
return;
}
}
*last_node = target_sector;
} // for i<100
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
*aim_position = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPointFixed
//-----------------------------------------------------------------------------
/** This is basically the original AI algorithm. It is clearly buggy:
* 1. the test:
*
* distance + m_kart_width * 0.5f
* > QuadGraph::get()->getNode(*last_node).getPathWidth() )
*
* is incorrect, it should compare with getPathWith*0.5f (since distance
* is the distance from the center, i.e. it is half the path width if
* the point is at the edge).
* 2. the test:
*
* QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord,
* *last_node );
* in the for loop tests always against distance from the same
@ -2050,17 +2040,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
* which takes some time - so it is actually mostly on track.
* Since this algoritm (so far) ends up with by far the best AI behaviour,
* it is for now the default).
*
* GSoC 2014: This algorithm has been updated so that the AI can drive on
* upside-down tracks. Because steering only works in 2D, you can steer left and
* right but not up and down, but the track might not be 2D. So for every quad,
* we have a set of k unrolled quads starting from the current quad. The AI uses
* these unrolled quads to search for a suitable aim point.
*
* \param aim_position On exit contains the point the AI should aim at.
* \param last_node On exit contais the graph node the AI is aiming at.
*/
void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
{
#ifdef AI_DEBUG_KART_HEADING
const Vec3 eps(0,0.5f,0);
@ -2069,7 +2052,7 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
Vec3 forw(0, 0, 50);
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
#endif
*last_node = m_track_node;
*last_node = m_next_node_index[m_track_node];
float angle = QuadGraph::get()->getAngleToNext(m_track_node,
m_successor_index[m_track_node]);
int target_sector;
@ -2078,30 +2061,14 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
Vec3 step_track_coord;
float angle1;
// We need to find out if there is an alternate path that the kart might take.
// This is done in advance so that the right set of unrolled quads are used
// and the AI finds aim_points on the alternate path. future_successor_idx
// is successor index of a future node. 0 is the default, but if there is an
// alternate path coming up, this will be set to 1.
int future_successor_idx = 0;
int current = m_track_node;
for (unsigned int j = 0; j < QuadGraph::get()->getNumberOfUnrolledQuads(); j++)
{
if (m_successor_index[current] != 0)
future_successor_idx = m_successor_index[current];
current = m_next_node_index[current];
}
// This for loop runs till it runs out of unrolled quads or breaks when the
// aim point is outside one of the unrolled quads.
for(unsigned int j=0; j<QuadGraph::get()->getNumberOfUnrolledQuads(); j++)
// The original while(1) loop is replaced with a for loop to avoid
// infinite loops (which we had once or twice). Usually the number
// of iterations in the while loop is less than 7.
for(unsigned int j=0; j<100; j++)
{
// target_sector is the sector at the longest distance that we can
// drive to without crashing with the track.
target_sector = m_next_node_index[*last_node];
angle1 = QuadGraph::get()->getAngleToNext(target_sector,
m_successor_index[target_sector]);
// In very sharp turns this algorithm tends to aim at off track points,
@ -2110,17 +2077,16 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
float diff = normalizeAngle(angle1-angle);
if(fabsf(diff)>1.5f)
{
*aim_position = QuadGraph::get()->getQuadOfNode(target_sector)
.getCenter();
*aim_position = QuadGraph::get()->getNode(target_sector)
.getCenter();
return;
}
Quad target_quad_unrolled = QuadGraph::get()->getNode(m_track_node).
getUnrolledQuad(future_successor_idx,j + 1);
//direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector).getCenter()
- m_kart->getXYZ();
direction = target_quad_unrolled.getCenter() - m_kart->getXYZ();
float len = direction.length();
float len=direction.length();
unsigned int steps = (unsigned int)( len / m_kart_length );
if( steps < 3 ) steps = 3;
@ -2130,38 +2096,34 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
if( steps>1000) steps = 1000;
// Protection against having vel_normal with nan values
if(len>0.0f)
{
if(len>0.0f) {
direction*= 1.0f/len;
}
Vec3 step_coord;
//Test if we crash if we drive towards the target sector (unrolled set)
//Test if we crash if we drive towards the target sector
for(unsigned int i = 2; i < steps; ++i )
{
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrackUnrolled(&step_track_coord, step_coord,
m_track_node, j, future_successor_idx);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord,
*last_node );
float distance = step_track_coord[0];
float distance = fabsf(step_track_coord[0]);
//If we are outside, the previous node is what we are looking for
if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode((*last_node+j)%QuadGraph::get()->getNumNodes() ).getPathWidth()*0.5f )
> QuadGraph::get()->getNode(*last_node).getPathWidth() )
{
*aim_position = QuadGraph::get()->getUnrolledQuadOfNode(m_track_node,future_successor_idx,j+1)
*aim_position = QuadGraph::get()->getNode(*last_node)
.getCenter();
return;
}
}
angle = angle1;
*last_node = target_sector;
}
// If we are inside entire unrolled set then set the aim_point to be center of the last unrolled quad
*aim_position = QuadGraph::get()->getNode(m_track_node).
getUnrolledQuad(future_successor_idx,QuadGraph::get()->getNumberOfUnrolledQuads()).getCenter();
} // for i<100
*aim_position = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPoint
//-----------------------------------------------------------------------------
@ -2176,9 +2138,9 @@ void SkiddingAI::determineTrackDirection()
//float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ)
// - m_kart->getHeading();
Vec3 track_direction = -qg->getQuadOfNode(m_track_node).getCenter()
+ qg->getQuadOfNode(next).getCenter();
//Vec3 kart_direction = qg->getQuadOfNode(m_track_node).getCenter() + m_kart->getVelocity();
Vec3 track_direction = -qg->getNode(m_track_node).getCenter()
+ qg->getNode(next).getCenter();
//Vec3 kart_direction = qg->getNode(m_track_node).getCenter() + m_kart->getVelocity();
float angle_to_track = 0;
if (m_kart->getVelocity().length() > 0.0f)
@ -2203,8 +2165,6 @@ void SkiddingAI::determineTrackDirection()
return;
}
qg->getNode(next).getDirectionData(m_successor_index[next],
&m_current_track_direction,
&m_last_direction_node);
@ -2265,10 +2225,10 @@ void SkiddingAI::handleCurve()
// Pick either the lower left or right point:
int index = m_current_track_direction==GraphNode::DIR_LEFT
? 0 : 1;
float r = (m_curve_center - qg->getQuadOfNode(i)[index]).length();
float r = (m_curve_center - qg->getNode(i)[index]).length();
if(m_current_curve_radius < r)
{
last_xyz = qg->getQuadOfNode(i)[index];
last_xyz = qg->getNode(i)[index];
determineTurnRadius(xyz, tangent, last_xyz,
&m_curve_center, &m_current_curve_radius);
m_last_direction_node = i;

@ -31,15 +31,15 @@
#ifdef DEBUG
// Enable AI graphical debugging
# undef AI_DEBUG
# define AI_DEBUG
// Shows left and right lines when using new findNonCrashing function
# undef AI_DEBUG_NEW_FIND_NON_CRASHING
# define AI_DEBUG_NEW_FIND_NON_CRASHING
// Show the predicted turn circles
# undef AI_DEBUG_CIRCLES
# define AI_DEBUG_CIRCLES
// Show the heading of the kart
# undef AI_DEBUG_KART_HEADING
# define AI_DEBUG_KART_HEADING
// Shows line from kart to its aim point
# undef AI_DEBUG_KART_AIM
# define AI_DEBUG_KART_AIM
#endif

@ -484,11 +484,11 @@ void SkiddingAI::handleSteering(float dt)
if( fabsf(side_dist) >
0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f )
{
steer_angle = steerToPoint(QuadGraph::get()->getQuadOfNode(next)
steer_angle = steerToPoint(QuadGraph::get()->getNode(next)
.getCenter());
#ifdef AI_DEBUG
m_debug_sphere[0]->setPosition(QuadGraph::get()->getQuadOfNode(next)
m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next)
.getCenter().toIrrVector());
Log::debug(getControllerName().c_str(),
"Outside of road: steer to center point.");
@ -621,13 +621,12 @@ void SkiddingAI::handleSteering(float dt)
*/
void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
int last_node)
{/*
{
#ifdef AI_DEBUG
m_item_sphere->setVisible(false);
#endif
// Angle of line from kart to aim_point
float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(),
aim_point->getZ()-m_kart->getXYZ().getZ());
// Angle to aim_point
Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ();
// Make sure we have a valid last_node
if(last_node==QuadGraph::UNKNOWN_SECTOR)
@ -643,12 +642,12 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
const float max_item_lookahead_distance = 30.f;
while(distance < max_item_lookahead_distance)
{
int q_index= QuadGraph::get()->getNode(node).getQuadIndex();
int n_index= QuadGraph::get()->getNode(node).getNodeIndex();
const std::vector<Item *> &items_ahead =
ItemManager::get()->getItemsInQuads(q_index);
ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++)
{
evaluateItems(items_ahead[i], kart_aim_angle,
evaluateItems(items_ahead[i], kart_aim_direction,
&items_to_avoid, &items_to_collect);
} // for i<items_ahead;
distance += QuadGraph::get()->getDistanceToNext(node,
@ -660,10 +659,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
m_avoid_item_close = items_to_avoid.size()>0;
core::line2df line_to_target(aim_point->getX(),
aim_point->getZ(),
m_kart->getXYZ().getX(),
m_kart->getXYZ().getZ());
core::line3df line_to_target_3d((*aim_point).toIrrVector(),
m_kart->getXYZ().toIrrVector());
// 2) If the kart is aiming for an item, but (suddenly) detects
// some close-by items to avoid (e.g. behind the item, which was too
@ -676,7 +673,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
for(unsigned int i=0; i< items_to_avoid.size(); i++)
{
Vec3 d = items_to_avoid[i]->getXYZ()-m_item_to_collect->getXYZ();
if( d.length2_2d()>m_ai_properties->m_bad_item_closeness_2)
if( d.length2()>m_ai_properties->m_bad_item_closeness_2)
continue;
// It could make sense to also test if the bad item would
// actually be hit, not only if it is close (which can result
@ -696,7 +693,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// -------------------------------------
if(m_item_to_collect)
{
if(handleSelectedItem(kart_aim_angle, aim_point))
if(handleSelectedItem(kart_aim_direction, aim_point))
{
// Still aim at the previsouly selected item.
*aim_point = m_item_to_collect->getXYZ();
@ -721,7 +718,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
{
// If we need to steer to avoid an item, this takes priority,
// ignore items to collect and return the new aim_point.
if(steerToAvoid(items_to_avoid, line_to_target, aim_point))
if(steerToAvoid(items_to_avoid, line_to_target_3d, aim_point))
{
#ifdef AI_DEBUG
m_item_sphere->setVisible(true);
@ -770,7 +767,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// it's on a good enough driveline, so make this item a permanent
// target. Otherwise only try to get closer (till hopefully this
// item s on our driveline)
if(item_to_collect->hitLine(line_to_target, m_kart))
if(item_to_collect->hitLine(line_to_target_3d, m_kart))
{
#ifdef AI_DEBUG
m_item_sphere->setVisible(true);
@ -789,9 +786,15 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// Kart will not hit item, try to get closer to this item
// so that it can potentially become a permanent target.
Vec3 xyz = item_to_collect->getXYZ();
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
xyz.getZ() - m_kart->getXYZ().getZ());
float angle = normalizeAngle(kart_aim_angle - item_angle);
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)
.getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
float angle_to_item = (projected_xyz - m_kart->getXYZ())
.angle(kart_aim_direction);
float angle = normalizeAngle(angle_to_item);
if(fabsf(angle) < 0.3)
{
@ -818,7 +821,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
} // kart will not hit item
} // does hit hit bad item
} // if item to consider was found
*/
} // handleItemCollectionAndAvoidance
//-----------------------------------------------------------------------------
@ -832,13 +835,13 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
bool SkiddingAI::hitBadItemWhenAimAt(const Item *item,
const std::vector<const Item *> &items_to_avoid)
{
/* core::line2df to_item(m_kart->getXYZ().getX(), m_kart->getXYZ().getZ(),
item->getXYZ().getX(), item->getXYZ().getZ() );
core::line3df to_item(m_kart->getXYZ().toIrrVector(),
item->getXYZ().toIrrVector());
for(unsigned int i=0; i<items_to_avoid.size(); i++)
{
if(items_to_avoid[i]->hitLine(to_item, m_kart))
return true;
}*/
}
return false;
} // hitBadItemWhenAimAt
@ -854,7 +857,7 @@ bool SkiddingAI::hitBadItemWhenAimAt(const Item *item,
* \param last_node
* \return True if th AI should still aim for the pre-selected item.
*/
bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point)
bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point)
{
// If the item is unavailable keep on testing. It is not necessary
// to test if an item has turned bad, this was tested before this
@ -862,11 +865,21 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point)
if(m_item_to_collect->getDisableTime()>0)
return false;
// Project the item's location onto the plane of the current quad.
// This is necessary because the kart's aim point may not be on the track
// in 3D curves. So we project the item's location onto the plane in which
// the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = m_item_to_collect->getXYZ();
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
xyz.getZ() - m_kart->getXYZ().getZ());
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
float angle_to_item = (projected_xyz - m_kart->getXYZ())
.angle(kart_aim_direction);
float angle = normalizeAngle(angle_to_item);
float angle = normalizeAngle(kart_aim_angle - item_angle);
if(fabsf(angle)>1.5)
{
// We (likely) have passed the item we were aiming for
@ -891,10 +904,10 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point)
* \return True if steering is necessary to avoid an item.
*/
bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
const core::line2df &line_to_target,
const core::line3df &line_to_target,
Vec3 *aim_point)
{
/* // First determine the left-most and right-most item.
// First determine the left-most and right-most item.
float left_most = items_to_avoid[0]->getDistanceFromCenter();
float right_most = items_to_avoid[0]->getDistanceFromCenter();
int index_left_most = 0;
@ -917,14 +930,19 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
// Check if we would drive left of the leftmost or right of the
// rightmost point - if so, nothing to do.
core::vector2df left(items_to_avoid[index_left_most]->getXYZ().getX(),
items_to_avoid[index_left_most]->getXYZ().getZ());
Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal();
Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end;
int item_index = -1;
bool is_left = false;
// >=0 means the point is to the right of the line, or the line is
// to the left of the point.
if(line_to_target.getPointOrientation(left)>=0)
if(left.sideofPlane(p1,p2,p3) <= 0)
{
// Left of leftmost point
item_index = index_left_most;
@ -932,9 +950,14 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
}
else
{
core::vector2df right(items_to_avoid[index_right_most]->getXYZ().getX(),
items_to_avoid[index_right_most]->getXYZ().getZ());
if(line_to_target.getPointOrientation(right)<=0)
Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal();
Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end;
if (left.sideofPlane(p1, p2, p3) >= 0)
{
// Right of rightmost point
item_index = index_right_most;
@ -975,20 +998,20 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
float min_distance[2] = {99999.9f, 99999.9f};
int index[2] = {-1, -1};
core::vector2df closest2d[2];
core::vector3df closest3d[2];
for(unsigned int i=0; i<items_to_avoid.size(); i++)
{
const Vec3 &xyz = items_to_avoid[i]->getXYZ();
core::vector2df item2d = xyz.toIrrVector2d();
core::vector2df point2d = line_to_target.getClosestPoint(item2d);
float d = (xyz.toIrrVector2d() - point2d).getLengthSQ();
float direction = line_to_target.getPointOrientation(item2d);
int ind = direction<0 ? 0 : 1;
core::vector3df point3d = line_to_target.getClosestPoint(xyz.toIrrVector());
float d = (xyz.toIrrVector() - point3d).getLengthSQ();
float direction = xyz.sideofPlane(p1,p2,p3);
int ind = direction<0 ? 1 : 0;
if(d<min_distance[ind])
{
min_distance[ind] = d;
index[ind] = i;
closest2d[ind] = point2d;
closest3d[ind] = point3d;
}
}
@ -998,25 +1021,24 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
// We are driving between item_to_avoid[index[0]] and ...[1].
// If we don't hit any of them, just keep on driving as normal
bool hit_left = items_to_avoid[index[0]]->hitKart(closest2d[0], m_kart);
bool hit_right = items_to_avoid[index[1]]->hitKart(closest2d[1], m_kart);
bool hit_left = items_to_avoid[index[0]]->hitKart(closest3d[0], m_kart);
bool hit_right = items_to_avoid[index[1]]->hitKart(closest3d[1], m_kart);
if( !hit_left && !hit_right)
return false;
*/
// If we hit the left item, aim at the right avoidance point
// of the left item. We might still hit the right item ... this might
// still be better than going too far off track
//if(hit_left)
//{
// *aim_point =
// *(items_to_avoid[index[0]]->getAvoidancePoint(/*left*/false));
// return true;
//}
if(hit_left)
{
*aim_point =
*(items_to_avoid[index[0]]->getAvoidancePoint(/*left*/false));
return true;
}
// Now we must be hitting the right item, so try aiming at the left
// avoidance point of the right item.
//*aim_point = *(items_to_avoid[index[1]]->getAvoidancePoint(/*left*/true));
*aim_point = *(items_to_avoid[index[1]]->getAvoidancePoint(/*left*/true));
return true;
} // steerToAvoid
@ -1034,7 +1056,7 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
* (NULL if no item was avoided so far).
* \param item_to_collect A pointer to a previously selected item to collect.
*/
void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
std::vector<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect)
{
@ -1082,13 +1104,20 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
// to avoid are collected).
if(!avoid)
{
// item_angle The angle of the item (relative to the forward axis,
// so 0 means straight ahead in world coordinates!).
// Project the item's location onto the plane of the current quad.
// This is necessary because the kart's aim point may not be on the track
// in 3D curves. So we project the item's location onto the plane in which
// the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = item->getXYZ();
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
xyz.getZ() - m_kart->getXYZ().getZ());
Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal();
float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
float diff = normalizeAngle(kart_aim_angle-item_angle);
float angle_to_item = (projected_xyz - m_kart->getXYZ())
.angle(kart_aim_direction);
float diff = normalizeAngle(angle_to_item);
// The kart is driving at high speed, when the current max speed
// is higher than the max speed of the kart (which is caused by
@ -1117,14 +1146,14 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
else
list = items_to_collect;
float new_distance = (item->getXYZ() - m_kart->getXYZ()).length2_2d();
float new_distance = (item->getXYZ() - m_kart->getXYZ()).length2();
// This list is usually very short, so use a simple bubble sort
list->push_back(item);
int i;
for(i=(int)list->size()-2; i>=0; i--)
{
float d = ((*list)[i]->getXYZ() - m_kart->getXYZ()).length2_2d();
float d = ((*list)[i]->getXYZ() - m_kart->getXYZ()).length2();
if(d<=new_distance)
{
break;
@ -1881,23 +1910,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
*last_node = m_next_node_index[m_track_node];
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
const Quad &q = QuadGraph::get()->getQuadOfNode(*last_node);
const GraphNode &g = QuadGraph::get()->getNode(*last_node);
// Index of the left and right end of a quad.
const unsigned int LEFT_END_POINT = 0;
const unsigned int RIGHT_END_POINT = 1;
core::line2df left (xz, q[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, q[RIGHT_END_POINT].toIrrVector2d());
core::line2df left (xz, g[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, g[RIGHT_END_POINT].toIrrVector2d());
#if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
const Vec3 eps1(0,0.5f,0);
m_curve[CURVE_LEFT]->clear();
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_LEFT]->addPoint(q[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(g[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->clear();
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(g[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
#endif
#if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
@ -1910,13 +1939,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
while(1)
{
unsigned int next_sector = m_next_node_index[*last_node];
const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector);
const GraphNode &g_next = QuadGraph::get()->getNode(next_sector);
// Test if the next left point is to the right of the left
// line. If so, a new left line is defined.
if(left.getPointOrientation(q_next[LEFT_END_POINT].toIrrVector2d())
if(left.getPointOrientation(g_next[LEFT_END_POINT].toIrrVector2d())
< 0 )
{
core::vector2df p = q_next[LEFT_END_POINT].toIrrVector2d();
core::vector2df p = g_next[LEFT_END_POINT].toIrrVector2d();
// Stop if the new point is to the right of the right line
if(right.getPointOrientation(p)<0)
break;
@ -1932,10 +1961,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// Test if new right point is to the left of the right line. If
// so, a new right line is defined.
if(right.getPointOrientation(q_next[RIGHT_END_POINT].toIrrVector2d())
if(right.getPointOrientation(g_next[RIGHT_END_POINT].toIrrVector2d())
> 0 )
{
core::vector2df p = q_next[RIGHT_END_POINT].toIrrVector2d();
core::vector2df p = g_next[RIGHT_END_POINT].toIrrVector2d();
// Break if new point is to the left of left line
if(left.getPointOrientation(p)>0)
break;
@ -1957,7 +1986,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// 0.5f*(left.end.Y+right.end.Y));
//*result = ppp;
*result = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
*result = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPointNew
//-----------------------------------------------------------------------------
@ -1994,10 +2023,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
target_sector = m_next_node_index[*last_node];
//direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter()
direction = QuadGraph::get()->getNode(target_sector).getCenter()
- m_kart->getXYZ();
float len=direction.length_2d();
float len=direction.length();
unsigned int steps = (unsigned int)( len / m_kart_length );
if( steps < 3 ) steps = 3;
@ -2026,14 +2055,14 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node).getPathWidth()*0.5f )
{
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node)
*aim_position = QuadGraph::get()->getNode(*last_node)
.getCenter();
return;
}
}
*last_node = target_sector;
} // for i<100
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
*aim_position = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPointFixed
//-----------------------------------------------------------------------------
@ -2097,16 +2126,16 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
float diff = normalizeAngle(angle1-angle);
if(fabsf(diff)>1.5f)
{
*aim_position = QuadGraph::get()->getQuadOfNode(target_sector)
.getCenter();
*aim_position = QuadGraph::get()->getNode(target_sector)
.getCenter();
return;
}
//direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter()
direction = QuadGraph::get()->getNode(target_sector).getCenter()
- m_kart->getXYZ();
float len=direction.length_2d();
float len=direction.length();
unsigned int steps = (unsigned int)( len / m_kart_length );
if( steps < 3 ) steps = 3;
@ -2135,7 +2164,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node).getPathWidth() )
{
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node)
*aim_position = QuadGraph::get()->getNode(*last_node)
.getCenter();
return;
}
@ -2143,7 +2172,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
angle = angle1;
*last_node = target_sector;
} // for i<100
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
*aim_position = QuadGraph::get()->getNode(*last_node).getCenter();
} // findNonCrashingPoint
//-----------------------------------------------------------------------------
@ -2154,8 +2183,18 @@ void SkiddingAI::determineTrackDirection()
{
const QuadGraph *qg = QuadGraph::get();
unsigned int succ = m_successor_index[m_track_node];
float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ)
- m_kart->getHeading();
unsigned int next = qg->getNode(m_track_node).getSuccessor(succ);
//float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ)
// - m_kart->getHeading();
Vec3 track_direction = -qg->getNode(m_track_node).getCenter()
+ qg->getNode(next).getCenter();
//Vec3 kart_direction = qg->getNode(m_track_node).getCenter() + m_kart->getVelocity();
float angle_to_track = 0;
if (m_kart->getVelocity().length() > 0.0f)
angle_to_track = track_direction.angle(m_kart->getVelocity().normalized());
angle_to_track = normalizeAngle(angle_to_track);
// In certain circumstances (esp. S curves) it is possible that the
@ -2175,8 +2214,6 @@ void SkiddingAI::determineTrackDirection()
return;
}
unsigned int next = qg->getNode(m_track_node).getSuccessor(succ);
qg->getNode(next).getDirectionData(m_successor_index[next],
&m_current_track_direction,
&m_last_direction_node);
@ -2237,10 +2274,10 @@ void SkiddingAI::handleCurve()
// Pick either the lower left or right point:
int index = m_current_track_direction==GraphNode::DIR_LEFT
? 0 : 1;
float r = (m_curve_center - qg->getQuadOfNode(i)[index]).length();
float r = (m_curve_center - qg->getNode(i)[index]).length();
if(m_current_curve_radius < r)
{
last_xyz = qg->getQuadOfNode(i)[index];
last_xyz = qg->getNode(i)[index];
determineTurnRadius(xyz, tangent, last_xyz,
&m_curve_center, &m_current_curve_radius);
m_last_direction_node = i;

@ -66,7 +66,6 @@ namespace irr
* stage) identical to the Skidding AI.
\ingroup controller
*/
class TestAI : public AIBaseLapController
{
private:
@ -205,13 +204,13 @@ private:
void computeNearestKarts();
void handleItemCollectionAndAvoidance(Vec3 *aim_point,
int last_node);
bool handleSelectedItem(float kart_aim_angle, Vec3 *aim_point);
bool handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point);
bool steerToAvoid(const std::vector<const Item *> &items_to_avoid,
const core::line2df &line_to_target,
const core::line3df &line_to_target,
Vec3 *aim_point);
bool hitBadItemWhenAimAt(const Item *item,
const std::vector<const Item *> &items_to_avoid);
void evaluateItems(const Item *item, float kart_aim_angle,
void evaluateItems(const Item *item, Vec3 kart_aim_direction,
std::vector<const Item *> *items_to_avoid,
std::vector<const Item *> *items_to_collect);

@ -64,6 +64,8 @@
#include "physics/physics.hpp"
#include "race/history.hpp"
#include "tracks/terrain_info.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "utils/constants.hpp"
@ -1292,7 +1294,7 @@ void Kart::update(float dt)
if (QuadGraph::get())
{
sector = ((LinearWorld*)World::getWorld())->getTrackSector(getWorldKartId()).getCurrentGraphNode();
quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal();
quadNormal = QuadGraph::get()->getNode(sector).getNormal();
btQuaternion q = getTrans().getRotation();
float roll = quadNormal.angle((Vec3(0, 1, 0).rotate(q.getAxis(), q.getAngle())));
@ -1374,7 +1376,7 @@ void Kart::update(float dt)
// We do this for now because dist_to_sector is not defined
float dist_to_sector;
if (QuadGraph::get())
dist_to_sector = getXYZ().distance(QuadGraph::get()->getQuadOfNode(sector).getCenter());
dist_to_sector = getXYZ().distance(QuadGraph::get()->getNode(sector).getCenter());
else
dist_to_sector = 0;
@ -2421,7 +2423,7 @@ void Kart::updateSliding()
if (QuadGraph::get())
{
int sector = ((LinearWorld*)World::getWorld())->getTrackSector(getWorldKartId()).getCurrentGraphNode();
Vec3 quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal();
Vec3 quadNormal = QuadGraph::get()->getNode(sector).getNormal();
Vec3 kart_up = m.getColumn(1);
distanceFromUp = kart_up.dot(quadNormal);
}

@ -26,9 +26,12 @@
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/kart_properties.hpp"
#include "graphics/material.hpp"
#include "physics/physics.hpp"
#include "race/history.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track_sector.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@ -644,8 +647,8 @@ unsigned int LinearWorld::getRescuePositionIndex(AbstractKart *kart)
// ------------------------------------------------------------------------
btTransform LinearWorld::getRescueTransform(unsigned int index) const
{
const Vec3 &xyz = QuadGraph::get()->getQuadOfNode(index).getCenter();
const Vec3 &normal = QuadGraph::get()->getQuadOfNode(index).getNormal();
const Vec3 &xyz = QuadGraph::get()->getNode(index).getCenter();
const Vec3 &normal = QuadGraph::get()->getNode(index).getNormal();
btTransform pos;
pos.setOrigin(xyz);

@ -24,6 +24,7 @@
using namespace irr;
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/mesh_tools.hpp"
#include "io/file_manager.hpp"

@ -22,8 +22,10 @@
#include <string>
#include <angelscript.h>
#include <functional>
#include <map>
#include "scriptengine/script_utils.hpp"
#include "utils/no_copy.hpp"
#include "utils/ptr_vector.hpp"
class TrackObjectPresentation;

@ -1,3 +1,4 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
@ -223,7 +224,7 @@ void BattleGraph::findItemsOnGraphNodes()
for (unsigned int j = 0; j < this->getNumNodes(); ++j)
{
if (getQuadOfNode(j).pointInQuad(xyz, false))
if (getQuadOfNode(j).pointInside(xyz, false))
polygon = j;
}
@ -248,7 +249,7 @@ int BattleGraph::pointToNode(const int cur_node,
for (unsigned int node = 0; node < this->getNumNodes(); node++)
{
const Quad& quad = this->getQuadOfNode(node);
if (quad.pointInQuad(cur_point, ignore_vertical))
if (quad.pointInside(cur_point, ignore_vertical))
{
return node;
}
@ -258,7 +259,7 @@ int BattleGraph::pointToNode(const int cur_node,
{
// Check if the point is still on the same node
const Quad& cur_quad = this->getQuadOfNode(cur_node);
if (cur_quad.pointInQuad(cur_point, ignore_vertical)) return cur_node;
if (cur_quad.pointInside(cur_point, ignore_vertical)) return cur_node;
// If not then check all nearby quads (8 quads)
// Skip the same node
@ -267,7 +268,7 @@ int BattleGraph::pointToNode(const int cur_node,
{
const int test_node = m_nearby_quads[cur_node][i];
const Quad& quad = this->getQuadOfNode(test_node);
if (quad.pointInQuad(cur_point, ignore_vertical))
if (quad.pointInside(cur_point, ignore_vertical))
{
return test_node;
}
@ -465,9 +466,3 @@ void BattleGraph::set3DVerticesOfGraph(int i, video::S3DVertex *v,
{
NavMesh::get()->getQuad(i).getVertices(v, color);
} // set3DVerticesOfGraph
// ----------------------------------------------------------------------------
const bool BattleGraph::isNodeInvisible(int n) const
{
return NavMesh::get()->getQuad(n).isInvisible();
} // isNodeInvisible

@ -76,7 +76,7 @@ private:
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const
{ NavMesh::get()->getBoundingBox(min, max); }
// ------------------------------------------------------------------------
virtual const bool isNodeInvisible(int n) const;
virtual const bool isNodeInvisible(int n) const { return false; }
// ------------------------------------------------------------------------
virtual const bool hasLapLine() const
{ return false; }

@ -28,7 +28,8 @@
#include "tracks/check_lap.hpp"
#include "tracks/check_line.hpp"
#include "tracks/check_structure.hpp"
#include "tracks/track.hpp"
#include "tracks/quad_graph.hpp"
#include "utils/log.hpp"
CheckManager *CheckManager::m_check_manager = NULL;

@ -22,51 +22,44 @@
#include "io/xml_node.hpp"
#include "matrix4.h"
#include "tracks/quad_graph.hpp"
#include "tracks/quad_set.hpp"
#include "utils/log.hpp"
// ----------------------------------------------------------------------------
/** Constructor. Saves the quad index which belongs to this graph node.
* \param index Index of the quad to use for this node (in QuadSet).
*/
GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
GraphNode::GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, const Vec3 &normal,
unsigned int node_index, bool invisible,
bool ai_ignore)
:Quad(p0, p1, p2, p3)
{
if (quad_index >= QuadSet::get()->getNumberOfQuads())
Log::fatal("GraphNode", "No driveline found, or empty driveline.");
m_quad_index = quad_index;
m_invisible = invisible;
m_ai_ignore = ai_ignore;
m_normal = normal;
m_node_index = node_index;
m_distance_from_start = -1.0f;
const Quad &quad = QuadSet::get()->getQuad(m_quad_index);
// The following values should depend on the actual orientation
// of the quad. ATM we always assume that indices 0,1 are the lower end,
// and 2,3 are the upper end (or the reverse if reverse mode is selected).
// The width is the average width at the beginning and at the end.
m_right_unit_vector = ( quad[0]-quad[1]
+quad[3]-quad[2]) * 0.5f;
m_right_unit_vector = ( m_p[0]-m_p[1]
+m_p[3]-m_p[2]) * 0.5f;
m_right_unit_vector.normalize();
m_width = ( (quad[1]-quad[0]).length()
+ (quad[3]-quad[2]).length() ) * 0.5f;
m_width = ( (m_p[1]-m_p[0]).length()
+ (m_p[3]-m_p[2]).length() ) * 0.5f;
if(QuadGraph::get()->isReverse())
{
m_lower_center = (quad[2]+quad[3]) * 0.5f;
m_upper_center = (quad[0]+quad[1]) * 0.5f;
m_lower_center = (m_p[2]+m_p[3]) * 0.5f;
m_upper_center = (m_p[0]+m_p[1]) * 0.5f;
m_right_unit_vector *= -1.0f;
}
else
{
m_lower_center = (quad[0]+quad[1]) * 0.5f;
m_upper_center = (quad[2]+quad[3]) * 0.5f;
m_lower_center = (m_p[0]+m_p[1]) * 0.5f;
m_upper_center = (m_p[2]+m_p[3]) * 0.5f;
}
m_line = core::line3df(m_lower_center.toIrrVector(),
m_upper_center.toIrrVector());
// Only this 2d point is needed later
m_lower_center_2d = core::vector2df(m_lower_center.getX(),
m_lower_center.getZ() );
} // GraphNode
// ----------------------------------------------------------------------------
@ -78,28 +71,25 @@ GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
void GraphNode::addSuccessor(unsigned int to)
{
m_successor_nodes.push_back(to);
// m_quad_index is the quad index
const Quad &this_quad = QuadSet::get()->getQuad(m_quad_index);
// to is the graph node
GraphNode &gn = QuadGraph::get()->getNode(to);
const Quad &next_quad = QuadGraph::get()->getQuadOfNode(to);
GraphNode &gn_to = QuadGraph::get()->getNode(to);
// Note that the first predecessor is (because of the way the quad graph
// is exported) the most 'natural' one, i.e. the one on the main
// driveline.
gn.m_predecessor_nodes.push_back(m_node_index);
gn_to.m_predecessor_nodes.push_back(m_node_index);
Vec3 d = m_lower_center - QuadGraph::get()->getNode(to).m_lower_center;
Vec3 d = m_lower_center - gn_to.m_lower_center;
m_distance_to_next.push_back(d.length());
Vec3 diff = next_quad.getCenter() - this_quad.getCenter();
Vec3 diff = gn_to.getCenter() - getCenter();
core::CMatrix4<float> m;
m.buildRotateFromTo(this_quad.getNormal().toIrrVector(),
m.buildRotateFromTo(getNormal().toIrrVector(),
Vec3(0, 1, 0).toIrrVector());
core::vector3df diffRotated;
m.rotateVect(diffRotated, diff.toIrrVector());
m_angle_to_next.push_back(atan2(diffRotated.X, diffRotated.Z));
} // addSuccessor
@ -183,197 +173,17 @@ void GraphNode::setDirectionData(unsigned int successor, DirectionType dir,
} // setDirectionData
// ----------------------------------------------------------------------------
/** Returns the distance a point has from this quad in forward and sidewards
* direction, i.e. how far forwards the point is from the beginning of the
* quad, and how far to the side from the line connecting the center points
* is it.
* \param xyz The coordinates of the point.
* \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance.
*/
void GraphNode::getDistances(const Vec3 &xyz, Vec3 *result)
{
core::vector3df xyz_irr = xyz.toIrrVector();
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
core::vector3df normal = getQuad().getNormal().toIrrVector();
if(xyz.sideofPlane(closest, closest+normal, m_line.end)<0)
result->setX( (closest-xyz_irr).getLength()); // to the right
else
result->setX(-(closest-xyz_irr).getLength()); // to the left
result->setZ( m_distance_from_start +
(closest-m_lower_center.toIrrVector()).getLength());
} // getDistances
// ----------------------------------------------------------------------------
/** Returns the distance a point has from an unrolled quad in forward and sidewards
* direction, i.e. how far forwards the point is from the beginning of the
* quad, and how far to the side from the line connecting the center points
* is it.
* \param xyz The coordinates of the point.
* \param fork_number The fork on which the unrolled quad lies.
* \param quad_idx The index of the unrolled quad to find distances from.
* \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance.
*/
void GraphNode::getDistancesUnrolled(const Vec3 &xyz, const int fork_number, unsigned int quad_idx, Vec3 *result)
{
const Quad& unrolled = getUnrolledQuad(fork_number,quad_idx);
Vec3 upper_center, lower_center;
if (!QuadGraph::get()->isReverse())
{
upper_center = 0.5f*(unrolled[2] + unrolled[3]),
lower_center = 0.5f*(unrolled[0] + unrolled[1]);
}
else
{
upper_center = 0.5f*(unrolled[0] + unrolled[1]),
lower_center = 0.5f*(unrolled[2] + unrolled[3]);
}
// center_line is from A to B, or lower_center to upper_center
core::vector3df A = lower_center.toIrrVector(), B = upper_center.toIrrVector();
result->setX(((B - A).crossProduct(xyz.toIrrVector() - A)).getLength() / (B - A).getLength());
result->setZ(QuadGraph::get()->getNode((m_node_index + quad_idx)%QuadGraph::get()->getNumNodes()).getDistanceFromStart()
+ (xyz - lower_center).length());
} // getDistancesUnrolled
// ----------------------------------------------------------------------------
/** Returns the square of the distance between the given point and any point
* on the 'centre' line, i.e. the finite line from the middle point of the
* lower end of the quad node to the middle point of the upper end of the
* quad which belongs to this graph node. The value is computed in 2d only!
* \param xyz The point for which the distance to the line is computed.
*/
float GraphNode::getDistance2FromPoint(const Vec3 &xyz)
{
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
return (closest-xyz.toIrrVector()).getLengthSQ();
} // getDistance2FromPoint
// ----------------------------------------------------------------------------
void GraphNode::setChecklineRequirements(int latest_checkline)
{
m_checkline_requirements.push_back(latest_checkline);
}
const Vec3 GraphNode::getPointTransformedToFlatQuad(Vec3 xyz)
{
Quad thisQuad = getQuad();
core::CMatrix4<float> m;
m.buildRotateFromTo(thisQuad.getNormal().toIrrVector(), core::vector3df(0, 1, 0));
core::vector3df result;
// Translate the input point into the Quads frame of reference, then rotate
m.rotateVect(result, (xyz - thisQuad.getCenter()).toIrrVector());
return (Vec3)result;
}
} // setChecklineRequirements
// ----------------------------------------------------------------------------
/** This functions builds unrolled quads for this node. This takes into account
* if there is a fork in coming up. In this case there will be two sets of
* unrolled quads for this node. One for each fork.
* \param unroll_quad_count The length of the unrolled set of quads per node.
/** Returns true if the index-successor of this node is one that the AI
* is allowed to use.
* \param index Index of the successor.
*/
void GraphNode::buildUnrolledQuads(unsigned int unroll_quad_count)
bool GraphNode::ignoreSuccessorForAI(unsigned int i) const
{
m_unrolled_quads.clear();
unsigned int numberOfForks = 1;
GraphNode* currentNode = this;
for (unsigned i = 0; i < unroll_quad_count+1; i++)
{
unsigned int successorCount = currentNode->getNumberOfSuccessors();
if (successorCount >= 2)
{
numberOfForks = successorCount;
break;
}
else
{
currentNode = &QuadGraph::get()->getNode(currentNode->getSuccessor(0));
}
}
m_unrolled_quads.resize(numberOfForks);
for (unsigned i = 0; i < numberOfForks; i++)
{
Quad thisQuad = getQuad();
m_unrolled_quads[i].push_back(thisQuad);
GraphNode& next = QuadGraph::get()->getNode(getSuccessor(i%getNumberOfSuccessors()));
addUnrolledQuad(next , i , unroll_quad_count);
}
} // buildUnrolledQuads
// ----------------------------------------------------------------------------
/** This function is called recursively to build one set of unrolled quads. Each
* call adds one unrolled quad to the existing set.
* \param unroll_quad_count The length of the unrolled set of quads per node.
*/
void GraphNode::addUnrolledQuad(const GraphNode& next_node, int fork_number, int k)
{
if (k == 0) return;
Quad next_quad = next_node.getQuad();
Quad next_quad_to_push = next_quad.getFlattenedQuad();
Quad last_pushed_quad = m_unrolled_quads[fork_number].back();
core::CMatrix4<float> m;
core::vector3df new_points[4];
// First rotate the next_quad_to_push so that it aligns with last quad
// in the vector of unrolled quads
m.buildRotateFromTo(next_quad_to_push.getNormal().toIrrVector(),
last_pushed_quad.getNormal().toIrrVector());
for (unsigned int i = 0; i < 4; i++)
m.rotateVect(new_points[i], next_quad_to_push[i].toIrrVector());
Vec3 endEdge, beginEdge;
if (!QuadGraph::get()->isReverse())
{
endEdge = (last_pushed_quad[2] - last_pushed_quad[3]);
beginEdge = (new_points[1] - new_points[0]);
}
else
{
endEdge = (last_pushed_quad[1] - last_pushed_quad[0]);
beginEdge = (new_points[2] - new_points[3]);
}
m.buildRotateFromTo(beginEdge.toIrrVector(), endEdge.toIrrVector());
for (unsigned int i = 0; i < 4; i++)
m.rotateVect(new_points[i]);
// Next translate the new quad to be pushed to the correct position infront
// of the last quad in the vector of unrolled quads
Vec3 lower_center, upper_center;
if (!QuadGraph::get()->isReverse())
{
lower_center = 0.5f*(new_points[0] + new_points[1]);
upper_center = 0.5f*(last_pushed_quad[2] + last_pushed_quad[3]);
}
else
{
lower_center = 0.5f*(new_points[2] + new_points[3]);
upper_center = 0.5f*(last_pushed_quad[0] + last_pushed_quad[1]);
}
m.setTranslation((upper_center-lower_center).toIrrVector());
for (unsigned int i = 0; i < 4; i++)
m.translateVect(new_points[i]);
// Push the quad into the vector of unrolled quads
m_unrolled_quads[fork_number].push_back(Quad(new_points[0], new_points[1], new_points[2], new_points[3]));
k = k - 1;
// Recurisvely build the vector of unrolled quads till k reduces to 0
GraphNode& next = QuadGraph::get()->getNode(next_node.getSuccessor(fork_number%next_node.getNumberOfSuccessors()));
addUnrolledQuad(next, fork_number, k);
} // addUnrolledQuad
return QuadGraph::get()->getNode(m_successor_nodes[i]).letAIIgnore();
} // ignoreSuccessorForAI

@ -21,22 +21,14 @@
#include <vector>
#include <vector2d.h>
#include <dimension2d.h>
#include <line2d.h>
#include "tracks/quad.hpp"
#include "tracks/quad_set.hpp"
#include "utils/vec3.hpp"
class QuadGraph;
/**
* \brief This class stores a node of the graph, i.e. a list of successor
* edges.
* edges, it can either be 2d or 3d.
* \ingroup tracks
*/
class GraphNode
class GraphNode : public Quad
{
public:
/** To indiciate in which direction the track is going:
@ -44,12 +36,25 @@ public:
* AI only. */
enum DirectionType {DIR_STRAIGHT, DIR_LEFT, DIR_RIGHT,
DIR_UNDEFINED};
protected:
/** Lower center point of the graph node. */
Vec3 m_lower_center;
/** Upper center point of the graph node. */
Vec3 m_upper_center;
/** Distance from the start to the beginning of the graph node. */
float m_distance_from_start;
private:
/** Index of this node in the set of quads. Several graph nodes can use
* the same quad, meaning it is possible to use a quad more than once,
* e.g. a figure 8 like track. */
unsigned int m_quad_index;
/** Normal of the graph node */
Vec3 m_normal;
/** Set to true if this graph node should not be shown in the minimap. */
bool m_invisible;
/** Set to true if this graph node should not be used by the AI. */
bool m_ai_ignore;
/** Index of this graph node. */
unsigned int m_node_index;
@ -66,83 +71,59 @@ private:
/** The angle of the line from this node to each neighbour. */
std::vector<float> m_angle_to_next;
/** Distance from the start to the beginning of this quad. */
float m_distance_from_start;
/** Width of the track, which is the average of the width at the
* beginning and at the end. FIXME: for now the width is independent
* of the orientation (e.g. a quad used more than once might once
* be used from top to bottom, one from left to right, so it should
* have a different width then). */
float m_width;
* beginning and at the end. */
float m_width;
/** The center point of the lower two points (e.g. points 0 and 1).
* This saves some computations in getDistances later. Only the
* start point is needed, and only in 2d. */
core::vector2df m_lower_center_2d;
/** A vector from the center of the quad to the right edge. */
Vec3 m_center_to_right;
/** Lower center point of the graph node. */
Vec3 m_lower_center;
typedef std::vector<int> PathToNodeVector;
/** This vector is only used if the graph node has more than one
* successor. In this case m_path_to_node[X] will contain the index
* of the successor to use in order to reach graph node X for this
* graph nodes. */
PathToNodeVector m_path_to_node;
/** Upper center point of the graph node. */
Vec3 m_upper_center;
/** The direction for each of the successors. */
std::vector<DirectionType> m_direction;
/** A vector from the center of the quad to the right edge. */
Vec3 m_center_to_right;
/** Stores for each successor the index of the last graph node that
* has the same direction (i.e. if index 0 curves left, this vector
* will store the index of the last graph node that is still turning
* left. */
std::vector<unsigned int> m_last_index_same_direction;
/** Line between lower and upper center, saves computation in
* getDistanceFromLine() later. The line is 2d only since otherwise
* taller karts would have a larger distance from the center. It also
* saves computation, and it is only needed to determine the distance
* from the center of the drivelines anyway. */
core::line3df m_line;
typedef std::vector<int> PathToNodeVector;
/** This vector is only used if the graph node has more than one
* successor. In this case m_path_to_node[X] will contain the index
* of the successor to use in order to reach graph node X for this
* graph nodes. */
PathToNodeVector m_path_to_node;
/** The direction for each of the successors. */
std::vector<DirectionType> m_direction;
/** Stores for each successor the index of the last graph node that
* has the same direction (i.e. if index 0 curves left, this vector
* will store the index of the last graph node that is still turning
* left. */
std::vector<unsigned int> m_last_index_same_direction;
/** A unit vector pointing from the center to the right side, orthogonal
* to the driving direction. */
Vec3 m_right_unit_vector;
/** A unit vector pointing from the center to the right side, orthogonal
* to the driving direction. */
Vec3 m_right_unit_vector;
/**
* Sets of checklines you should have activated when you are driving on
* this node (there is a possibility of more than one set because of
* alternate ways)
*/
std::vector< int > m_checkline_requirements;
* Sets of checklines you should have activated when you are driving on
* this node (there is a possibility of more than one set because of
* alternate ways)
*/
std::vector< int > m_checkline_requirements;
std::vector< std::vector<Quad> >m_unrolled_quads;
void markAllSuccessorsToUse(unsigned int n,
void markAllSuccessorsToUse(unsigned int n,
PathToNodeVector *m_path_to_node);
void addUnrolledQuad(const GraphNode& next_node, int fork_number, int k);
public:
GraphNode(unsigned int quad_index, unsigned int node_index);
GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, const Vec3 &normal,
unsigned int node_index, bool invisible,
bool ai_ignore);
// ------------------------------------------------------------------------
virtual ~GraphNode() {}
// ------------------------------------------------------------------------
void addSuccessor (unsigned int to);
void getDistances(const Vec3 &xyz, Vec3 *result);
void getDistancesUnrolled(const Vec3 &xyz, const int fork_number,
unsigned int quad_idx, Vec3 *result);
float getDistance2FromPoint(const Vec3 &xyz);
// ------------------------------------------------------------------------
void setupPathsToNode();
// ------------------------------------------------------------------------
void setChecklineRequirements(int latest_checkline);
// ------------------------------------------------------------------------
void setDirectionData(unsigned int successor, DirectionType dir,
unsigned int last_node_index);
void buildUnrolledQuads(unsigned int unroll_quad_count);
// ------------------------------------------------------------------------
/** Returns the number of successors. */
unsigned int getNumberOfSuccessors() const
@ -161,23 +142,15 @@ public:
*/
int getPredecessor(unsigned int i) const {return m_predecessor_nodes[i]; }
// ------------------------------------------------------------------------
/** Returns the quad_index in the quad_set of this node. */
int getQuadIndex() const { return m_quad_index; }
/** Returns the node index of this node. */
unsigned int getNodeIndex() const { return m_node_index; }
// ------------------------------------------------------------------------
/** Returns the quad of this graph node. */
const Quad& getQuad() const {return QuadSet::get()->getQuad(m_quad_index);}
// ------------------------------------------------------------------------
/** Returns the i-th. point of a quad. ATM this just returns the vertices
* from the quads, but if necessary this method will also consider
* rotated quads. So index 0 will always be lower left point, then
* counterclockwise. */
const Vec3& operator[](int i) const
{return QuadSet::get()->getQuad(m_quad_index)[i];}
/** Returns the normal of this quad */
const Vec3& getNormal() const { return m_normal; }
// ------------------------------------------------------------------------
/** Returns the distance to the j-th. successor. */
float getDistanceToSuccessor(unsigned int j) const
{ return m_distance_to_next[j]; }
// ------------------------------------------------------------------------
/** Returns the angle from this node to the j-th. successor. */
float getAngleToSuccessor(unsigned int j) const
@ -199,21 +172,11 @@ public:
/** Returns the center point of the upper edge of this graph node. */
const Vec3& getUpperCenter() const {return m_upper_center;}
// ------------------------------------------------------------------------
/** Returns the center point of this graph node. */
const Vec3 getCenter() const
{return (m_upper_center + m_lower_center) / 2.0f;}
// ------------------------------------------------------------------------
/** Returns the length of the quad of this node. */
float getNodeLength() const
{return (m_lower_center-m_upper_center).length();}
// ------------------------------------------------------------------------
/** Returns true if the index-successor of this node is one that the AI
* is allowed to use.
* \param index Index of the successor. */
bool ignoreSuccessorForAI(unsigned int i) const
{
return QuadSet::get()->getQuad(m_successor_nodes[i]).letAIIgnore();
};
bool ignoreSuccessorForAI(unsigned int i) const;
// ------------------------------------------------------------------------
/** Returns which successor node to use in order to be able to reach the
* given node n.
@ -239,10 +202,18 @@ public:
// ------------------------------------------------------------------------
/** Returns a unit vector pointing to the right side of the quad. */
const Vec3 &getRightUnitVector() const { return m_right_unit_vector; }
// ------------------------------------------------------------------------
/** Returns true of this node is invisible, i.e. not to be shown in
* the minimap. */
bool isInvisible() const { return m_invisible; }
// ------------------------------------------------------------------------
/** True if this node should be ignored by the AI. */
bool letAIIgnore() const { return m_ai_ignore; }
// ------------------------------------------------------------------------
virtual float getDistance2FromPoint(const Vec3 &xyz) = 0;
// ------------------------------------------------------------------------
virtual void getDistances(const Vec3 &xyz, Vec3 *result) = 0;
const Vec3 getPointTransformedToFlatQuad(Vec3 xyz);
const Quad& getUnrolledQuad(int succ_idx, int i) const { return m_unrolled_quads[succ_idx][i]; }
}; // GraphNode
#endif

@ -95,6 +95,14 @@ NavMesh::NavMesh(const std::string &filename)
m_quads.push_back(new Quad(
all_vertices[quad_index[0]], all_vertices[quad_index[1]],
all_vertices[quad_index[2]], all_vertices[quad_index[3]]));
/*(AbstractNode* tn = createNode(
all_vertices[quad_index[0]], all_vertices[quad_index[1]],
all_vertices[quad_index[2]], all_vertices[quad_index[3]],false,false);
Vec3 pp(0,0,0);
tn->pointInNode(pp);*/
}
}
}

69
src/tracks/node_2d.cpp Normal file

@ -0,0 +1,69 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/node_2d.hpp"
// ----------------------------------------------------------------------------
Node2D::Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore)
: GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore)
{
m_line = core::line2df(m_upper_center.getX(), m_upper_center.getZ(),
m_lower_center.getX(), m_lower_center.getZ());
// Only this 2d point is needed later
m_lower_center_2d = core::vector2df(m_lower_center.getX(),
m_lower_center.getZ());
} // Node2D
// ----------------------------------------------------------------------------
/** Returns the distance a point has from this node in forward and sidewards
* direction, i.e. how far forwards the point is from the beginning of the
* node, and how far to the side from the line connecting the center points
* is it. All these computations are done in 2D only.
* \param xyz The coordinates of the point.
* \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance.
*/
void Node2D::getDistances(const Vec3 &xyz, Vec3 *result)
{
core::vector2df xyz2d(xyz.getX(), xyz.getZ());
core::vector2df closest = m_line.getClosestPoint(xyz2d);
if (m_line.getPointOrientation(xyz2d) > 0)
result->setX( (closest-xyz2d).getLength()); // to the right
else
result->setX(-(closest-xyz2d).getLength()); // to the left
result->setZ(m_distance_from_start +
(closest-m_lower_center_2d).getLength());
} // getDistances
// ----------------------------------------------------------------------------
/** Returns the square of the distance between the given point and any point
* on the 'centre' line, i.e. the finite line from the middle point of the
* lower end of the node to the middle point of the upper end of the node
* which belongs to this graph node. The value is computed in 2d only!
* \param xyz The point for which the distance to the line is computed.
*/
float Node2D::getDistance2FromPoint(const Vec3 &xyz)
{
core::vector2df xyz2d(xyz.getX(), xyz.getZ());
core::vector2df closest = m_line.getClosestPoint(xyz2d);
return (closest-xyz2d).getLengthSQ();
} // getDistance2FromPoint

55
src/tracks/node_2d.hpp Normal file

@ -0,0 +1,55 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_NODE_2D_HPP
#define HEADER_NODE_2D_HPP
#include "tracks/graph_node.hpp"
#include "utils/cpp2011.hpp"
#include <line2d.h>
/**
* \ingroup tracks
*/
class Node2D : public GraphNode
{
private:
/** The center point of the lower two points (e.g. points 0 and 1).
* This saves some computations in getDistances later. Only the
* start point is needed, and only in 2d. */
core::vector2df m_lower_center_2d;
/** Line between lower and upper center, saves computation in
* getDistance() later. The line is 2d only since otherwise taller karts
* would have a larger distance from the center. It also saves
* computation, and it is only needed to determine the distance from the
* center of the drivelines anyway. */
core::line2df m_line;
public:
Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore);
// ------------------------------------------------------------------------
virtual void getDistances(const Vec3 &xyz, Vec3 *result) OVERRIDE;
// ------------------------------------------------------------------------
virtual float getDistance2FromPoint(const Vec3 &xyz) OVERRIDE;
};
#endif

94
src/tracks/node_3d.cpp Normal file

@ -0,0 +1,94 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/node_3d.hpp"
// ----------------------------------------------------------------------------
Node3D::Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore)
: GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore)
{
// Compute the node bounding box used for pointInNode
Vec3 box_corners[8];
float box_high = 5.0f;
float box_low = 1.0f;
box_corners[0] = m_p[0] + box_high * normal;
box_corners[1] = m_p[1] + box_high * normal;
box_corners[2] = m_p[2] + box_high * normal;
box_corners[3] = m_p[3] + box_high * normal;
box_corners[4] = m_p[0] - box_low * normal;
box_corners[5] = m_p[1] - box_low * normal;
box_corners[6] = m_p[2] - box_low * normal;
box_corners[7] = m_p[3] - box_low * normal;
Vec3 box_faces[6][4] =
{
{ box_corners[0], box_corners[1], box_corners[2], box_corners[3] },
{ box_corners[3], box_corners[2], box_corners[6], box_corners[7] },
{ box_corners[7], box_corners[6], box_corners[5], box_corners[4] },
{ box_corners[1], box_corners[0], box_corners[4], box_corners[5] },
{ box_corners[4], box_corners[0], box_corners[3], box_corners[7] },
{ box_corners[1], box_corners[5], box_corners[6], box_corners[2] }
};
for (unsigned int i = 0; i < 6 ; i++)
{
for (unsigned int j = 0; j < 4; j++)
m_box_faces[i][j] = box_faces[i][j];
}
m_line = core::line3df(m_lower_center.toIrrVector(),
m_upper_center.toIrrVector());
} // Node3D
// ----------------------------------------------------------------------------
/** Returns the distance a point has from this node in forward and sidewards
* direction, i.e. how far forwards the point is from the beginning of the
* node, and how far to the side from the line connecting the center points
* is it.
* \param xyz The coordinates of the point.
* \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance.
*/
void Node3D::getDistances(const Vec3 &xyz, Vec3 *result)
{
core::vector3df xyz_irr = xyz.toIrrVector();
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
core::vector3df normal = getNormal().toIrrVector();
if (xyz.sideofPlane(closest, closest + normal, m_line.end) < 0)
result->setX( (closest-xyz_irr).getLength()); // to the right
else
result->setX(-(closest-xyz_irr).getLength()); // to the left
result->setZ(m_distance_from_start +
(closest-m_lower_center.toIrrVector()).getLength());
} // getDistances
// ----------------------------------------------------------------------------
/** Returns the square of the distance between the given point and any point
* on the 'centre' line, i.e. the finite line from the middle point of the
* lower end of the node to the middle point of the upper end of the node
* which belongs to this node.
* \param xyz The point for which the distance to the line is computed.
*/
float Node3D::getDistance2FromPoint(const Vec3 &xyz)
{
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
return (closest-xyz.toIrrVector()).getLengthSQ();
} // getDistance2FromPoint

64
src/tracks/node_3d.hpp Normal file

@ -0,0 +1,64 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_NODE_3D_HPP
#define HEADER_NODE_3D_HPP
#include "tracks/graph_node.hpp"
#include "utils/cpp2011.hpp"
/**
* \ingroup tracks
*/
class Node3D : public GraphNode
{
private:
/** For each node, construct a 3D box to check if a point lies inside it.
*/
Vec3 m_box_faces[6][4];
/** Line between lower and upper center, saves computation in
* getDistance() later.
*/
core::line3df m_line;
public:
Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore);
// ------------------------------------------------------------------------
virtual bool pointInside(const Vec3& p,
bool ignore_vertical = false) const OVERRIDE
{
float side = p.sideofPlane(m_box_faces[0][0], m_box_faces[0][1],
m_box_faces[0][2]);
for (int i = 1; i < 6; i++)
{
if (side * p.sideofPlane(m_box_faces[i][0], m_box_faces[i][1],
m_box_faces[i][2]) < 0)
return false;
}
return true;
}
// ------------------------------------------------------------------------
virtual void getDistances(const Vec3 &xyz, Vec3 *result) OVERRIDE;
// ------------------------------------------------------------------------
virtual float getDistance2FromPoint(const Vec3 &xyz) OVERRIDE;
};
#endif

@ -20,56 +20,21 @@
#include "utils/log.hpp"
#include <algorithm>
#include <matrix4.h>
#include <S3DVertex.h>
#include <triangle3d.h>
#include "LinearMath/btTransform.h"
/** Constructor, takes 4 points. */
Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
bool invisible, bool ai_ignore)
{
Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3)
{
m_p[0]=p0; m_p[1]=p1; m_p[2]=p2; m_p[3]=p3;
m_center = 0.25f*(p0+p1+p2+p3);
m_min_height = std::min ( std::min(p0.getY(), p1.getY()),
std::min(p2.getY(), p3.getY()) );
m_max_height = std::max ( std::max(p0.getY(), p1.getY()),
std::max(p2.getY(), p3.getY()) );
m_invisible = invisible;
m_ai_ignore = ai_ignore;
findNormal();
// Compute the quad bounding box used for pointInQuad
Vec3 boxCorners[8];
Vec3 normal = getNormal();
float boxHigh = 5.0f;
float boxLow = 1.0f;
boxCorners[0] = m_p[0] + boxHigh*normal;
boxCorners[1] = m_p[1] + boxHigh*normal;
boxCorners[2] = m_p[2] + boxHigh*normal;
boxCorners[3] = m_p[3] + boxHigh*normal;
boxCorners[4] = m_p[0] - boxLow*normal;
boxCorners[5] = m_p[1] - boxLow*normal;
boxCorners[6] = m_p[2] - boxLow*normal;
boxCorners[7] = m_p[3] - boxLow*normal;
Vec3 boxFaces[6][4] = {
{ boxCorners[0], boxCorners[1], boxCorners[2], boxCorners[3] },
{ boxCorners[3], boxCorners[2], boxCorners[6], boxCorners[7] },
{ boxCorners[7], boxCorners[6], boxCorners[5], boxCorners[4] },
{ boxCorners[1], boxCorners[0], boxCorners[4], boxCorners[5] },
{ boxCorners[4], boxCorners[0], boxCorners[3], boxCorners[7] },
{ boxCorners[1], boxCorners[5], boxCorners[6], boxCorners[2] }
};
for (unsigned int i = 0; i < 6 ; i++)
for (unsigned int j = 0; j < 4; j++)
m_box_faces[i][j] = boxFaces[i][j];
} // Quad
// ----------------------------------------------------------------------------
@ -108,7 +73,7 @@ void Quad::getVertices(video::S3DVertex *v, const video::SColor &color) const
} // setVertices
// ----------------------------------------------------------------------------
bool Quad::pointInQuad(const Vec3& p, bool ignore_vertical) const
bool Quad::pointInside(const Vec3& p, bool ignore_vertical) const
{
// In case that a kart can validly run too high over one driveline
// and it should not be considered to be on that driveline. Example:
@ -136,20 +101,7 @@ bool Quad::pointInQuad(const Vec3& p, bool ignore_vertical) const
return p.sideOfLine2D(m_p[2], m_p[3]) > 0.0 &&
p.sideOfLine2D(m_p[3], m_p[0]) >= 0.0;
}
} // pointInQuad
// ----------------------------------------------------------------------------
/** Checks if a given point p lies in the bounding box of this quad */
bool Quad::pointInQuad3D(const Vec3& p) const
{
float side = p.sideofPlane(m_box_faces[0][0], m_box_faces[0][1], m_box_faces[0][2]);
for (int i = 1; i < 6; i++)
{
if (side*p.sideofPlane(m_box_faces[i][0], m_box_faces[i][1], m_box_faces[i][2]) < 0) return false;
}
return true;
} // pointInQuad3D
} // pointInside
// ----------------------------------------------------------------------------
/** Transforms a quad by a given transform (i.e. translation+rotation). This
@ -171,36 +123,3 @@ void Quad::transform(const btTransform &t, Quad *result) const
std::min(result->m_p[2].getY(),
result->m_p[3].getY()) );
} // transform
// ----------------------------------------------------------------------------
/** Find the normal of this quad by computing the normal of two triangles and taking
* their average.
*/
void Quad::findNormal()
{
core::triangle3df tri1(m_p[0].toIrrVector(), m_p[1].toIrrVector(), m_p[2].toIrrVector());
core::triangle3df tri2(m_p[0].toIrrVector(), m_p[2].toIrrVector(), m_p[3].toIrrVector());
Vec3 normal1 = tri1.getNormal();
Vec3 normal2 = tri2.getNormal();
m_normal = -0.5f*(normal1 + normal2);
m_normal.normalize();
} // findNormal
// ----------------------------------------------------------------------------
/** Return a flattened version of this quad. */
Quad Quad::getFlattenedQuad()
{
core::CMatrix4<float> m;
m.buildRotateFromTo(m_normal.toIrrVector(), core::vector3df(0, 1, 0));
Vec3 m_p_flat[4];
for (unsigned int i = 0; i < 4; i++)
{
m.rotateVect(m_p_flat[i], (m_p[i] - m_center).toIrrVector());
m_p_flat[i].setY(0);
}
return Quad(m_p_flat[0], m_p_flat[1], m_p_flat[2], m_p_flat[3]);
} // getFlattenedQuad

@ -20,9 +20,10 @@
#define HEADER_QUAD_HPP
#include <SColor.h>
#include "utils/vec3.hpp"
#include <array>
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
namespace irr
{
@ -35,9 +36,9 @@ class btTransform;
/**
* \ingroup tracks
*/
class Quad
class Quad : public NoCopy
{
private:
protected:
/** The four points of a quad. */
Vec3 m_p[4];
@ -45,8 +46,7 @@ private:
* This saves some computations at runtime. */
Vec3 m_center;
Vec3 m_normal;
private:
/** The minimum height of the quad, used in case that several quads
* are on top of each other when determining the sector a kart is on. */
float m_min_height;
@ -55,47 +55,28 @@ private:
* to distinguish between quads which are on top of each other. */
float m_max_height;
/** Set to true if this quad should not be shown in the minimap. */
bool m_invisible;
/** Set if this quad should not be used by the AI. */
bool m_ai_ignore;
/** For each quad, construct a 3D box to check if a point lies inside it. */
Vec3 m_box_faces[6][4];
/** Find the normal of this quad */
void findNormal();
public:
Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
bool invis=false, bool ai_ignore=false);
LEAK_CHECK()
// ------------------------------------------------------------------------
Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3);
// ------------------------------------------------------------------------
virtual ~Quad() {}
// ------------------------------------------------------------------------
void getVertices(video::S3DVertex *v, const video::SColor &color) const;
bool pointInQuad(const Vec3& p, bool ignore_vertical = false) const;
bool pointInQuad3D(const Vec3& p) const;
// ------------------------------------------------------------------------
void transform(const btTransform &t, Quad *result) const;
// ------------------------------------------------------------------------
/** Returns the i-th. point of a quad. */
const Vec3& operator[](int i) const {return m_p[i]; }
const Vec3& operator[](int i) const { return m_p[i]; }
// ------------------------------------------------------------------------
/** Returns the center of a quad. */
const Vec3& getCenter () const {return m_center; }
const Vec3& getCenter () const { return m_center; }
// ------------------------------------------------------------------------
/** Returns the minimum height of a quad. */
float getMinHeight() const { return m_min_height; }
float getMinHeight() const { return m_min_height; }
// ------------------------------------------------------------------------
/** Returns true of this quad is invisible, i.e. not to be shown in
* the minimap. */
bool isInvisible() const { return m_invisible; }
// ------------------------------------------------------------------------
/** True if this quad should be ignored by the AI. */
bool letAIIgnore() const { return m_ai_ignore; }
// ------------------------------------------------------------------------
/** Returns the normal of this quad */
const Vec3& getNormal() const { return m_normal; }
// ------------------------------------------------------------------------
/** Return a flattened version of this quad */
Quad getFlattenedQuad();
virtual bool pointInside(const Vec3& p,
bool ignore_vertical = false) const;
}; // class Quad
#endif

@ -35,13 +35,47 @@
#include "tracks/check_lap.hpp"
#include "tracks/check_line.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/quad_set.hpp"
#include "tracks/node_2d.hpp"
#include "tracks/node_3d.hpp"
#include "tracks/track.hpp"
#include "graphics/glwrap.hpp"
const int QuadGraph::UNKNOWN_SECTOR = -1;
QuadGraph *QuadGraph::m_quad_graph = NULL;
/** Factory method to dynamic create 2d / 3d node */
GraphNode* createNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, unsigned int node_index,
bool invisible, bool ai_ignore)
{
// Find the normal of this node by computing the normal of two triangles
// and taking their average.
core::triangle3df tri1(p0.toIrrVector(), p1.toIrrVector(),
p2.toIrrVector());
core::triangle3df tri2(p0.toIrrVector(), p2.toIrrVector(),
p3.toIrrVector());
Vec3 normal1 = tri1.getNormal();
Vec3 normal2 = tri2.getNormal();
Vec3 normal = -0.5f * (normal1 + normal2);
normal.normalize();
// Use the angle between the normal and an up vector to choose 3d/2d node
const float angle = normal.angle(Vec3(0, 1, 0));
if (angle > 0.5f)
{
Log::debug("TrackNode", "3d node created, normal: %f, %f, %f",
normal.x(), normal.y(), normal.z());
return new Node3D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore);
}
Log::debug("TrackNode", "2d node created, normal: %f, %f, %f",
normal.x(), normal.y(), normal.z());
return new Node2D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore);
} // createNode
// ----------------------------------------------------------------------------
/** Constructor, loads the graph information for a given set of quads
* from a graph file.
* \param quad_file_name Name of the file of all quads
@ -52,20 +86,17 @@ QuadGraph::QuadGraph(const std::string &quad_file_name,
const bool reverse) : m_reverse(reverse)
{
m_lap_length = 0;
m_unroll_quad_count = 6;
QuadSet::create();
QuadSet::get()->init(quad_file_name);
m_quad_filename = quad_file_name;
m_quad_graph = this;
load(graph_file_name);
load(quad_file_name, graph_file_name);
} // QuadGraph
// -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
/** Destructor, removes all nodes of the graph. */
QuadGraph::~QuadGraph()
{
QuadSet::destroy();
for(unsigned int i=0; i<m_all_nodes.size(); i++) {
for(unsigned int i=0; i<m_all_nodes.size(); i++)
{
delete m_all_nodes[i];
}
if(UserConfigParams::m_track_debug)
@ -73,31 +104,98 @@ QuadGraph::~QuadGraph()
GraphStructure::destroyRTT();
} // ~QuadGraph
// -----------------------------------------------------------------------------
void QuadGraph::addSuccessor(unsigned int from, unsigned int to) {
// ----------------------------------------------------------------------------
void QuadGraph::addSuccessor(unsigned int from, unsigned int to)
{
if(m_reverse)
m_all_nodes[to]->addSuccessor(from);
else
m_all_nodes[from]->addSuccessor(to);
} // addSuccessor
// -----------------------------------------------------------------------------
/** Loads a quad graph from a file.
* \param filename Name of the file to load.
*/
void QuadGraph::load(const std::string &filename)
// ----------------------------------------------------------------------------
/** This function interprets a point specification as an attribute in the
xml quad file. It understands two different specifications:
p1="n:p" : get point p from square n (n, p integers)
p1="p1,p2,p3" : make a 3d point out of these 3 floating point values
*/
void QuadGraph::getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3* result) const
{
std::string s;
xml->get(attribute_name, &s);
int pos=(int)s.find_first_of(":");
if(pos>0) // n:p specification
{
std::vector<std::string> l = StringUtils::split(s, ':');
int n=atoi(l[0].c_str());
int p=atoi(l[1].c_str());
*result=(*m_all_nodes[n])[p];
}
else
{
xml->get(attribute_name, result);
}
} // getPoint
// ----------------------------------------------------------------------------
/** Loads a quad graph from a file.
* \param filename Name of the quad file to load.
* \param filename Name of the graph file to load.
*/
void QuadGraph::load(const std::string &quad_file_name,
const std::string &filename)
{
XMLNode *quad = file_manager->createXMLTree(quad_file_name);
if (!quad || quad->getName() != "quads")
{
Log::error("Quad Graph : Quad xml '%s' not found.", filename.c_str());
delete quad;
return;
}
m_min = Vec3( 99999, 99999, 99999);
m_max = Vec3(-99999, -99999, -99999);
// Each quad is part of the graph exactly once now.
for(unsigned int i=0; i<quad->getNumNodes(); i++)
{
const XMLNode *xml_node = quad->getNode(i);
if(xml_node->getName()!="quad")
{
Log::warn("Quad Graph: Unsupported node type '%s' found in '%s' - ignored.",
xml_node->getName().c_str(), filename.c_str());
continue;
}
// Note that it's not easy to do the reading of the parameters here
// in quad, since the specification in the xml can contain references
// to previous points. E.g.:
// <quad p0="40:3" p1="40:2" p2="25.396030 0.770338 64.796539" ...
Vec3 p0, p1, p2, p3;
getPoint(xml_node, "p0", &p0);
getPoint(xml_node, "p1", &p1);
getPoint(xml_node, "p2", &p2);
getPoint(xml_node, "p3", &p3);
bool invisible=false;
xml_node->get("invisible", &invisible);
bool ai_ignore=false;
xml_node->get("ai-ignore", &ai_ignore);
GraphNode* node =
createNode(p0, p1, p2, p3, m_all_nodes.size(), invisible, ai_ignore);
m_max.max(p0);m_max.max(p1);m_max.max(p2);m_max.max(p3);
m_min.min(p0);m_min.min(p1);m_min.min(p2);m_min.min(p3);
m_all_nodes.push_back(node);
}
delete quad;
const XMLNode *xml = file_manager->createXMLTree(filename);
if(!xml)
{
// No graph file exist, assume a default loop X -> X+1
// i.e. each quad is part of the graph exactly once.
// First create an empty graph node for each quad:
for(unsigned int i=0; i<QuadSet::get()->getNumberOfQuads(); i++)
m_all_nodes.push_back(new GraphNode(i, (unsigned int) m_all_nodes.size()));
// Then set the default loop:
// Set the default loop:
setDefaultSuccessors();
computeDirectionData();
@ -120,29 +218,13 @@ void QuadGraph::load(const std::string &filename)
for(unsigned int node_index=0; node_index<xml->getNumNodes(); node_index++)
{
const XMLNode *xml_node = xml->getNode(node_index);
// First graph node definitions:
// -----------------------------
// Load the definition of edges between the graph nodes:
// -----------------------------------------------------
if(xml_node->getName()=="node-list")
{
// A list of quads is connected to a list of graph nodes:
unsigned int from, to;
xml_node->get("from-quad", &from);
xml_node->get("to-quad", &to);
for(unsigned int i=from; i<=to; i++)
{
m_all_nodes.push_back(new GraphNode(i, (unsigned int) m_all_nodes.size()));
}
// Each quad is part of the graph exactly once now.
continue;
}
else if(xml_node->getName()=="node")
{
// A single quad is connected to a single graph node.
unsigned int id;
xml_node->get("quad", &id);
m_all_nodes.push_back(new GraphNode(id, (unsigned int) m_all_nodes.size()));
}
// Then the definition of edges between the graph nodes:
// -----------------------------------------------------
else if(xml_node->getName()=="edge-loop")
{
// A closed loop:
@ -202,11 +284,6 @@ void QuadGraph::load(const std::string &filename)
m_lap_length = l;
}
// Build unrolled quads
for (unsigned int i = 0; i < m_all_nodes.size(); i++)
{
m_all_nodes[i]->buildUnrolledQuads(m_unroll_quad_count);
}
} // load
// ----------------------------------------------------------------------------
@ -439,7 +516,7 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
if(current_distance<new_distance)
{
float delta = new_distance - current_distance;
updateDistancesForAllSuccessors(gn->getQuadIndex(), delta, 0);
updateDistancesForAllSuccessors(gn->getNodeIndex(), delta, 0);
}
return;
}
@ -456,7 +533,7 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
if(gn_next->getDistanceFromStart()==0)
continue;
computeDistanceFromStart(gn_next->getQuadIndex(),
computeDistanceFromStart(gn_next->getNodeIndex(),
new_distance + gn->getDistanceToSuccessor(i));
} // for i
} // computeDistanceFromStart
@ -631,21 +708,6 @@ void QuadGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz,
getNode(sector).getDistances(xyz, dst);
} // spatialToTrack
//-----------------------------------------------------------------------------
void QuadGraph::spatialToTrackUnrolled(Vec3 *dst, const Vec3& xyz,
const int parent_sector,
const int unroll_qd_idx,
const int fork_number) const
{
if (parent_sector == UNKNOWN_SECTOR)
{
Log::warn("Quad Graph", "UNKNOWN_SECTOR in spatialToTrackUnrolled().");
return;
}
getNode(parent_sector).getDistancesUnrolled(xyz, fork_number,
unroll_qd_idx, dst);
} // spatialToTrackUnrolled
//-----------------------------------------------------------------------------
/** findRoadSector returns in which sector on the road the position
* xyz is. If xyz is not on top of the road, it sets UNKNOWN_SECTOR as sector.
@ -663,7 +725,7 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector,
{
// Most likely the kart will still be on the sector it was before,
// so this simple case is tested first.
if(*sector!=UNKNOWN_SECTOR && getQuadOfNode(*sector).pointInQuad3D(xyz) )
if(*sector!=UNKNOWN_SECTOR && getNode(*sector).pointInside(xyz) )
{
return;
} // if still on same quad
@ -671,9 +733,6 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector,
// Now we search through all graph nodes, starting with
// the current one
int indx = *sector;
// This was used to check the vertical distance of kart from sector
// but because now karts are checked in a 3D space, this is not required
//float min_dist = 999999.9f;
// If a current sector is given, and max_lookahead is specify, only test
// the next max_lookahead graph nodes instead of testing the whole graph.
@ -694,13 +753,9 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector,
indx = (*all_sectors)[i];
else
indx = indx<(int)m_all_nodes.size()-1 ? indx +1 : 0;
const Quad &q = getQuadOfNode(indx);
float dist = xyz.getY() - q.getMinHeight();
// While negative distances are unlikely, we allow some small negative
// numbers in case that the kart is partly in the track.
if(q.pointInQuad3D(xyz))// && dist < min_dist && dist>-1.0f)
const GraphNode &gn = getNode(indx);
if(gn.pointInside(xyz))
{
//min_dist = dist;
*sector = indx;
}
} // for i<m_all_nodes.size()
@ -788,8 +843,8 @@ int QuadGraph::findOutOfRoadSector(const Vec3& xyz,
float dist_2 = m_all_nodes[next_sector]->getDistance2FromPoint(xyz);
if(dist_2<min_dist_2)
{
const Quad &q = getQuadOfNode(next_sector);
float dist = xyz.getY() - q.getMinHeight();
const GraphNode &gn = getNode(next_sector);
float dist = xyz.getY() - gn.getMinHeight();
// While negative distances are unlikely, we allow some small
// negative numbers in case that the kart is partly in the
// track. Only do the height test in phase==0, in phase==1
@ -809,7 +864,44 @@ int QuadGraph::findOutOfRoadSector(const Vec3& xyz,
if(min_sector==UNKNOWN_SECTOR )
{
Log::info("Quad Grap", "unknown sector found.");
Log::info("Quad Graph", "unknown sector found.");
}
return min_sector;
} // findOutOfRoadSector
//-----------------------------------------------------------------------------
void QuadGraph::set3DVerticesOfGraph(int i, video::S3DVertex *v,
const video::SColor &color) const
{
m_all_nodes[i]->getVertices(v, color);
} // set3DVerticesOfGraph
//-----------------------------------------------------------------------------
const bool QuadGraph::isNodeInvisible(int n) const
{
return m_all_nodes[n]->isInvisible();
} // isNodeInvisible
//-----------------------------------------------------------------------------
float QuadGraph::getDistanceToNext(int n, int j) const
{
return m_all_nodes[n]->getDistanceToSuccessor(j);
} // getDistanceToNext
//-----------------------------------------------------------------------------
float QuadGraph::getAngleToNext(int n, int j) const
{
return m_all_nodes[n]->getAngleToSuccessor(j);
} // getAngleToNext
//-----------------------------------------------------------------------------
int QuadGraph::getNumberOfSuccessors(int n) const
{
return m_all_nodes[n]->getNumberOfSuccessors();
} // getNumberOfSuccessors
//-----------------------------------------------------------------------------
float QuadGraph::getDistanceFromStart(int j) const
{
return m_all_nodes[j]->getDistanceFromStart();
} // getDistanceFromStart

@ -23,12 +23,13 @@
#include <string>
#include <set>
#include "tracks/graph_node.hpp"
#include "tracks/graph_structure.hpp"
#include "tracks/quad_set.hpp"
#include "utils/aligned_array.hpp"
class CheckLine;
#include "LinearMath/btTransform.h"
class GraphNode;
class XMLNode;
/**
* \brief This class stores a graph of quads. It uses a 'simplified singleton'
@ -46,6 +47,10 @@ class QuadGraph : public GraphStructure
private:
static QuadGraph *m_quad_graph;
/** The 2d bounding box, used for hashing. */
Vec3 m_min;
Vec3 m_max;
/** The actual graph data structure. */
std::vector<GraphNode*> m_all_nodes;
@ -58,9 +63,6 @@ private:
/** Wether the graph should be reverted or not */
bool m_reverse;
/** Number of unrolled quads to compute per quad */
unsigned int m_unroll_quad_count;
void setDefaultSuccessors();
void computeChecklineRequirements(GraphNode* node, int latest_checkline);
void computeDirectionData();
@ -68,7 +70,9 @@ private:
float normalizeAngle(float f);
void addSuccessor(unsigned int from, unsigned int to);
void load (const std::string &filename);
void load(const std::string &quad_file_name, const std::string &filename);
void getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3 *result) const;
void computeDistanceFromStart(unsigned int start_node, float distance);
unsigned int getStartNode() const;
QuadGraph(const std::string &quad_file_name,
@ -78,14 +82,12 @@ private:
// ------------------------------------------------------------------------
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
const video::SColor &color) const
{ m_all_nodes[i]->getQuad().getVertices(v, color); }
const video::SColor &color) const;
// ------------------------------------------------------------------------
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const
{ QuadSet::get()->getBoundingBox(min, max); }
{ *min = m_min; *max = m_max; }
// ------------------------------------------------------------------------
virtual const bool isNodeInvisible(int n) const
{ return m_all_nodes[n]->getQuad().isInvisible(); }
virtual const bool isNodeInvisible(int n) const;
// ------------------------------------------------------------------------
virtual const bool hasLapLine() const
{ return true; }
@ -101,12 +103,6 @@ public:
bool for_ai=false) const;
void spatialToTrack(Vec3 *dst, const Vec3& xyz,
const int sector) const;
void spatialToTrackUnrolled(Vec3 *dst,
const Vec3& xyz,
const int parent_sector,
const int unroll_qd_idx,
const int fork_number) const;
void findRoadSector(const Vec3& XYZ, int *sector,
std::vector<int> *all_sectors=NULL) const;
int findOutOfRoadSector(const Vec3& xyz,
@ -124,13 +120,13 @@ public:
unsigned int count);
void setupPaths();
void computeChecklineRequirements();
// ----------------------------------------------------------------------======
// ------------------------------------------------------------------------
/** Returns the one instance of this object. It is possible that there
* is no instance created (e.g. in battle mode, since it doesn't have
* a quad graph), so we don't assert that an instance exist, and we
* also don't create one if it doesn't exists. */
static QuadGraph *get() { return m_quad_graph; }
// ----------------------------------------------------------------------==
// ------------------------------------------------------------------------
/** Creates a QuadGraph instance. */
static void create(const std::string &quad_file_name,
const std::string &graph_file_name,
@ -156,45 +152,28 @@ public:
// ------------------------------------------------------------------------
/** Returns the number of nodes in the graph. */
virtual const unsigned int getNumNodes() const
{ return (unsigned int)m_all_nodes.size();}
{ return m_all_nodes.size(); }
// ------------------------------------------------------------------------
/** Return the distance to the j-th successor of node n. */
float getDistanceToNext(int n, int j) const
{ return m_all_nodes[n]->getDistanceToSuccessor(j);}
float getDistanceToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the angle of the line between node n and its j-th.
* successor. */
float getAngleToNext(int n, int j) const
{ return m_all_nodes[n]->getAngleToSuccessor(j); }
float getAngleToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the number of successors of a node n. */
int getNumberOfSuccessors(int n) const
{ return m_all_nodes[n]->getNumberOfSuccessors(); }
int getNumberOfSuccessors(int n) const;
// ------------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
const Quad& getQuadOfNode(unsigned int j) const
{ return QuadSet::get()->getQuad(m_all_nodes[j]->getQuadIndex()); }
// ------------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
GraphNode& getNode(unsigned int j) const{ return *m_all_nodes[j]; }
GraphNode& getNode(unsigned int j) const { return *m_all_nodes[j]; }
// ------------------------------------------------------------------------
/** Returns the distance from the start to the beginning of a quad. */
float getDistanceFromStart(int j) const
{ return m_all_nodes[j]->getDistanceFromStart(); }
float getDistanceFromStart(int j) const;
// ------------------------------------------------------------------------
/** Returns the length of the main driveline. */
float getLapLength() const {return m_lap_length; }
float getLapLength() const { return m_lap_length; }
// ------------------------------------------------------------------------
bool isReverse() const {return m_reverse; }
// ----------------------------------------------------------------------
/** Returns a unrolled quad of a node. */
const Quad& getUnrolledQuadOfNode(unsigned int node,
unsigned int fork_number,
unsigned int quad_number)
{ return getNode(node).getUnrolledQuad(fork_number,quad_number); }
// ----------------------------------------------------------------------
/** Returns the number of forward quads that are unrolled for each quad **/
unsigned int getNumberOfUnrolledQuads() const { return m_unroll_quad_count; }
bool isReverse() const { return m_reverse; }
}; // QuadGraph

@ -1,124 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/quad_set.hpp"
#include <stdlib.h>
#include <algorithm>
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "utils/string_utils.hpp"
QuadSet *QuadSet::m_quad_set = NULL;
/** Constructor, loads the quad set from a file. Assigns a pointer
* to this instance to m_quad_set, so that it can be accessed using get().
*/
QuadSet::QuadSet()
{
m_quad_set = this;
} // QuadSet
// -----------------------------------------------------------------------------
/** Destructor, frees all memory.
*/
QuadSet::~QuadSet()
{
for(unsigned int i=0; i<m_all_quads.size(); i++)
{
delete m_all_quads[i];
}
m_all_quads.clear();
m_quad_set = NULL;
} // ~QuadSet
// -----------------------------------------------------------------------------}
/** This function interprets a point specification as an attribute in the
xml quadset file. It understands two different specifications:
p1="n:p" : get point p from square n (n, p integers)
p1="p1,p2,p3" : make a 3d point out of these 3 floating point values
*/
void QuadSet::getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3* result) const
{
std::string s;
xml->get(attribute_name, &s);
int pos=(int)s.find_first_of(":");
if(pos>0) // n:p specification
{
std::vector<std::string> l = StringUtils::split(s, ':');
int n=atoi(l[0].c_str());
int p=atoi(l[1].c_str());
*result=(*m_all_quads[n])[p];
}
else
{
xml->get(attribute_name, result);
}
} // getPoint
// -----------------------------------------------------------------------------
/** Loads the set of all quads from the specified filename.
* \param filename The absolute filename to load the quad file from.
*/
void QuadSet::init(const std::string &filename)
{
m_min = Vec3( 99999, 99999, 99999);
m_max = Vec3(-99999, -99999, -99999);
XMLNode *xml = file_manager->createXMLTree(filename);
if(!xml || xml->getName()!="quads")
{
Log::error("[QuadSet::load] ERROR : QuadSet '%s' not found.", filename.c_str());
delete xml;
return;
}
for(unsigned int i=0; i<xml->getNumNodes(); i++)
{
const XMLNode *xml_node = xml->getNode(i);
if(xml_node->getName()!="quad")
{
Log::warn("[QuadSet::load] WARNING: Unsupported node type '%s' found in '%s' - ignored.",
xml_node->getName().c_str(), filename.c_str());
continue;
}
// Note that it's not easy to do the reading of the parameters here
// in quad, since the specification in the xml can contain references
// to previous points. E.g.:
// <quad p0="40:3" p1="40:2" p2="25.396030 0.770338 64.796539" ...
Vec3 p0, p1, p2, p3;
getPoint(xml_node, "p0", &p0);
getPoint(xml_node, "p1", &p1);
getPoint(xml_node, "p2", &p2);
getPoint(xml_node, "p3", &p3);
bool invisible=false;
xml_node->get("invisible", &invisible);
bool ai_ignore=false;
xml_node->get("ai-ignore", &ai_ignore);
Quad* q=new Quad(p0,p1,p2,p3, invisible, ai_ignore);
m_all_quads.push_back(q);
m_max.max(p0);m_max.max(p1);m_max.max(p2);m_max.max(p3);
m_min.min(p0);m_min.min(p1);m_min.min(p2);m_min.min(p3);
}
delete xml;
} // load
// -----------------------------------------------------------------------------

@ -1,90 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_QUAD_SET_HPP
#define HEADER_QUAD_SET_HPP
#include <vector>
#include <string>
#include "tracks/quad.hpp"
#include "utils/vec3.hpp"
class XMLNode;
/**
* \ingroup tracks
*/
class QuadSet
{
private:
/** The 2d bounding box, used for hashing. */
Vec3 m_min;
Vec3 m_max;
/** The list of all quads. */
std::vector<Quad*> m_all_quads;
/** Pointer to the one instance of a quad set. */
static QuadSet *m_quad_set;
void getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3 *result) const;
QuadSet();
~QuadSet();
public:
static const int QUAD_NONE=-1;
void init (const std::string &filename);
// ------------------------------------------------------------------------
/** Creates one instance of the quad set. */
static void create()
{
assert(m_quad_set==NULL);
m_quad_set = new QuadSet();
}
// ------------------------------------------------------------------------
/** Destroys the one instance of a quad set. */
static void destroy()
{
delete m_quad_set; m_quad_set = NULL;
}
// ------------------------------------------------------------------------
/** Static member function to access the QuadSet instance. */
static QuadSet *get() { return m_quad_set; }
// ------------------------------------------------------------------------
/** Returns the quad with a given index number. */
const Quad& getQuad(int n) const {return *(m_all_quads[n]); }
// ------------------------------------------------------------------------
/** Return the minimum and maximum coordinates of this quad set. */
void getBoundingBox(Vec3 *min, Vec3 *max)
{ *min=m_min; *max=m_max; }
// ------------------------------------------------------------------------
/** Returns the number of quads. */
unsigned int getNumberOfQuads() const
{return (unsigned int)m_all_quads.size(); }
// ------------------------------------------------------------------------
/** Returns the center of quad n. */
const Vec3& getCenterOfQuad(int n) const
{return m_all_quads[n]->getCenter(); }
// ------------------------------------------------------------------------
/** Returns the n-th. quad. */
const Quad& getQuad(int n) {return *(m_all_quads[n]); }
}; // QuadSet
#endif

@ -32,6 +32,7 @@
#include "graphics/glwrap.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/mesh_tools.hpp"
#include "graphics/moving_texture.hpp"
@ -54,10 +55,10 @@
#include "tracks/bezier_curve.hpp"
#include "tracks/battle_graph.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/model_definition_loader.hpp"
#include "tracks/track_manager.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/quad_set.hpp"
#include "tracks/track_object_manager.hpp"
#include "utils/constants.hpp"
#include "utils/log.hpp"
@ -2291,8 +2292,8 @@ void Track::itemCommand(const XMLNode *node)
// If a valid road_sector is not found
if (road_sector == QuadGraph::UNKNOWN_SECTOR)
road_sector = QuadGraph::get()->findOutOfRoadSector(xyz, road_sector);
Vec3 quadnormal = QuadGraph::get()->getQuadOfNode(road_sector).getNormal();
const Vec3& quadnormal = QuadGraph::get()->getNode(road_sector).getNormal();
const Material *m;
Vec3 hit_point;
m_track_mesh->castRay(loc, loc + -1.0f*quadnormal, &hit_point, &m, &normal);
@ -2384,7 +2385,7 @@ bool Track::findGround(AbstractKart *kart)
{
int sector = ((LinearWorld*)World::getWorld())->getTrackSector(kart->getWorldKartId()).getCurrentGraphNode();
if (sector != QuadGraph::UNKNOWN_SECTOR)
quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal();
quadNormal = QuadGraph::get()->getNode(sector).getNormal();
}
to = to + -1000.0f*quadNormal;
@ -2436,3 +2437,7 @@ bool Track::findGround(AbstractKart *kart)
return true;
} // findGround
float Track::getTrackLength() const {return QuadGraph::get()->getLapLength();}
float Track::getAngle(int n) const { return QuadGraph::get()->getAngleToNext(n, 0); }

@ -26,31 +26,31 @@
* objects.
*/
#include <SColor.h>
#include <string>
#include <vector>
namespace irr
{
namespace video { class ITexture; class SColor; }
namespace scene { class IMesh; class ILightSceneNode; }
namespace video { class ITexture; }
namespace scene { class IMesh; class ILightSceneNode; class ISceneNode; }
}
using namespace irr;
class ModelDefinitionLoader;
#include "LinearMath/btTransform.h"
#include "graphics/material.hpp"
#include "items/item.hpp"
#include "scriptengine/script_engine.hpp"
#include "tracks/quad_graph.hpp"
#include "utils/aligned_array.hpp"
#include "utils/translation.hpp"
#include "utils/vec3.hpp"
#include "utils/ptr_vector.hpp"
class AbstractKart;
class AnimationManager;
class BezierCurve;
class CheckManager;
class FrameBuffer;
class MovingTexture;
class MusicInformation;
class ParticleEmitter;
@ -473,8 +473,7 @@ public:
int getVersion () const {return m_version; }
// ------------------------------------------------------------------------
/** Returns the length of the main driveline. */
float getTrackLength () const
{return QuadGraph::get()->getLapLength();}
float getTrackLength () const;
// ------------------------------------------------------------------------
/** Returns a unique identifier for this track (the directory name). */
const std::string& getIdent () const {return m_ident; }
@ -511,8 +510,7 @@ public:
* in the direction of the default way on the track.
* \param n Number of the quad for which the angle is asked.
*/
float getAngle(int n) const
{ return QuadGraph::get()->getAngleToNext(n, 0); }
float getAngle(int n) const;
// ------------------------------------------------------------------------
/** Returns the 2d coordinates of a point when drawn on the mini map
* texture.

@ -20,9 +20,9 @@
#include "modes/world.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/check_structure.hpp"
#include "tracks/track.hpp"
#include "tracks/track_sector.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/graph_node.hpp"
// ----------------------------------------------------------------------------
/** Initialises the object, and sets the current graph node to be undefined.
@ -65,7 +65,7 @@ void TrackSector::update(const Vec3 &xyz)
{
// keep the current quad as the latest valid one IF the player has one
// of the required checklines
GraphNode gn = QuadGraph::get()->getNode(m_current_graph_node);
const GraphNode& gn = QuadGraph::get()->getNode(m_current_graph_node);
const std::vector<int>& checkline_requirements = gn.getChecklineRequirements();
if (checkline_requirements.size() == 0)