Beispiel #1
0
/** Check that given edge is in current sector */
bool NodeNav::isEdgeInSector( GEdge * edge) const
{
    GNode *n = otherEnd( edge);
    /* item corresponding to other (than node_priv) node */
    if ( isNullP( n) || sector() == UNDEF_SECTOR)
        return false;

    NodeItem *item = n->item();
    
    // Both points in current node's coordinates
    QPointF p_center = node_priv->item()->boundingRect().center();
    QPointF s_center = node_priv->item()->mapFromItem( item, item->boundingRect().center());

    qreal angle = QLineF( p_center, s_center).angle();
    
    qreal max_angle = sectorMaxAngle();
    qreal min_angle = sectorMinAngle();

    if ( angle > 270 && sector() == RIGHT_SECTOR)
    {
        max_angle +=360;
    }
    if ( angle < 90 && sector() == RIGHT_SECTOR)
    {
        min_angle -=360;
    }

    if ( angle <= max_angle && angle >= min_angle)
        return true;
    return false;
}
Beispiel #2
0
// Graph layout stuff
void MainWindow::applyRandomLayout()
{
    RandomNumberGenerator rng(QDateTime::currentMSecsSinceEpoch());

    // Define the topology to work in
    QRectF rc(m_graphView->visibleRegion().boundingRect());
    rc.adjust(-10.0f, -10.0f, -10.0f, -10.0f);
    rc.moveTo(-rc.width() / 2.0f, -rc.height() / 2.0f);
    Topology top(rng, rc.left(), rc.top(), rc.right(), rc.bottom());

    // Apply the layout
    boost::random_graph_layout(m_graph,
        get(&NodeProperties::pos, m_graph), top);

    // Forward the calculated values into the graphics objects
    std::pair<DigraphVertexIterator, DigraphVertexIterator> iterators =
        boost::vertices(m_graph);
    DigraphVertexIterator it = iterators.first;
    for (; it != iterators.second; ++it) {
        TopologicalPoint pt   = m_graph[*it].pos;
        NodeItem*        node = m_graph[*it].item;

        node->setPos(pt[0], pt[1]);
    }
}
Beispiel #3
0
void NodeMove::redo() {
	NodeItem *item = scene->findItem(node_id);
	item->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
	item->setPos(_new);
	scene->updateConnections(item);
	item->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
	//scene->update();
}
void DeleteNode::redo() {
	NodeItem *item = scene->findItem(QString::fromStdString(node_id));
	Q_ASSERT(item != 0);
	scene->disconnect(item);
	scene->node_items.remove(item->getId());
	Node *n = item->getNode();
	delete item;
	scene->model->removeNode(n); //deletes n
}
/*

void NodeItem::mouseMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    event->setAccepted(true);
}


void ParameterItem::mousePressEvent(QGraphicsSceneDragDropEvent *event)
{

    event->setAccepted(false);

}
*/
void ParameterItem::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
{

    if (event->button() == Qt::LeftButton) {
        setColor(Qt::darkCyan);
        // force my box to snap to grid, just truncate the pixel number and
        // snap to the next lowest grid value
        if (fmod(_location.x(),_gridSpace) >_gridSpace/2)
            _location.setX( ( static_cast<int>(_location.x()+_gridSpace) / _gridSpace) * _gridSpace );
        else
            _location.setX( ( static_cast<int>(_location.x()) / _gridSpace) * _gridSpace );
        if (fmod(_location.y(),_gridSpace) >_gridSpace/2)
            _location.setY( ( static_cast<int>(_location.y()+_gridSpace) / _gridSpace) * _gridSpace );
        else
            _location.setY( ( static_cast<int>(_location.y()) / _gridSpace) * _gridSpace );

        foreach (QGraphicsItem *item, collidingItems()) {

                if (item->type() ==GroupItem::Type){

                    this->setPos(mapToItem(item,0,0));
                        setParentItem(item);

                } else {
                    this->setPos(mapToScene(0,0));
                    this->setParentItem(0);
                }
            }

        if (scene()->itemAt(_location)){

            switch (scene()->itemAt(_location)->type()){
            case GroupItem::Type:                                                         //Group
                setParentItem(scene()->itemAt(_location));
                this->setPos(_location-(this->parentItem()->pos()));
                break;
            case NodeItem::Type:                                                         //Node or Test
                NodeItem *node;
                node=qgraphicsitem_cast<NodeItem *>(scene()->itemAt(_location));
                node->addParamItem(this);
                scene()->removeItem(this);
                break;
            case 8:                                                             //TextItem -> check for parent
                if (scene()->itemAt(_location)->parentItem()->type() ==NodeItem::Type){  //Node or Test
                    NodeItem *node;
                    node=qgraphicsitem_cast<NodeItem *>(scene()->itemAt(_location)->parentItem());
                    node->addParamItem(this);
                    scene()->removeItem(this);
                }
                break;
            }
       }
        event->setAccepted(true);// tell the base class we are handling this event

    }
void ChangeParameters::undo() {
	NodeItem *item = scene->findItem(id);
	Q_ASSERT(item != 0);
	item->getNode()->deinit();
	item->restoreParameters(before);
	SimulationParameters sp = scene->simulation->getSimulationParameters();
	item->getNode()->init(sp.start + seconds(sp.dt), sp.stop, sp.dt);
	item->updatePorts();
	//scene->update();
	scene->updateConnections(item);
}
void DeleteNode::undo() {
	Node *node = scene->node_reg->createNode(node_class);
	scene->model->addNode(node_id, node);

	NodeItem *nitem = new NodeItem(node);

	nitem->restoreParameters(parameters);
	SimulationParameters sp = scene->simulation->getSimulationParameters();
	node->init(sp.start + seconds(sp.dt), sp.stop, sp.dt);
	nitem->updatePorts();
	nitem->setPos(pos);
	scene->add(nitem);
	//scene->update();
}
void ChangeParameters::redo() {
	if (first_redo) {
		first_redo = false;
		return;
	}
	NodeItem *item = scene->findItem(id);
	Q_ASSERT(item != 0);
	item->getNode()->deinit();
	item->restoreParameters(after);
	SimulationParameters sp = scene->simulation->getSimulationParameters();
	item->getNode()->init(sp.start + seconds(sp.dt), sp.stop, sp.dt);
	item->updatePorts();
	//scene->update();
	scene->updateConnections(item);
}
/*!\brief reimplementation of the dropEvent
 *
 * Creates a node item if a node is dropped in the view.
 * The neccessary nodeinformation is fetched during the mousepressaction for the drag event
 * in RxDev::selectionHandle_availableNodes.
 */
void LaunchFileView::dropEvent(QDropEvent *event) {
    NodeItem * newNode;
    newNode = new NodeItem(selectedNodeName,selectedNodePackage,selectedNodeSubscriptions,
                           selectedNodePublications,selectedNodeServices,selectedNodeParameters);
    newNode->setLocation(mapToScene(event->pos()));

    newNode->setPos(mapToScene(event->pos()));

    if (newNode->getNodeData()==true){
        scene()->addItem(newNode);
    }

    selectedBox->setColor(Qt::black);
    selectedBox= newNode;
}
Beispiel #10
0
/** Get edge to the left of given edge */
GEdge *
NodeNav::edgeInDir( GEdge * edge, NavDirection dir) const
{
    /* Applicable only for top and bottom sectors */
    if ( !isDirApplicable( dir, sector()))
    {
        return NULL;
    }
    
    GNode *n = otherEnd( edge);
    /* item corresponding to other (than node_priv) node */
    if ( isNullP( n))
        return NULL;

    NodeItem *item = n->item();
    
    // in current node's coordinates
    QPointF edge_point = node()->item()->mapFromItem( item, item->boundingRect().center());

    GEdge *res = NULL;
    qreal min_delta = 0;
    /** For each edge */   
    for ( Node::EdgeIter e_iter = node()->edgesBegin(),
                         e_end = node()->edgesEnd();
          e_iter != e_end;
          e_iter++ )
    {
        GEdge *e = static_cast<GEdge *>( e_iter.edge());
        if ( isEdgeInSector( e) && areNotEqP( e, edge))
        {
            NodeItem *p_item = static_cast<GNode *>( e_iter.node())->item();
            QPointF point = node()->item()->mapFromItem( p_item, p_item->boundingRect().center());
            if ( isPointInDir( point, edge_point, dir))
            {
                qreal delta = deltaInDir( point, edge_point, dir);
                if ( isNullP( res) 
                     || delta < min_delta) // for selection of closest edge
                {
                    res = e;
                    min_delta = delta;
                }
            }
        }
    }

    return res;
}
Beispiel #11
0
        void updateCache()
        {
            if (!dirty) return;
            dirty = false;

            if (node->style()->shape() != shape->type()) {
                delete shape;
                shape = createShape(node->style()->shape(), q);
            }

            shapePath = shape->shape();
            outlinePath = shape->outline();

            q->setRotation(node->style()->rotation());

            q->update();
        }
Beispiel #12
0
void
RootPanel::updateUnit(NavUnit *unit)
{
  NodeItem *el = 0;
  nodeMap.find(unit->getID(), el);

  UnitLocation loc = unit->getLocation();
  //width is incl. borders and text, so correct for this .
  loc.x_ = (long)loc.x_ % (navview->width() - 40);
  loc.y_ = (long)loc.y_ % (navview->height() - 80);

  el->moveBy(loc.x_ - el->pos().x() , loc.y_ - el->pos().y());
  el->show();
  canvas.update();
  if(unit->getID() == 1)
    {
      this->details->updateLocation(loc);
    }
}
Beispiel #13
0
koregui::NodeItem* koregui::SceneViewer
  ::createNode(kore::SceneNode* sourcenode,
               int x,
               int y) {
  NodeItem* nodeItem = new NodeItem(sourcenode);
  _scene.addItem(nodeItem);

  std::vector<kore::SceneNodePtr> pnode = sourcenode->getChildren();
  int startx = x -(estimateTreeWidth(sourcenode)/2);
  for (unsigned int i = 0; i<pnode.size(); i++) {
    int localwidth = estimateTreeWidth(pnode[i].get());
    NodePathItem* path = new NodePathItem(nodeItem,
                                          createNode(pnode[i].get(),
                                            startx + localwidth/2,
                                            y + nodeItem->getHeight() + 80));
    path->setZValue(-1);
    _scene.addItem(path);
    startx += localwidth;
  }
  nodeItem->setPos(x, y);
  return nodeItem;
}
Beispiel #14
0
void GraphEditor::mouseMoveEvent(QMouseEvent* e)
  {if(gwp->moving_item)
      {//setRenderHints(!QPainter::Antialiasing);
      gwp->moving_item->moveBy(e->pos().x() - start_position.x(), e->pos().y() - start_position.y());
      start_position = e->pos();
      }
  else if(gwp->moving_subgraph)
      {setRenderHints(0);
      GeometricGraph & G = *(gwp->pGG);
      Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      short vcol=0;  G.vcolor.getinit(vcol);
      NodeItem * node;
      for(tvertex v = 1; v <= G.nv();v++)
          {node =(NodeItem *)nodeitem[v];
          if(G.vcolor[node->v] != vcol)continue;
          node->moveBy(e->pos().x() - start_position.x(), e->pos().y() - start_position.y());
          }
      start_position = e->pos();
      }
  else if(gwp->curs_item) // moving the elastic cursor
      gwp->curs_item->setToPoint(e->pos().x(),e->pos().y());
  }
Beispiel #15
0
bool GraphScene::saveTo(const QString &fileName)
{
    QFile file(fileName);
    if (file.open(QFile::WriteOnly | QFile::Truncate)) {
        QTextStream stream(&file);

        // Save the nodes with the following line format: 'node $NAME $TYPE $ROW $COL $FORMULA'
        for (int row = 0; row < m_gridLayout->rowCount(); row++) {
            for (int column = 0; column < m_gridLayout->columnCount(); column++) {
                NodeItem *node = static_cast<NodeItem *>(m_gridLayout->itemAt(row, column));
                if (node) {
                    stream << "node " << node->name() << ' ' << node->nodeType() << ' '
                           << row << ' ' << column << " \"" << node->formula() << '"' << endl;
                }
            }
        }
        // Save the edges with the following line format: 'edge $NAME $START $END $FORMULA'
        foreach (const DirectedEdgeItem *edge, m_edges) {
            stream << "edge " << edge->name() << ' ' << edge->start()->name() << ' '
                   << edge->end()->name() << " \"" << edge->formula() << '"' << endl;
        }
        file.close();
        return true;
    }
void RxDev::on_pushButton_managerNodelet_clicked()
{
    NodeItem * newNode;
    newNode = new NodeItem("","nodelet",QStringList(),QStringList(),QStringList(),QStringList());
    newNode->setType("nodelet");
    newNode->setArgs("manager");
    newNode->setLocation(findSpace(QPoint(0,55)));
    newNode->setColor(Qt::yellow);
    newNode->setPos(findSpace(QPoint(0,55)));

    if (newNode->getNodeData()==true){
        scene->addItem(newNode);
    }
}
void RxDev::on_pushButton_blankNode_clicked()
{
    NodeItem * newNode;
    newNode = new NodeItem("","",QStringList(),QStringList(),QStringList(),QStringList());
    newNode->setType("_blank_node");
    newNode->setLocation(findSpace(QPoint(0,55)));
newNode->setColor(Qt::yellow);
    newNode->setPos(findSpace(QPoint(0,55)));

    if (newNode->getNodeData()==true){
        scene->addItem(newNode);
    }


}
Beispiel #18
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
      }
  }
