//Copyright 2017 Ryan Wick //This file is part of Bandage //Bandage is free software: you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. //Bandage is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. //You should have received a copy of the GNU General Public License //along with Bandage. If not, see . #include "mygraphicsscene.h" #include "../graph/debruijnnode.h" #include "../graph/debruijnedge.h" #include "../graph/graphicsitemnode.h" #include "../graph/graphicsitemedge.h" #include "../graph/debruijnnode.h" MyGraphicsScene::MyGraphicsScene(QObject *parent) : QGraphicsScene(parent) { } bool compareNodePointers(DeBruijnNode * a, DeBruijnNode * b) { QString aName = a->getName(); QString bName = b->getName(); QString aName2 = aName; aName2.chop(1); QString bName2 = bName; bName2.chop(1); bool ok1, ok2; long long aNum = aName2.toLongLong(&ok1); long long bNum = bName2.toLongLong(&ok2); //If the node names are essentially numbers, then sort them as numbers if (ok1 && ok2 && aNum != bNum) return aNum < bNum; return aName < bName; } //This function returns all of the selected nodes, sorted by their node number. std::vector MyGraphicsScene::getSelectedNodes() { std::vector returnVector; QList selection = selectedItems(); for (int i = 0; i < selection.size(); ++i) { QGraphicsItem * selectedItem = selection[i]; GraphicsItemNode * selectedNodeItem = dynamic_cast(selectedItem); if (selectedNodeItem != 0) returnVector.push_back(selectedNodeItem->m_deBruijnNode); } std::sort(returnVector.begin(), returnVector.end(), compareNodePointers); return returnVector; } //This function works like getSelectedNodes, but only positive nodes are //returned. If a negative node is selected, its positive complement is in the //results. If both nodes in a pair are selected, then only the positive node //of the pair is in the results. std::vector MyGraphicsScene::getSelectedPositiveNodes() { std::vector selectedNodes = getSelectedNodes(); //First turn all of the nodes to positive nodes. std::vector allPositive; for (size_t i = 0; i < selectedNodes.size(); ++i) { DeBruijnNode * node = selectedNodes[i]; if (node->isNegativeNode()) node = node->getReverseComplement(); allPositive.push_back(node); } //Now remove duplicates. Since the nodes are sorted, all duplicates should //be adjacent to each other. std::vector uniquePositive; for (size_t i = 0; i < allPositive.size(); ++i) { DeBruijnNode * node = allPositive[i]; DeBruijnNode * previousNode = 0; if (i > 0) previousNode = allPositive[i-1]; if (node != previousNode) uniquePositive.push_back(node); } return uniquePositive; } //This function returns all of the selected graphics item nodes, unsorted. std::vector MyGraphicsScene::getSelectedGraphicsItemNodes() { std::vector returnVector; QList selection = selectedItems(); for (int i = 0; i < selection.size(); ++i) { QGraphicsItem * selectedItem = selection[i]; GraphicsItemNode * selectedNodeItem = dynamic_cast(selectedItem); if (selectedNodeItem != 0) returnVector.push_back(selectedNodeItem); } return returnVector; } std::vector MyGraphicsScene::getSelectedEdges() { std::vector returnVector; QList selection = selectedItems(); for (int i = 0; i < selection.size(); ++i) { QGraphicsItem * selectedItem = selection[i]; GraphicsItemEdge * selectedEdgeItem = dynamic_cast(selectedItem); if (selectedEdgeItem != 0) returnVector.push_back(selectedEdgeItem->m_deBruijnEdge); } return returnVector; } DeBruijnNode * MyGraphicsScene::getOneSelectedNode() { std::vector selectedNodes = getSelectedNodes(); if (selectedNodes.size() == 0) return 0; else return selectedNodes[0]; } DeBruijnEdge * MyGraphicsScene::getOneSelectedEdge() { std::vector selectedEdges = getSelectedEdges(); if (selectedEdges.size() == 0) return 0; else return selectedEdges[0]; } //This function, like getOneSelectedNode, returns a single selected node from //graph and a 0 if it can't be done. However, it will always return the //positive node in the pair, and if two complementary nodes are selected, it //will still work. DeBruijnNode * MyGraphicsScene::getOnePositiveSelectedNode() { std::vector selectedNodes = getSelectedNodes(); if (selectedNodes.size() == 0) return 0; else if (selectedNodes.size() == 1) { DeBruijnNode * selectedNode = selectedNodes[0]; if (selectedNode->isPositiveNode()) return selectedNode; else return selectedNode->getReverseComplement(); } else if (selectedNodes.size() == 2) { DeBruijnNode * selectedNode1 = selectedNodes[0]; DeBruijnNode * selectedNode2 = selectedNodes[1]; if (selectedNode1->getReverseComplement() == selectedNode2) { if (selectedNode1->isPositiveNode()) return selectedNode1; else return selectedNode2; } else return 0; } return 0; } double MyGraphicsScene::getTopZValue() { double topZ = 0.0; QList allItems = items(); for (int i = 0; i < allItems.size(); ++i) { QGraphicsItem * item = allItems[i]; if (i == 0) topZ = item->zValue(); else { double z = item->zValue(); if (z > topZ) topZ = z; } } return topZ; } //Expands the scene rectangle a bit beyond the items so they aren't drawn right to the edge. void MyGraphicsScene::setSceneRectangle() { QRectF boundingRect = itemsBoundingRect(); double width = boundingRect.width(); double height = boundingRect.height(); double margin = std::max(width, height); margin *= 0.05; //5% margin setSceneRect(boundingRect.left() - margin, boundingRect.top() - margin, width + 2 * margin, height + 2 * margin); } //After the user drags nodes, it may be necessary to expand the scene rectangle //if the nodes were moved out of the existing rectangle. void MyGraphicsScene::possiblyExpandSceneRectangle(std::vector * movedNodes) { QRectF currentSceneRect = sceneRect(); QRectF newSceneRect = currentSceneRect; for (size_t i = 0; i < movedNodes->size(); ++i) { GraphicsItemNode * node = (*movedNodes)[i]; QRectF nodeRect = node->boundingRect(); newSceneRect = newSceneRect.united(nodeRect); } if (newSceneRect != currentSceneRect) setSceneRect(newSceneRect); }