void PHScene::doRender(void) { // retrieve graph GVGraphPtr graph = ph->toGVGraph(); // create GProcesses linking actual processes (PH info) with GVNodes (display info) QList<GVNode> gnodes = graph->nodes(); for (GVNode &gn : gnodes) { for (SortPtr &s : ph->getSorts()) { for (ProcessPtr &p : s->getProcesses()) { if (gn.name == makeProcessName(p)) { GProcessPtr gp = make_shared<GProcess>(p, gn, graph->getDPI()); processes.push_back(gp); p.get()->setGProcess(gp); } } } } // create GSorts linking actual sorts (PH info) with GVClusters (display info) QList<GVCluster> gclusters = graph->clusters(); for (GVCluster &gc : gclusters) for (SortPtr &s : ph->getSorts()) if (gc.name == makeClusterName(s->getName())) sorts.insert(GSortEntry(s->getName(), make_shared<GSort>(s, gc))); // create GActions linking actual actions to GVEdges (display info) createActions(graph); draw(); }
void PHScene::updateGraph() { GVGraphPtr graph = ph->updateGVGraph(this); // update GProcess items' positions // using nested loops to make sure that each GVNode matches related GProcess list<ProcessPtr> phProcesses = ph->getProcesses(); for (GVNode &gvnode : graph->nodes()) for (list<ProcessPtr>::iterator it = phProcesses.begin(); it != phProcesses.end(); ++it) if (gvnode.name == makeProcessName(*it)) { (*it)->getGProcess()->setNode(gvnode); break; } // update GSort items' positions (including related GProcess items) map<string, GSortPtr>::iterator it; for(it = sorts.begin(); it != sorts.end(); it++) { it->second->updatePosition(); } // create GActions linking actual actions to GVEdges (display info) actions.clear(); createActions(graph); for (GActionPtr &a : actions) addItem(a->getDisplayItem()); // hide actions that are related to hidden sorts showActions(); }
void PHScene::createActions(GVGraphPtr graph) { // retrieve list of GVEdge structs from graphviz geometry data QList<GVEdge> gEdges = graph->edges(); // create GAction items using std::pair; pair<GVEdge*, GVEdge*> edges; for (ActionPtr &a : ph->getActions()) { edges.first = NULL; edges.second = NULL; // find graph edges that match the Action for (GVEdge &gEdge : gEdges) { // check the hit of the Action if ( makeProcessName(a->getSource()) == gEdge.source && makeProcessName(a->getTarget()) == gEdge.target ) edges.first = &gEdge; // check the bounce (result) of the Action if ( makeProcessName(a->getTarget()) == gEdge.source && makeProcessName(a->getResult()) == gEdge.target ) edges.second = &gEdge; // if match, add Action to objects to be drawn if (edges.first != NULL && edges.second != NULL) { actions.push_back(make_shared<GAction>(a, *(edges.first), *(edges.second), this)); break; } } } }
// represent the PH as a mathematical graph and calculates a layout GVGraphPtr PH::toGVGraph(void) { GVGraphPtr res = make_shared<GVGraph>(QString("PH Graph")); QString s; QString posVal; // add Sorts and Processes (well named) for (auto &e : sorts) { s = makeClusterName(e.second->getName()); res->addSubGraph(s); res->getSubGraph(s)->setLabel(QString::fromStdString(e.second->getName())); // add constraints on Processes: displayed vertically in their Sort for (int i = 0; i < e.second->countProcesses(); i++) { res->getSubGraph(s)->addNode(makeProcessName(e.second->getProcess(i))); posVal = QString::number(0).append(",").append(QString::number(i)).append("!"); _agset(res->getNode(makeProcessName(e.second->getProcess(i))), "pos", posVal); } } // let graphviz calculate an appropriate layout res->applyLayout(); return res; }
GVGraphPtr PH::updateGVGraph(PHScene *scene) { // TODO make sure graph name is always unique in the application (see GVGraph constructor) GVGraphPtr res = make_shared<GVGraph>(QString("PH Graph")); // add Processes as Nodes (well named and well located) QString clusterName, processName, posVal; qreal nodeX, nodeY; for (auto &e : scene->getGSorts()) { clusterName = makeClusterName(e.second->getSort()->getName()); // add constraints on Processes: positions retrieved from graphics scene for (int i(0); i < e.second->getSort()->countProcesses(); i++) { processName = makeProcessName(e.second->getSort()->getProcess(i)); res->addNode(processName); // TODO use GProcess ellipse's absolute coordinates instead (maybe avoids progressive vertical shifting that occurs sometimes between processes and actions of a sort) nodeX = (qreal) e.second->getSort()->getProcess(i)->getGProcess()->getNode()->centerPos.x() / res->getDPI(); nodeY = - (qreal) e.second->getSort()->getProcess(i)->getGProcess()->getNode()->centerPos.y() / res->getDPI(); posVal = QString::number(nodeX).append(",").append(QString::number(nodeY)).append("!"); _agset(res->getNode(processName), "pos", posVal); } } // add Actions as Edges (well named) for (ActionPtr &a : actions) { res->addEdge( makeProcessName(a->getSource()) , makeProcessName(a->getTarget())); res->addEdge( makeProcessName(a->getTarget()) , makeProcessName(a->getResult())); } // BUG FIXING ATTEMPT: // to force hits' heads and bounces' tails to coincide if(MainWindow::mwThis->getDisplayMode() == 0){ const int nbPorts(3); const int nbResult(5); int i(0); int j(0); QStringList target; QStringList result; QStringList source; // add Actions (well named) for (ActionPtr &a : actions) { res->addEdge( makeProcessName(a->getSource()) , makeProcessName(a->getTarget())); res->addEdge( makeProcessName(a->getTarget()) , makeProcessName(a->getResult())); int xSource = a->getSource()->getGProcess()->getNode()->centerPos.x(); int ySource = a->getSource()->getGProcess()->getNode()->centerPos.y(); int xTarget = a->getTarget()->getGProcess()->getNode()->centerPos.x(); int yTarget = a->getTarget()->getGProcess()->getNode()->centerPos.y(); //int xResult = a->getResult()->getGProcess()->getNode()->centerPos.x(); int yResult = a->getResult()->getGProcess()->getNode()->centerPos.y(); if((xSource > xTarget && ySource < yTarget) || (xSource >= xTarget && ySource < yTarget) || (xSource > xTarget && ySource <= yTarget)){ target.insert(0,"n"); target.insert(1,"ne"); target.insert(2,"e"); source.insert(0,"s"); source.insert(1,"sw"); source.insert(2,"w"); } else if((xSource < xTarget && ySource < yTarget) || (xSource <= xTarget && ySource < yTarget) || (xSource < xTarget && ySource <= yTarget)){ target.insert(0,"n"); target.insert(1,"nw"); target.insert(2,"w"); source.insert(0,"s"); source.insert(1,"se"); source.insert(2,"e"); } else if((xSource > xTarget && ySource > yTarget) || (xSource >= xTarget && ySource > yTarget) || (xSource > xTarget && ySource >= yTarget)){ target.insert(0,"e"); target.insert(1,"se"); target.insert(2,"s"); source.insert(0,"n"); source.insert(1,"nw"); source.insert(2,"w"); } else if((xSource < xTarget && ySource > yTarget) || (xSource <= xTarget && ySource > yTarget) || (xSource < xTarget && ySource >= yTarget)){ target.insert(0,"w"); target.insert(1,"sw"); target.insert(2,"s"); source.insert(0,"n"); source.insert(1,"ne"); source.insert(2,"e"); } else if(xSource == xTarget && ySource == yTarget){ target.insert(0,"ne"); source.insert(0,"e"); } else{ target.insert(0,"_"); source.insert(0,"_"); } if(yResult < yTarget){ result.insert(0,"s"); result.insert(1,"se"); result.insert(2,"sw"); result.insert(3,"w"); result.insert(4,"e"); } else if(yResult > yTarget){ result.insert(0,"n"); result.insert(1,"nw"); result.insert(2,"w"); result.insert(3,"ne"); result.insert(4,"e"); } else{ result.insert(0,"_"); } // BUG FIXING ATTEMPT: // to force hits' heads and bounces' tails to coincide _agset(res->getEdge(makeProcessName(a->getSource()), makeProcessName(a->getTarget())), "tailport", source.at(i)); _agset(res->getEdge(makeProcessName(a->getSource()), makeProcessName(a->getTarget())), "headport", target.at(i)); _agset(res->getEdge(makeProcessName(a->getTarget()), makeProcessName(a->getResult())), "tailport", target.at(i)); _agset(res->getEdge(makeProcessName(a->getTarget()), makeProcessName(a->getResult())), "headport", result.at(j)); i = (i+1) % (nbPorts-1); j = (j+1) % (nbResult-1); } } else if(MainWindow::mwThis->getDisplayMode() == 1){ const int nbPorts(9); QString ports[nbPorts] = {"n", "ne", "e", "se", "s", "sw", "w", "nw", "_"}; int i(0); // add Actions (well named) for (ActionPtr &a : actions) { res->addEdge( makeProcessName(a->getSource()) , makeProcessName(a->getTarget())); res->addEdge( makeProcessName(a->getTarget()) , makeProcessName(a->getResult())); // BUG FIXING ATTEMPT: // to force hits' heads and bounces' tails to coincide _agset(res->getEdge(makeProcessName(a->getSource()), makeProcessName(a->getTarget())), "headport", ports[i]); _agset(res->getEdge(makeProcessName(a->getTarget()), makeProcessName(a->getResult())), "tailport", ports[i]); i = (i+1) % (nbPorts-1); } } res->applyLayout(); return res; }