Beispiel #19
0
void GraphEditor::mouseReleaseEvent(QMouseEvent* event)
  {//setRenderHints(QPainter::Antialiasing);
  if(gwp->info_item) //end info
      {scene()->removeItem(gwp->info_item->rectitem);
      scene()->removeItem(gwp->info_item);
      gwp->info_item = 0;
      setCursor(QCursor(Qt::ArrowCursor));
      return;
      }
  if(gwp->moving_item) //end moving a vertex
      {if(!FitToGrid)
          {gwp->moving_item = 0;return;}
      GeometricGraph & G = *(gwp->pGG);
      NodeItem *node = gwp->moving_item;
      tvertex v = node->v;
      double prev_x = G.vcoord[v].x();
      double prev_y = G.vcoord[v].y();
      ToGrid(v);
      double dx =  G.vcoord[v].x() - prev_x;
      double dy =  G.vcoord[v].y() - prev_y;
      G.vcoord[v].x() = prev_x;
      G.vcoord[v].y() = prev_y;
      node->moveBy(dx,-dy);
      gwp->moving_item = 0;
      UpdateSizeGrid();
      PrintSizeGrid();
      return;
      }
  if(gwp->moving_subgraph == true)
      {gwp->moving_subgraph = false;
      if(!FitToGrid)return;
      GeometricGraph & G = *(gwp->pGG);
      Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      short vcol=0;  G.vcolor.getinit(vcol);
      NodeItem * node;
      // Find a vertex of the subgraph
      tvertex mv = 0;
      tvertex v;
      for(v = 1; v <= G.nv();v++)
          {node =(NodeItem *)nodeitem[v];
          if(G.vcolor[node->v] != vcol)continue;
          else {mv = v;break;}
          }
      if(!mv)return;
      double prev_x = G.vcoord[mv].x();
      double prev_y = G.vcoord[mv].y();
      ToGrid(mv);
      double dx =  G.vcoord[mv].x() - prev_x;
      double dy =  G.vcoord[mv].y() - prev_y;
      G.vcoord[mv].x() = prev_x;
      G.vcoord[mv].y() = prev_y;
      for(v = 1;v <= G.nv();v++)
          {node =(NodeItem *)nodeitem[v];
          if(G.vcolor[node->v] != vcol)continue;
          node->moveBy(dx,-dy);
          }
      UpdateSizeGrid();
      PrintSizeGrid();
      return;
      }
  if(gwp->curs_item)// end creating an edge
      {GeometricGraph & G = *(gwp->pGG);
      Prop<EdgeItem *> edgeitem(G.Set(tedge()),PROP_CANVAS_ITEM);
      Prop<NodeItem *> nodeitem(G.Set(tvertex()),PROP_CANVAS_ITEM);
      NodeItem* node;
      EdgeItem *edge;
      tvertex v1,v2;
      // Reset the color of starting vertex
      v1 = gwp->curs_item->v;
      node = (NodeItem *)(nodeitem[v1]); node->SetColor(color[G.vcolor[v1]]);
      QPoint p(event->pos()); 
      ToGrid(p);
      int rtt = FindItem(p,node,edge);
      v2 = (rtt != node_rtti) ? 0 : node->v;
      if(rtt != node_rtti) //create a vertex
          {int h = (int)gwp->canvas->height();
          Tpoint pp((double)p.x(),(double)(h - p.y()));
          v2 = G.NewVertex(pp);ToGrid(v2);
          nodeitem[v2] = CreateNodeItem(v2,gwp);
          mywindow->mouse_actions->ButtonUndoGrid->setDisabled(true);
          if(IsGrid)UpdateSizeGrid();
          }
      else
          v2 = node->v;
      if(v1 != v2) // Create an edge 
          {tedge e = G.NewEdge(v1,v2);
          edgeitem[e] = CreateEdgeItem(e,gwp);
          }
      delete gwp->curs_item;      gwp->curs_item = 0;
      mywindow->information();// Informations
      if(v1 == v2) // We have created a vertex
          PrintSizeGrid();
      return;
      }
  }
