Example #1
0
/** Recursively determines the distance the beginning (lower end) of the quads
 *  have from the start of the track.
 *  \param node The node index for which to set the distance from start.
 *  \param new_distance The new distance for the specified graph node.
 */
void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
{
    GraphNode *gn = m_all_nodes[node];
    float current_distance = gn->getDistanceFromStart();

    // If this node already has a distance defined, check if the new distance
    // is longer, and if so adjust all following nodes. Without this the
    // length of the track (as taken by the distance from start of the last
    // node) could be smaller than some of the paths. This can result in
    // incorrect results for the arrival time estimation of the AI karts.
    // See trac #354 for details.
    // Then there is no need to test/adjust any more nodes.
    if(current_distance>=0)
    {
        if(current_distance<new_distance)
        {
            float delta = new_distance - current_distance;
            updateDistancesForAllSuccessors(gn->getQuadIndex(), delta, 0);
        }
        return;
    }

    // Otherwise this node has no distance defined yet. Set the new
    // distance, and recursively update all following nodes.
    gn->setDistanceFromStart(new_distance);

    for(unsigned int i=0; i<gn->getNumberOfSuccessors(); i++)
    {
        GraphNode *gn_next = m_all_nodes[gn->getSuccessor(i)];
        // The start node (only node with distance 0) is reached again,
        // recursion can stop now
        if(gn_next->getDistanceFromStart()==0)
            continue;

        computeDistanceFromStart(gn_next->getQuadIndex(),
                                 new_distance + gn->getDistanceToSuccessor(i));
    }   // for i
}   // computeDistanceFromStart
Example #2
0
/** Loads a quad graph from a file.
 *  \param filename Name of the file to load.
 */
void QuadGraph::load(const std::string &filename)
{
    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:
        setDefaultSuccessors();
        computeDirectionData();

        if (m_all_nodes.size() > 0)
        {
            m_lap_length = m_all_nodes[m_all_nodes.size()-1]->getDistanceFromStart()
                         + m_all_nodes[m_all_nodes.size()-1]->getDistanceToSuccessor(0);
        }
        else
        {
            Log::error("Quad Graph", "No node in driveline graph.");
            m_lap_length = 10.0f;
        }

        return;
    }

    // The graph file exist, so read it in. The graph file must first contain
    // the node definitions, before the edges can be set.
    for(unsigned int node_index=0; node_index<xml->getNumNodes(); node_index++)
    {
        const XMLNode *xml_node = xml->getNode(node_index);
        // First graph node definitions:
        // -----------------------------
        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()));
            }
        }
        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:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            for(unsigned int i=from; i<=to; i++)
            {
                assert(i!=to ? i+1 : from <m_all_nodes.size());
                addSuccessor(i,(i!=to ? i+1 : from));
                //~ m_all_nodes[i]->addSuccessor(i!=to ? i+1 : from);
            }
        }
        else if(xml_node->getName()=="edge-line")
        {
            // A line:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            for(unsigned int i=from; i<to; i++)
            {
                addSuccessor(i,i+1);
                //~ m_all_nodes[i]->addSuccessor(i+1);
            }
        }
        else if(xml_node->getName()=="edge")
        {
            // Adds a single edge to the graph:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            assert(to<m_all_nodes.size());
            addSuccessor(from,to);
            //~ m_all_nodes[from]->addSuccessor(to);
        }   // edge
        else
        {
            Log::error("Quad Graph", "Incorrect specification in '%s': '%s' ignored.",
                    filename.c_str(), xml_node->getName().c_str());
            continue;
        }   // incorrect specification
    }
    delete xml;

    setDefaultSuccessors();
    computeDistanceFromStart(getStartNode(), 0.0f);
    computeDirectionData();

    // Define the track length as the maximum at the end of a quad
    // (i.e. distance_from_start + length till successor 0).
    m_lap_length = -1;
    for(unsigned int i=0; i<m_all_nodes.size(); i++)
    {
        float l = m_all_nodes[i]->getDistanceFromStart()
                + m_all_nodes[i]->getDistanceToSuccessor(0);
        if(l > m_lap_length)
            m_lap_length = l;
    }
}   // load
Example #3
0
/** Loads a drive graph from a file.
 *  \param filename Name of the quad file to load.
 *  \param filename Name of the graph file to load.
 */
