Exemplo n.º 1
0
QVariant NodeItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionHasChanged) {
        EdgeItem *edge;
        foreach(edge, inList) {
            edge->setToPoint( int(x()), int(y()) );
        }
Exemplo n.º 2
0
void MainWindow::on_actionLoad_XML_triggered()
{
    scene->clear();
    graph.clear();

    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Files (*.xml)", NULL);
    CFG cfg = parser.getCFG(fileName);

    // add all blocks
    for(Block block : cfg.getBlocks()) {
        Node* node = new Node(block.getName(), 50, 50);
        node->setX(qrand() % ((500 + 1) - (-500)) + (-500));
        node->setY(qrand() % ((500 + 1) - (-500)) + (-500));
        scene->addItem(node);
        graph.addNode(node);
    }

    // add all edges
    for(Block block : cfg.getBlocks()) {
        AbstractNode* from = graph.getNode(block.getName());
        for(QString succName : block.getSuccessors()) {
            AbstractNode* to = graph.getNode(succName);
            EdgeItem* edge = new EdgeItem(from,to,true);
            edge->adjust();
            scene->addItem(edge);
            graph.addEdge(from,to,edge);
        }
    }

    graph.setStart(graph.getNode(cfg.getStart().getName()));
}
Exemplo n.º 3
0
void MainWindow::generateRouteReport()
{
    int     totalCost = 0;
    QString route;

    // Check a route actually exists
    if (m_route.isEmpty() || !m_routeStart || !m_routeEnd) {
        postErrorMessage("Route has not been built.");
        return;
    }

    // Seed the route with the start node
    route = m_routeStart->text();

    // Iterate over the route list updating the variables above
    QListIterator<EdgeItem*> i(m_route);
    while (i.hasNext()) {
        EdgeItem* edge = i.next();

        // Add the target to the route
        route += edge->endNode()->text();

        // Update the cost
        totalCost += edge->weight();
    }

    // Print the result
    postInfoMessage(QString("Total route cost: %1").arg(totalCost));
    postInfoMessage(QString("Route taken:      %1").arg(route));
}
Exemplo n.º 4
0
void MainWindow::setHighlightPath(bool highlight)
{
    m_highlightPath = highlight;

    QListIterator<EdgeItem*> i(m_route);
    while (i.hasNext()) {
        EdgeItem* edge = i.next();
        edge->setEmphasised(highlight);
    }
}
Exemplo n.º 5
0
QVariant NodeItem::itemChange(QGraphicsItem::GraphicsItemChange change,
    const QVariant& value)
{
    if (change == QGraphicsItem::ItemPositionHasChanged) {
        QListIterator<EdgeItem*> i(m_edges);
        while (i.hasNext()) {
            EdgeItem* edge = i.next();
            edge->adjust();
        }
    }

    return QGraphicsItem::itemChange(change, value);
}
Exemplo n.º 6
0
void Graph::reverseEdge(AbstractNode *from, AbstractNode *to)
{
    from->removeSuccessor(to);
    to->removePredecessor(from);
    from->addPredecessor(to);
    to->addSuccessor(from);

    QPair<AbstractNode*, AbstractNode*> pair(from,to);
    EdgeItem* edge = edges.value(pair);
    edge->reverse();
    edges.remove(pair);

    //add it to the set of reversed edges
    QPair<AbstractNode*, AbstractNode*> pairReversed(to,from);
    reversedEdges.insert(pairReversed,edge);
}
Exemplo n.º 7
0
void NodeItem::moveBy(double dx, double dy)
{
    QCanvasEllipse::moveBy( dx, dy ); // 使用父類別的moveBy函數

    QPtrListIterator<EdgeItem> it1( inList ); // 設定it1為指到QPtrList的指標變數
    EdgeItem *edge;
    // 若it1指到的位置存放的EdgeItem的指標不是0時,則執行大括號內的指令,直到edge為空指標
    while (( edge = it1.current() )) { 
	++it1;
	edge->setToPoint( int(x()), int(y()) );
    }
    QPtrListIterator<EdgeItem> it2( outList );
    while (( edge = it2.current() )) {
	++it2;
	edge->setFromPoint( int(x()), int(y()) );
    }
}
Exemplo n.º 8
0
QVariant NodeItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionHasChanged) {
        Q3PtrListIterator<EdgeItem> it1( inList );
        EdgeItem *edge;
        while (( edge = it1.current() )) {
            ++it1;
            edge->setToPoint( int(x()), int(y()) );
        }
        Q3PtrListIterator<EdgeItem> it2( outList );
        while (( edge = it2.current() )) {
            ++it2;
            edge->setFromPoint( int(x()), int(y()) );
        }
    }

    return QGraphicsEllipseItem::itemChange(change, value);
}
Exemplo n.º 9
0
void GraphEditor::load(bool initgrid) 
// by default initgrid = true
// when editing (erasing edges, vertices,reorienting) initgrid = false
  {
  if(!is_init) //MAC
    {gwp->canvas->setSceneRect(0,0,contentsRect().width(),contentsRect().height());
    is_init=true;
    }
  //if(!is_init)return;
  clear();// delete all items
  if(gwp->pGG->nv() > staticData::MaxND)
      {Tprintf("Too big graph nv= %d (>%d)",gwp->pGG->nv(),staticData::MaxND);return;}
  GeometricGraph & G = *(gwp->pGG);

  if(initgrid)
      {Normalise();
      InitGrid(current_grid);
      }
  DrawGrid(current_grid);
  if(ShowGrid)showGrid(true);

  Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM,(NodeItem *)NULL);
  Prop<EdgeItem *> edgeitem(G.Set(tedge()),PROP_CANVAS_ITEM,(EdgeItem *)NULL);
  nodeitem.SetName("nodeitem");edgeitem.SetName("edgeitem");

  for(tvertex v = 1;v <= G.nv();v++)
      nodeitem[v] =  CreateNodeItem(v,gwp);
  for(tedge e = 1;e <= G.ne();e++)
      edgeitem[e] = CreateEdgeItem(e,gwp); 

  if(staticData::ShowExtTbrin())
      {tedge e = G.extbrin().GetEdge();
      EdgeItem *edge = (G.extbrin() > 0) ? edgeitem[e]  : edgeitem[e]->opp;
      edge->SetColor(color[Green],false);
      } 

  Prop<bool> eoriented(G.Set(tedge()),PROP_ORIENTED,false);
  CreateColorItems(gwp,color_node,color_edge);
  G.vcolor.definit(color_node);
  G.vlabel.definit(0L);
  G.elabel.definit(0L);
  CreateThickItems(gwp,width_edge);
  G.ewidth.definit(width_edge);
  }