Beispiel #20
0
void Main::addMesh()
{
    int x0 = 0;
    int y0 = 0;

    if ( !tb ) tb = new QBrush( Qt::red );
    if ( !tp ) tp = new QPen( Qt::black );

    int nodecount = 0;

    int w = int(canvas.width());
    int h = int(canvas.height());

    const int dist = 30;
    int rows = h / dist;
    int cols = w / dist;

#ifndef QT_NO_PROGRESSDIALOG
    Q3ProgressDialog progress( "Creating mesh...", "Abort", rows,
			      this, "progress", TRUE );
#endif

    canvas.update();
    
    Q3MemArray<NodeItem*> lastRow(cols);
    for ( int j = 0; j < rows; j++ ) {
	int n = j%2 ? cols-1 : cols;
	NodeItem *prev = 0;
	for ( int i = 0; i < n; i++ ) {
	    NodeItem *el = new NodeItem;
            canvas.addItem(el);
	    nodecount++;
	    int r = qrand();
	    int xrand = r %20;
	    int yrand = (r/20) %20;
	    el->setPos( xrand + x0 + i*dist + (j%2 ? dist/2 : 0 ),
                        yrand + y0 + j*dist );

	    if ( j > 0 ) {
		if ( i < cols-1 )
		    canvas.addItem(new EdgeItem( lastRow[i], el));
		if ( j%2 )
		    canvas.addItem(new EdgeItem( lastRow[i+1], el));
		else if ( i > 0 )
		    canvas.addItem(new EdgeItem( lastRow[i-1], el));
	    }
	    if ( prev ) {
		canvas.addItem(new EdgeItem( prev, el));
	    }
	    if ( i > 0 ) lastRow[i-1] = prev;
	    prev = el;
	}
	lastRow[n-1]=prev;
#ifndef QT_NO_PROGRESSDIALOG
	progress.setProgress( j );
	if ( progress.wasCancelled() )
	    break;
#endif
    }
#ifndef QT_NO_PROGRESSDIALOG
    progress.setProgress( rows );
#endif
    // qDebug( "%d nodes, %d edges", nodecount, EdgeItem::count() );
}
Beispiel #21
0
bool GraphScene::loadFrom(const QString &fileName)
{
    QFile file(fileName);
    if (file.exists() && file.open(QFile::ReadOnly)) {
        QTextStream stream(&file);
        QHash<QString, NodeItem *> nodes;                   // Temporary hashmap for faster lookup

        init(EmptyInit);                                    // Create an empty scene

        QString line;
        do {                                                // Iterate over all the lines in the file
            line = stream.readLine();                       // and split the line at ' ' characters
            const QStringList splittedLine = line.split(" ");
            if (splittedLine[0] == "node") {
                // Found a node, add it to the scene
                NodeItem *node = new NodeItem(NULL, this);
                node->setName(splittedLine[1]);
                NodeItem::NodeType nodeType = static_cast<NodeItem::NodeType>(splittedLine[2].toInt());
                switch (nodeType) {
                    case NodeItem::InputNode:
                        setInputNode(node);                 // We found the input node
                        break;
                    case NodeItem::OutputNode:
                        setOuputNode(node);                 // We found the ouput node
                        break;
                    case NodeItem::StandardNode:
                        // This should already be set by default but doesn't harm here
                        node->setNodeType(NodeItem::StandardNode);
                        break;
                }
                // There is obviously a (Matlab) formula attached, parse it...
                if (splittedLine.length() > 5) {
                    int formulaStart = line.indexOf('"');
                    QString formula = line;
                    formula.remove(0, formulaStart);
                    while (!formula.endsWith('"')) {        // Formula spans multiple lines
                        formula += '\n' + stream.readLine();
                    }
                    formula.chop(1);                        // Remove leading '"'
                    formula.remove(0, 1);                   // Remove trailing '"'
                    node->setFormula(formula);
                }

                nodes.insert(node->name(), node);
                m_gridLayout->addItem(node, splittedLine[3].toInt(), splittedLine[4].toInt());
            } else if (splittedLine[0] == "edge") {
                NodeItem *start = nodes[splittedLine[2]];   // Found an edge, add it to the scene
                NodeItem *end = nodes[splittedLine[3]];

                DirectedEdgeItem *edge = addEdge(start, end);
                edge->setName(splittedLine[1]);
                // There is obviously a (Matlab) formula attached, parse it...
                if (splittedLine.length() > 4) {
                    int formulaStart = line.indexOf('"');
                    QString formula = line;
                    formula.remove(0, formulaStart);
                    while (!formula.endsWith('"')) {        // Formula spans multiple lines
                        formula += '\n' + stream.readLine();
                    }
                    formula.chop(1);                        // Remove leading '"'
                    formula.remove(0, 1);                   // Remove trailing '"'
                    edge->setFormula(formula);
                }
            }
        } while (!line.isNull());

        emit graphChanged();
        file.close();
        return true;
    }
    return false;
}
Beispiel #22
0
void MainWindow::applySpringLayout()
{
    ConstantValueDoubleMap weights(1.0f);
    RandomNumberGenerator rng(QDateTime::currentMSecsSinceEpoch());

    // Create an undirected copy of the graph
    QMap<GraphVertex, DigraphVertex> mapDtoU;
    QMap<DigraphVertex, GraphVertex> mapUtoD;
    Graph g;

    {
        // Copy the nodes
        std::pair<DigraphVertexIterator, DigraphVertexIterator> digraphVertices
            = boost::vertices(m_graph);
        DigraphVertexIterator vit = digraphVertices.first;
        for (; vit != digraphVertices.second; vit++) {
            // Add the vertex
            GraphVertex v = boost::add_vertex(m_graph[*vit], g);

            // Create the mapping
            mapDtoU[*vit] = v;
            mapUtoD[v]    = *vit;
        }

        // Copy the edges
        std::pair<Digraph::edge_iterator, Digraph::edge_iterator> digraphEdges
            = boost::edges(m_graph);
        Digraph::edge_iterator eit = digraphEdges.first;
        for (; eit != digraphEdges.second; eit++) {
            // Get the nodes in terms of the undirected graph
            DigraphVertex src = boost::source(*eit, m_graph);
            DigraphVertex tgt = boost::target(*eit, m_graph);

            // Add an edge into the undirected graph
            boost::add_edge(mapDtoU[src], mapDtoU[tgt], m_graph[*eit], g);
        }
    }

    // Define the topology to work in
    QRectF rc(m_graphView->visibleRegion().boundingRect());
    float adjH = rc.width()  * 0.1f;
    float adjV = rc.height() * 0.1f;
    rc.adjust(adjH, adjV, -adjH, -adjV);
    rc.moveTo(-rc.width() / 2.0f, -rc.height() / 2.0f);

    Topology top(rng, rc.left(), rc.top(), rc.right(), rc.bottom());

    MaxIterationsLayoutTolerance<double> done(
                boost::num_vertices(m_graph) * m_controlsDock->maxIterations(),
                m_controlsDock->layoutTolerance());

    // Seed with a random layout
    boost::random_graph_layout(g, get(&NodeProperties::pos, g), top);

    // Now apply the force-directed layout
    boost::kamada_kawai_spring_layout(g,
        get(&NodeProperties::pos, g), weights, top,
        boost::side_length(rc.width()), done);

    // Forward the calculated values into the graphics objects
    std::pair<GraphVertexIterator, GraphVertexIterator> iterators =
        boost::vertices(g);
    GraphVertexIterator it = iterators.first;
    for (; it != iterators.second; ++it) {
        TopologicalPoint pt   = g[*it].pos;
        NodeItem*        node = g[*it].item;

        // Set the scene item
        node->setPos(pt[0], pt[1]);

        // Update the digraph
        m_graph[mapUtoD[*it]].pos = pt;
    }
}
/*!\brief reimplementation of the mouseReleaseEvent
 *
 * ...
 */