void DriveGraph::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("DriveGraph : Quad xml '%s' not found.", filename.c_str());
        delete quad;
        return;
    }

    // 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("DriveGraph: 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);

        bool ignored = false;
        std::string direction;
        xml_node->get("direction", &direction);
        if (direction == "forward" && race_manager->getReverseTrack())
        {
            ignored = true;
            invisible = true;
            ai_ignore = true;
        }
        else if (direction == "reverse" && !race_manager->getReverseTrack())
        {
            ignored = true;
            invisible = true;
            ai_ignore = true;
        }

        createQuad(p0, p1, p2, p3, m_all_nodes.size(), invisible, ai_ignore,
                   false/*is_arena*/, ignored);
    }
    delete quad;

    const XMLNode *xml = file_manager->createXMLTree(filename);

    if(!xml)
    {
        // No graph file exist, assume a default loop X -> X+1
        // Set the default loop:
        setDefaultSuccessors();
        computeDirectionData();

        if (m_all_nodes.size() > 0)
        {
            m_lap_length = getNode(m_all_nodes.size()-1)->getDistanceFromStart()
                         + getNode(m_all_nodes.size()-1)->getDistanceToSuccessor(0);
        }
        else
        {
            Log::error("DriveGraph", "No node in driveline graph.");
            m_lap_length = 10.0f;
        }

        return;
    }

    // The graph file exist, so read it in. The graph file must first contain
    // the node definitions, before the edges can be set.
    for(unsigned int node_index=0; node_index<xml->getNumNodes(); node_index++)
    {
        const XMLNode *xml_node = xml->getNode(node_index);
        // Load the definition of edges between the graph nodes:
        // -----------------------------------------------------
        if (xml_node->getName() == "node-list")
        {
            // Each quad is part of the graph exactly once now.
            unsigned int to = 0;
            xml_node->get("to-quad", &to);
            assert(to + 1 == m_all_nodes.size());
            continue;
        }
        else if(xml_node->getName()=="edge-loop")
        {
            // A closed loop:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            for(unsigned int i=from; i<=to; i++)
            {
                assert(i!=to ? i+1 : from <m_all_nodes.size());
                addSuccessor(i,(i!=to ? i+1 : from));
                //~ m_all_nodes[i]->addSuccessor(i!=to ? i+1 : from);
            }
        }
        else if(xml_node->getName()=="edge-line")
        {
            // A line:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            for(unsigned int i=from; i<to; i++)
            {
                addSuccessor(i,i+1);
                //~ m_all_nodes[i]->addSuccessor(i+1);
            }
        }
        else if(xml_node->getName()=="edge")
        {
            // Adds a single edge to the graph:
            unsigned int from, to;
            xml_node->get("from", &from);
            xml_node->get("to", &to);
            assert(to<m_all_nodes.size());
            addSuccessor(from,to);
            //~ m_all_nodes[from]->addSuccessor(to);
        }   // edge
        else
        {
            Log::error("DriveGraph", "Incorrect specification in '%s': '%s' ignored.",
                    filename.c_str(), xml_node->getName().c_str());
            continue;
        }   // incorrect specification
    }
    delete xml;

    setDefaultSuccessors();
    computeDistanceFromStart(getStartNode(), 0.0f);
    computeDirectionData();

    // Define the track length as the maximum at the end of a quad
    // (i.e. distance_from_start + length till successor 0).
    m_lap_length = -1;
    for(unsigned int i=0; i<m_all_nodes.size(); i++)
    {
        float l = getNode(i)->getDistanceFromStart()
                + getNode(i)->getDistanceToSuccessor(0);
        if(l > m_lap_length)
            m_lap_length = l;
    }

    loadBoundingBoxNodes();

}   // load