Exemplo n.º 10
0
void GraphEditor::mousePressEvent(QMouseEvent* e)
  {GeometricGraph & G = *(gwp->pGG);
  QPoint p((int)e->pos().x(),(int)e->pos().y());
  setFocus(); // as we might loose the focus
  ColorItem *coloritem;
  if(FindItem(p,coloritem) != 0)
      {if(e->button() == Qt::LeftButton)
          {if(coloritem->node)
              {gwp->NodeColorItem[color_node]->SetPenColor(White);
              coloritem->SetPenColor(coloritem->brush_color);
              color_node = coloritem->brush_color;
              G.vcolor.definit(color_node);
              }
          else
              {gwp->EdgeColorItem[color_edge]->SetPenColor(White);
              coloritem->SetPenColor(coloritem->brush_color);
              color_edge = coloritem->brush_color;
              G.ecolor.definit(color_edge);
              }
          return;
          }
      else if(e->button() == Qt::RightButton)
          {QString t;
          if(coloritem->node)
              t.sprintf("Vertex color:%s",ColorName[coloritem->brush_color]);
          else
              t.sprintf("Edge color:%s",ColorName[coloritem->brush_color]);
          gwp->info_item = CreateInfoItem(gwp,t,p);
          setCursor(QCursor(Qt::WhatsThisCursor));
          return;
          }
      }
  ThickItem *thickitem;
  if(FindItem(p,thickitem) != 0)
      {if(e->button() == Qt::LeftButton)
          {gwp->EdgeThickItem[width_edge]->SetBrushColor(White);
          thickitem->SetBrushColor(Yellow);
          width_edge = thickitem->width;
          G.ewidth.definit(width_edge);
          return;
          }
      else if(e->button() == Qt::RightButton)
          {QString t;
          t.sprintf("Edge width:%d",thickitem->width);
          gwp->info_item = CreateInfoItem(gwp,t,p);
          setCursor(QCursor(Qt::WhatsThisCursor));
          return;
          }
      }
  if(e->button() == Qt::RightButton )
      {NodeItem* node;
      EdgeItem *edge;
      QString t;
      int rtt = FindItem(p,node,edge);
      if(rtt == 0)rtt = FindItem(p,edge);//augment the collision zone
      if(rtt == node_rtti)
          if (G.Set().exist(PROP_VSLABEL) && G.Set(tvertex()).exist(PROP_SLABEL))
              {QString tt;
              Prop1<svector<tstring *> >vslabel(G.Set(),PROP_VSLABEL);
              Prop<int> slabel(G.Set(tvertex()),PROP_SLABEL,0);
              if (vslabel()[slabel[node->v]]==(tstring *)0) tt="(null)";
              else tt=~(*(vslabel()[slabel[node->v]]));
              t.sprintf("vertex:%d Label:%d (%s)",(node->v)(),G.vlabel[node->v],(const char *)tt.toLatin1());
              }
          else
              t.sprintf("vertex:%d Label:%d",(node->v)(),G.vlabel[node->v]);
      else if(rtt == edge_rtti)
          {double d = Distance(G.vcoord[G.vin[edge->e]],G.vcoord[G.vin[-(edge->e)]])+.5;
          t.sprintf("edge:%d Label:%d len:%d",(edge->e)(),G.elabel[edge->e],(int)d);
          }
      else
          {t.sprintf("(%d,%d)",(int)e->pos().x(),(int)e->pos().y());
          setCursor(QCursor(Qt::BlankCursor));
          }
      gwp->info_item = CreateInfoItem(gwp,t,p);
      return;
      }
  //GetMouseAction_1 returns the active radio button (0,5)
  int MouseAction = GetMouseAction_1();
  bool Shift    =  e->modifiers() == Qt::ShiftModifier;
  bool Control  =  e->modifiers() ==  Qt::ControlModifier;
  bool SControl =  e->modifiers() ==  (Qt::ShiftModifier | Qt::ControlModifier);

  if(e->button() == Qt::MidButton) //move
      MouseAction = (Shift) ? -3 : 3;
  else if(Shift && MouseAction == 1)        //add
      MouseAction = -1;                     // delete vertex or edge
  else if(Control && MouseAction == 1)
      MouseAction = 10;                     //duplicate graph
  else if(SControl && MouseAction == 1)
      MouseAction = 11;                     //duplicate +
  else if(Shift && MouseAction == 2)        //Orient or reorient if oriented
      MouseAction = -2;                     //disorient
  else if(Shift && MouseAction == 3)        //move vertices
      MouseAction = -3;                     //move colored vertices
  else if(Shift && MouseAction == 4)        //bissect
      MouseAction = -4;                     //contract
  else if(Shift && MouseAction == 5)        //define exterior face
      MouseAction = -5;                     //define extbrin
  else if(Shift && MouseAction == 6)        //define a label
      MouseAction = -6;                     //reset all labels to indices
  
  if(MouseAction == 0) // color
      {NodeItem* node;
      EdgeItem *edge;
      int rtt = FindItem(p,node,edge);
      if(rtt == 0) //augment the collision zone
          {rtt = FindItem(p,edge);
          if(rtt == 0)return;
          } 
      if(rtt == node_rtti)
          {mywindow->UndoTouch(false);
          G.vcolor[node->v] = color_node;
          node->SetColor(color[color_node]);
          }
      else if(rtt == edge_rtti)
          {mywindow->UndoTouch(false);
          G.ecolor[edge->e] = color_edge;
          G.ewidth[edge->e]  = width_edge;
          if(edge->lower) edge->SetColor(color[color_edge]);
          else edge->opp->SetColor(color[color_edge]);
          }
      return; 
      }
  else if(MouseAction == 1) // Start create an edge
      {mywindow->UndoTouch(false);
      Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      NodeItem* node;
      EdgeItem *edge;
      tvertex v;
      int h = (int)gwp->canvas->height();
      int rtt = FindItem(p,node,edge);
      if(rtt != node_rtti)// add a vertex
          {Tpoint pp((double)p.x(),(double)(h - p.y()));
          v = G.NewVertex(pp);
          ToGrid(v);
          nodeitem[v] = node  = CreateNodeItem(v,gwp);
          mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
          }
      else
          v = node->v;
      start_position = QPoint((int)G.vcoord[v].x(),h-(int)G.vcoord[v].y());
      node->SetColor(Qt::red);
      gwp->curs_item = new CursItem(v,start_position,gwp);
      }
  else if(MouseAction == -1) // Delete
      {NodeItem* node;
      EdgeItem *edge;
      int rtt = FindItem(p,node,edge);
      if(rtt == 0) //augment the collision zone
          {rtt = FindItem(p,edge);
          if(rtt == 0)return;
          } 
      if(rtt == node_rtti)
          {mywindow->UndoTouch(true);
          G.DeleteVertex(node->v);
          mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
          }
      else
          {mywindow->UndoTouch(true);
          G.DeleteEdge(edge->e);
          }
      load(false);
      mywindow->information();// Informations
      PrintSizeGrid();
      return;
      }
  else if(MouseAction == 3) // Start moving a vertex
      {NodeItem* node;
      EdgeItem *edge;
      int rtt = FindItem(p,node,edge);
      if(rtt != node_rtti)return;
      mywindow->UndoTouch(false);
      gwp->moving_item = node;
      start_position = p;
      return;
      }
  else if(MouseAction == -3) // Start moving a subgraph
      {mywindow->UndoTouch(false);
      gwp->moving_subgraph = true;
      start_position = p;
      return;
      }
  else if(MouseAction == 4) // Bissect an edge
      {mywindow->UndoTouch(true);
      if(FitToGrid)//and we are sure that ButtonFitGrid exists
	  mywindow->mouse_actions->ButtonFitGrid->setChecked(false);
      mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
      EdgeItem *edge;
      int rtt = FindItem(p,edge);
      if(rtt != edge_rtti)return;
      G.BissectEdge(edge->e);
      DoNormalise = false;
      load(true);
      DoNormalise = true;
      mywindow->information();// Informations
      return;
      }
  else if(MouseAction == -4) // Contract an edge
      {EdgeItem *edge;
      int rtt = FindItem(p,edge);
      if(rtt != edge_rtti)return;
      mywindow->UndoTouch(true);
      // provisoire
      if(edge->lower)G.ReverseEdge(edge->e);
      // end provisoire
      G.ContractEdge(edge->e);
      load(false);
      mywindow->information();// Informations
      return;
      }
  else if(MouseAction == 5) // Color Exterior face
      {GeometricGraph & G = *(gwp->pGG);
      Prop<EdgeItem *> edgeitem(G.Set(tedge()),PROP_CANVAS_ITEM);
      Tpoint pp((double)p.x(),(double)(gwp->canvas->height()-p.y()));
      if(G.FindExteriorFace(pp) == 0)return;
      //ColorExteriorface
      tedge e;
      ForAllEdges(e,G)edgeitem[e]->SetColor(color[color_edge]);
      tbrin b0 = G.extbrin();
      tbrin b = b0;
      do
          {e = b.GetEdge();
          edgeitem[e]->SetColor(color[Red]);
          } while((b = G.cir[-b]) != b0);
      if(b0() > 0)
          edgeitem[b0.GetEdge()]->SetColor(color[Green],false);
      else
          edgeitem[b0.GetEdge()]->opp->SetColor(color[Green],false);
      return; 	  
      }
  else if(MouseAction == -5) // Define Extbrin
      {EdgeItem *edge;
      int rtt = FindItem(p,edge);
      if(rtt != edge_rtti)return;
      Prop<EdgeItem *> edgeitem(G.Set(tedge()),PROP_CANVAS_ITEM);
      tedge je;
      ForAllEdges(je,G)edgeitem[je]->SetColor(color[color_edge]);
      GeometricGraph & G = *(gwp->pGG);
      je = edge->e;
      //       Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      //       NodeItem *n1 =  nodeitem[G.vin[je]];   Tpoint p1(n1->x(),n1->y());
      //       NodeItem *n2 =  nodeitem[G.vin[-je]];  Tpoint p2(n2->x(),n2->y());
      //       Tpoint pp((double)p.x(),(double)p.y());
      //       G.extbrin() = (Distance2(pp,p1) < Distance2(pp,p2)) ? je.firsttbrin() : je.secondtbrin();
      G.extbrin() = (edge->lower ) ? je.firsttbrin() : je.secondtbrin();
      edge->SetColor(color[Green],false);
      return;
      }
  else if(MouseAction == 6) // Modify label
      {NodeItem* node;
      EdgeItem *edge;
      int rtt = FindItem(p,node,edge);
      if(rtt != node_rtti)return;
      tvertex v = node->v;
      bool ok;
      //int res = QInputDialog::getInteger(this,"Pigale","Enter a number:",(int)G.vlabel[node->v],0,2147483647,1,&ok);
      int res = QInputDialog::getInt(this,"Pigale","Enter a number:",(int)G.vlabel[node->v],0,2147483647,1,&ok);
      if(!ok)return;
      G.vlabel[node->v] = res;
      QString t = getVertexLabel(G.Container(),v);
      node->SetText(t);
      return;
      }
  else if(MouseAction == -6) // Reset all labels
      {Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      for(tvertex v = 1; v <= G.nv();v++)
          {G.vlabel[v] = v();
          nodeitem[v]->SetText(QString("%1").arg(v()));
          }
      for(tedge e = 1; e <= G.ne();e++)
          G.elabel[e] = e();
      }
  else if(MouseAction == 2  || MouseAction == -2) // Orient/Reverse or deorient
      {Prop<bool> eoriented(G.Set(tedge()),PROP_ORIENTED,false);
      Prop<bool> reoriented(G.Set(tedge()),PROP_REORIENTED); 
      Prop<EdgeItem *> edgeitem(G.Set(tedge()),PROP_CANVAS_ITEM);
      mywindow->setShowOrientation(true);
      EdgeItem *edge;
      int rtt = FindItem(p,edge);
      if(rtt != edge_rtti)return;
      mywindow->UndoTouch(true);
      if(MouseAction == 2)
          {if(eoriented[edge->e])
              {G.ReverseEdge(edge->e); eoriented[edge->e] = true;
              reoriented[edge->e] = false;
              edgeitem[edge->e] = CreateEdgeItem(edge->e,gwp); 
	      if(edge->arrow)
                  scene()->removeItem(edge->arrow);
	      else 
                  scene()->removeItem(edge->opp->arrow);
	      scene()->removeItem(edge->opp);scene()->removeItem(edge);
              mywindow->information();// Informations
              return;
              }
          else
              {eoriented[edge->e] = true;
	      if(edge->lower)
                  {G.ReverseEdge(edge->e);reoriented[edge->e] = false;}
	      edgeitem[edge->e] = CreateEdgeItem(edge->e,gwp);
	      if(edge->arrow)
                  scene()->removeItem(edge->arrow);
	      else 
                  scene()->removeItem(edge->opp->arrow);
	      scene()->removeItem(edge->opp);scene()->removeItem(edge);
              mywindow->information();// Informations
              return;
              }
          }
      else
          {eoriented[edge->e] = false;
	  edgeitem[edge->e] = CreateEdgeItem(edge->e,gwp); 
          if(edge->arrow)
              scene()->removeItem(edge->arrow);
          else 
              scene()->removeItem(edge->opp->arrow);
	  scene()->removeItem(edge->opp);scene()->removeItem(edge);
          mywindow->information();// Informations
          return;
          }
      }
  else if(MouseAction == 10)// Duplicate the sugraph of the current color
      {mywindow->UndoTouch(true);
      if(FitToGrid)//and we are sure that ButtonFitGrid exists
          mywindow->mouse_actions->ButtonFitGrid->setChecked(false);
      mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
      short vcol=0;  G.vcolor.getinit(vcol);
      G.vcolor.definit((short)((vcol+1)%16));
      GeometricGraph & G = *(gwp->pGG);
      Tpoint translate(this->width()/2.,0);
      int n = G.nv();
      svector<tvertex> newvertex(1,n);
      tvertex v;
      for(v = 1; v <= n;v++)//translate all the graph
          G.vcoord[v] /= 2.;
      for(v = 1; v <= n;v++)
          {if(G.vcolor[v] != vcol)continue;
          newvertex[v] = G.NewVertex(G.vcoord[v] + translate);
          }
      int m = G.ne();
      tvertex v1,v2;
      for(tedge e = 1; e <= m;e++)
          {v1 = G.vin[e];v2 = G.vin[-e];
          if(G.vcolor[v1] == vcol && G.vcolor[v2] == vcol)
              G.NewEdge(newvertex[v1],newvertex[v2]);
          }
      load(true);
      mywindow->information();// Informations
      }
  else if(MouseAction == 11)
      //Duplicate the sugraph of the current color
      // and add edges between a new vertex and its father
      {mywindow->UndoTouch(true);
      if(FitToGrid)//and we are sure that ButtonFitGrid exists
          mywindow->mouse_actions->ButtonFitGrid->setChecked(false);
      mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
      mywindow->mouse_actions->ButtonFitGrid->setChecked(false);
      short vcol=0;  G.vcolor.getinit(vcol);
      G.vcolor.definit((short)((vcol+1)%16));
      GeometricGraph & G = *(gwp->pGG);
      Tpoint translate(this->width()/2.,0);
      int n = G.nv();
      svector<tvertex> newvertex(1,n);
      tvertex v;
      for(v = 1; v <= n;v++)//translate all the graph
          G.vcoord[v] /= 2.;
      for(v = 1; v <= n;v++)
          {if(G.vcolor[v] != vcol)continue;
          newvertex[v] = G.NewVertex(G.vcoord[v] + translate);
          }
      int m = G.ne();
      tvertex v1,v2;
      for(tedge e = 1; e <= m;e++)
          {v1 = G.vin[e];v2 = G.vin[-e];
          if(G.vcolor[v1] == vcol && G.vcolor[v2] == vcol)
              G.NewEdge(newvertex[v1],newvertex[v2]);
          }
      for(v = 1; v <= n;v++)
          {if(G.vcolor[v] != vcol)continue;
          G.NewEdge(v,newvertex[v]);
          }
      load(true);
      mywindow->information();// Informations
      }
  }