void LaunchFileView::mouseReleaseEvent(QMouseEvent *event)
{

    if (_handScrolling) {
        _handScrolling = false;
        viewport()->setCursor(_savedCursor);

        event->accept();
        return;
    }
    if (itemAt((event->pos()))){ //else tool crashes
        if (myMode== DeleteItem && event->button() == Qt::LeftButton) {

            if (itemAt(event->pos())->type() == NodeItem::Type) {

                qgraphicsitem_cast<NodeItem *>(itemAt(event->pos()))->removeArrows();
                scene()->removeItem(itemAt(event->pos())); ///removes the Node from the scene
            } else if (itemAt(event->pos())->type() == 8){  // Don't try to kill the View
                if (itemAt(event->pos())->parentItem()->type() == NodeItem::Type){
                    qgraphicsitem_cast<NodeItem *>((itemAt(event->pos()))->parentItem())->removeArrows();
                    scene()->removeItem((itemAt(event->pos()))->parentItem()); ///removes the Node from the scene
                }else
                    scene()->removeItem((itemAt(event->pos()))->parentItem()); ///removes the Parameter

            }else if(itemAt(event->pos())->type() == GroupItem::Type) {
                QList<QGraphicsItem *> list;
                list=itemAt(event->pos())->childItems();
                //qDebug()<<"Begin group items->";

                for (int i = 0; i < list.size(); i++) {
                    if (list.at(i)->type() != 8)

                        (list.at(i))->setParentItem(0);
                  //  qDebug()<<(list.at(i)->type());
                }
                //qDebug()<<"<-End group items";
                scene()->removeItem(itemAt(event->pos()));
            }


            event->setAccepted(true);// tell the base class we are handling this event


        }
    }if (line != 0 && myMode == InsertLine) {

            QList<QGraphicsItem *> startItems = scene()->items(line->line().p1());
            if (startItems.count() && startItems.first() == line)
                startItems.removeFirst();

            QList<QGraphicsItem *> endItems = scene()->items(line->line().p2());
            if (endItems.count() && endItems.first() == line)
                endItems.removeFirst();

            if (startItems.count() &&startItems.first()->type() == 8)
                startItems.first() = startItems.first()->parentItem();
            if (endItems.count() && endItems.first()->type() == 8)
                endItems.first() = endItems.first()->parentItem();


            scene()->removeItem(line); //remove temporary line
            delete line;
            //! [11] //! [12]



            if (startItems.count() > 0 && endItems.count() > 0 &&
                    startItems.first()->type() == NodeItem::Type &&
                    endItems.first()->type() == NodeItem::Type &&
                    startItems.first() != endItems.first()) {
                NodeItem *startItem =
                        qgraphicsitem_cast<NodeItem *>(startItems.first());
                NodeItem *endItem =
                        qgraphicsitem_cast<NodeItem *>(endItems.first());


                RemapArrow *arrow = new RemapArrow(startItem, endItem);
                if (arrow->getArrowData()==true){

                    startItem->addArrow(arrow);
                    endItem->addArrow(arrow);
                    arrow->setZValue(-20);
                    scene()->addItem(arrow);
                    arrow->updatePosition();
                }
            }
        }

    //! [12] //! [13]
    line = 0;

    QGraphicsView::mouseReleaseEvent(event);
}
Beispiel #24
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;
}
Beispiel #25
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());
}