Esempio n. 1
0
// find shortest path from one marker to another
static BOOL FindPath(CNavigationMarker *pnmSrc, CNavigationMarker *pnmDst)
{

  ASSERT(pnmSrc!=pnmDst);
  CPathNode *ppnSrc = pnmSrc->GetPathNode();
  CPathNode *ppnDst = pnmDst->GetPathNode();

  PRINTOUT(CPrintF("--------------------\n"));
  PRINTOUT(CPrintF("FindPath(%s, %s)\n", ppnSrc->GetName(), ppnDst->GetName()));

  // start with empty open and closed lists
  ASSERT(_lhOpen.IsEmpty());
  ASSERT(_lhClosed.IsEmpty());

  // add the start node to open list
  ppnSrc->pn_fG = 0.0f;
  ppnSrc->pn_fH = NodeDistance(ppnSrc, ppnDst);
  ppnSrc->pn_fF = ppnSrc->pn_fG +ppnSrc->pn_fH;
  _lhOpen.AddTail(ppnSrc->pn_lnInOpen);
  PRINTOUT(CPrintF("StartState: %s\n", ppnSrc->GetName()));

  // while the open list is not empty
  while (!_lhOpen.IsEmpty()) {
    // get the first node from open list (that is, the one with lowest F)
    CPathNode *ppnNode = LIST_HEAD(_lhOpen, CPathNode, pn_lnInOpen);
    ppnNode->pn_lnInOpen.Remove();
      _lhClosed.AddTail(ppnNode->pn_lnInClosed);
    PRINTOUT(CPrintF("Node: %s - moved from OPEN to CLOSED\n", ppnNode->GetName()));

    // if this is the goal
    if (ppnNode==ppnDst) {
      PRINTOUT(CPrintF("PATH FOUND!\n"));
      // the path is found
      return TRUE;
    }

    // for each link of current node
    CPathNode *ppnLink = NULL;
    for(INDEX i=0; (ppnLink=ppnNode->GetLink(i))!=NULL; i++) {
      PRINTOUT(CPrintF(" Link %d: %s\n", i, ppnLink->GetName()));
      // get cost to get to this node if coming from current node
      FLOAT fNewG = ppnLink->pn_fG+NodeDistance(ppnNode, ppnLink);
      // if a shorter path already exists
      if ((ppnLink->pn_lnInOpen.IsLinked() || ppnLink->pn_lnInClosed.IsLinked()) && fNewG>=ppnLink->pn_fG) {
        PRINTOUT(CPrintF("  shorter path exists through: %s\n", ppnLink->pn_ppnParent->GetName()));
        // skip this link
        continue;
      }
      // remember this path
      ppnLink->pn_ppnParent = ppnNode;
      ppnLink->pn_fG = fNewG;
      ppnLink->pn_fH = NodeDistance(ppnLink, ppnDst);
      ppnLink->pn_fF = ppnLink->pn_fG + ppnLink->pn_fH;
      // remove from closed list, if in it
      if (ppnLink->pn_lnInClosed.IsLinked()) {
        ppnLink->pn_lnInClosed.Remove();
        PRINTOUT(CPrintF("  %s removed from CLOSED\n", ppnLink->GetName()));
      }
      // add to open if not in it
      if (!ppnLink->pn_lnInOpen.IsLinked()) {
        SortIntoOpenList(ppnLink);
        PRINTOUT(CPrintF("  %s added to OPEN\n", ppnLink->GetName()));
      }
    }
  }

  // if we get here, there is no path
  PRINTOUT(CPrintF("PATH NOT FOUND!\n"));
  return FALSE;
}
Esempio n. 2
0
bool CriticalGraph::ComputeCriticalPath(
        const CriticalNode* from,
        const CriticalNode* to,
        const std::unordered_set<uint32_t>& tids,
        CriticalPath* path) const
{
    assert(from != nullptr);
    assert(to != nullptr);
    assert(path != nullptr);

    // Topological sort.
    std::vector<const CriticalNode*> topological;
    if (!TopologicalSort(from, to, &topological)) {
        tberror() << "Destination node wasn't found in topological sort." << tbendl();
        return false;
    }

    // Compute maximum distance from destination for each node.
    std::unordered_map<const CriticalNode*, NodeDistance> distances;

    for (auto it = topological.rbegin(); it != topological.rend(); ++it)
    {
        // If the node is the destination, the distance is zero.
        if (*it == to)
        {
            distances[*it] = NodeDistance(0, kInvalidCriticalEdgeId);
            continue;
        }

        // Compute the 2 possible distances.
        size_t horizontal_distance = kHugeDistance;
        CriticalEdgeId horizontal_edge_id = (*it)->edge(kCriticalEdgeOutHorizontal);

        if (horizontal_edge_id != kInvalidCriticalEdgeId)
        {
            const auto& edge = GetEdge(horizontal_edge_id);
            auto distance_look = distances.find(edge.to());
            if (distance_look != distances.end()) {
                horizontal_distance = distance_look->second.distance;
                if (horizontal_distance != kHugeDistance)
                {
                    if (tids.find((*it)->tid()) == tids.end())
                    {
                        // Reduce the cost of edges that are on other threads.
                        horizontal_distance = std::min(horizontal_distance, static_cast<size_t>(1));
                    }
                    horizontal_distance += edge.Cost();
                }
            }
        }

        size_t vertical_distance = kHugeDistance;
        CriticalEdgeId vertical_edge_id = (*it)->edge(kCriticalEdgeOutVertical);

        if (vertical_edge_id != kInvalidCriticalEdgeId)
        {
            const auto& edge = GetEdge(vertical_edge_id);
            auto distance_look = distances.find(edge.to());
            if (distance_look != distances.end()) {
                vertical_distance = distance_look->second.distance;
                if (vertical_distance != kHugeDistance)
                    vertical_distance += edge.Cost();
            }
        }

        // Keep the maximum distance which is not invalid.
        if (horizontal_distance != kHugeDistance &&
            (vertical_distance == kHugeDistance || horizontal_distance >= vertical_distance))
        {
            distances[*it] = NodeDistance(horizontal_distance, horizontal_edge_id);
        }
        else if (vertical_distance != kHugeDistance &&
                 (horizontal_distance == kHugeDistance || vertical_distance >= horizontal_distance))
        {
            distances[*it] = NodeDistance(vertical_distance, vertical_edge_id);
        }
    }

    // Retrieve the critical path.
    const CriticalNode* cur = from;
    while (cur != to)
    {
        const NodeDistance& distance = distances[cur];
        const CriticalEdge& edge = GetEdge(distance.edge);

        if (edge.type() != CriticalEdgeType::kVertical)
        {
            path->Push(CriticalPathSegment(
                edge.from()->ts(), edge.from()->tid(), edge.type()));
        }

        cur = GetEdge(distance.edge).to();
    }

    // Restrict the critical path to the autorized threads.
    path->RestrictToThreads(tids);

    return true;
}