Exemplo n.º 11
0
void MainWindow::routeNetwork()
{
    // Storage class for the metadata required by Dijkstra
    struct MetaData {
        int         distance;
        EdgeItem*   edge;
        NodeItem*   previous;
        NodeItem*   owner;

        MetaData()
            : distance(INT_MAX)
            , edge(nullptr)
            , previous(nullptr)
            , owner(nullptr)
        {
        }

        MetaData(NodeItem* owner_)
            : distance(INT_MAX)
            , edge(nullptr)
            , previous(nullptr)
            , owner(owner_)
        {
        }
    };

    QMap<NodeItem*, MetaData>   metadata;
    QList<NodeItem*>            nodes;
    NodeItem*                   current;

    // Initialise data-structres
    postInfoMessage("Preparing to route...");
    {
        QMapIterator<QString, NodeItem*> i(m_graphNodes);
        while (i.hasNext()) {
            auto item = i.next();

            // Initialise the metadata
            MetaData md(item.value());
            if (item.value() == m_routeStart) {
                // Need minimal distance for the start node
                md.distance = 0;
            }
            metadata[i.value()] = md;

            // Initialise the node list
            nodes.append(i.value());
        }
    }

    // Dijkstra's algorithm: calculate all the distances
    while (!nodes.isEmpty()) {
        // Find node with smallest distance
        {
            int d = INT_MAX;
            auto elem = nodes.end();
            for (auto it = nodes.begin(); it != nodes.end(); ++it) {
                int thisDistance = metadata[*it].distance;
                if (thisDistance < d) {
                    d    = thisDistance;
                    elem = it;
                }
            }

            current = *elem;

            // If we hit the target, we can stop
            if (current == m_routeEnd) {
                postInfoMessage("Search complete; reached target node!");
                break;
            } else {
                // Emshrinken the list
                nodes.erase(elem);
            }
        }

        postInfoMessage(QString("Considering node %1...")
                .arg(current->text()));

        // Visit the neighbours
        QListIterator<EdgeItem*> i(current->edges());
        while (i.hasNext()) {
            EdgeItem* edge      = i.next();
            NodeItem* neighbour = edge->endNode();
            int       dist      = metadata[current].distance + edge->weight();

            if (dist < metadata[neighbour].distance) {
                metadata[neighbour].distance = dist;
                metadata[neighbour].edge     = edge;
                metadata[neighbour].previous = current;
            }
        }
    }

    // Walk backwards from the target to the source, building the path
    postInfoMessage("Back-tracking to construct route...");
    for (current = m_routeEnd; current; current = metadata[current].previous) {
        EdgeItem* edge = metadata[current].edge;

        if (edge) {
            m_route.prepend(edge);
        }
    }

    // All done!
    postSuccessMessage("Routing complete!");

    // Update the display
    setHighlightStartNode(m_controlsDock->highlightStartNode());
    setHighlightEndNode(m_controlsDock->highlightEndNode());
    setHighlightPath(m_controlsDock->highlightPath());
}
Exemplo n.º 12
0
int MainWindow::buildNetwork(const QString& description)
{
    int result = Success;

    // Split into lines
    QStringList lines = description.split(QRegExp("[\\n|\\r]"),
        QString::SkipEmptyParts);
    if (lines.isEmpty()) {
        postErrorMessage("Problem specification is empty after whitespace "
            "removed!");
        return ErrorEmpty;
    }

    // Validate the length of the specification
    int nodeCount = lines[0].toInt();
    postInfoMessage(QString("Expecting %1x%1 adjacency matrix...")
        .arg(nodeCount));

    if (lines.length() != (nodeCount + 2)) {
        postErrorMessage(QString("Expecting %1 lines in specification; read %2")
            .arg(nodeCount + 2)
            .arg(lines.length()));
        return ErrorSpecTooSmall;
    }

    // Clear the existing graph and scene
    if (boost::num_vertices(m_graph) != 0) {
        postWarningMessage("Existing network already loaded; must be cleared "
            "in order to continue.");

        int response = QMessageBox::question(this, "NetRoute", "There is "
            "already a graph in the explorer; the current data will have to "
            "be discared.  Continue?");
        if (response == QMessageBox::No) {
            postErrorMessage("Aborted by user.");
            return WarningAbort;
        }

        postInfoMessage("Discarding network.");
        clearNetwork();
    }

    // Create the nodes
    postInfoMessage("Creating nodes...");
    for (int i = 0; i < nodeCount; ++i) {
        QString name = QString("%1").arg(QChar('A' + i));

        NodeItem* node = new NodeItem;
        node->setText(name);
        
        m_graphNodes[name] = node;
        
        boost::add_vertex(NodeProperties(node), m_graph);

        m_graphScene->addItem(node);
    }

    // Create the edges
    postInfoMessage("Creating edges from adjacency matrix...");
    for (int i = 0; i < nodeCount; ++i) {
        QString     line    = lines[i + 1].trimmed();
        QStringList weights = line.split(',', QString::SkipEmptyParts);

        // Sanity check
        if (weights.length() != nodeCount) {
            postErrorMessage(
                QString("Matrix row %1 has %2 columns; expecting %3.")
                    .arg(i)
                    .arg(weights.length())
                    .arg(nodeCount));
            return ErrorRowTooShort;
        }

        // Actually create the edges
        postInfoMessage(QString("Creating edges for node %1")
            .arg(QChar('A' + i)));
        DigraphVertex vStart = boost::vertex(i, m_graph);
        for (int j = 0; j < nodeCount; ++j) {
            bool ok;
            int weight = weights[j].trimmed().toInt(&ok);

            if (ok && weight >= 0) {
                DigraphVertex vEnd = boost::vertex(j, m_graph);

                // Create the new edge item
                EdgeItem* edge = new EdgeItem;
                edge->setStartNode(m_graph[vStart].item);
                edge->setEndNode(m_graph[vEnd].item);
                edge->setWeight(weight);
                m_graphScene->addItem(edge);

                // Add it to the graph
                boost::add_edge(vStart, vEnd, EdgeProperties(edge), m_graph);
            } else if (!ok) {
                postWarningMessage(QString("Weight (%1,%2) is malformed: %3.")
                    .arg(i)
                    .arg(j)
                    .arg(weights[j]));
                result |= WarningBadCell;
            }
        }
    }

    // Parse the final line of the description: the start/end nodes
    QStringList nodes = lines[lines.length() - 1].split(QRegExp("\\s+"),
        QString::SkipEmptyParts);
    if (nodes.length() != 2) {
        postWarningMessage("Start and end nodes line is malformed; "
            "routing will not take place.");
        result |= WarningBadStartEnd;
    } else {
        QString startNodeName = nodes[0];
        QString endNodeName   = nodes[1];

        m_routeStart = m_graphNodes[startNodeName];
        m_routeEnd   = m_graphNodes[endNodeName];

        if (!m_routeStart) {
            postWarningMessage(QString("Failed to find start node '%1'; "
                "routing will not take place.")
                    .arg(startNodeName));
            result |= WarningNoStartNode;
        }

        if (!m_routeEnd) {
            postWarningMessage(QString("Failed to find end node '%1'; "
                "routing will not take place.")
                    .arg(endNodeName));
            result |= WarningNoEndNode;
        }
    }

    // Graph was built successfully, even if some parsing errors arose.
    return result;
}