00001 #include "constants.h"
00002
00003 #include "drawAlgorithm.h"
00004 #include "editor.h"
00005 #include "commands.h"
00006 #include "stateManager.h"
00007 #include "transitionManager.h"
00008 #include "state.h"
00009 #include "oneStateTransition.h"
00010 #include "twoStatesTransition.h"
00011 #include "automataCreator.h"
00012 #include "transition.h"
00013
00014 #include "iautomaton.h"
00015 #include "itransition.h"
00016 #include "istate.h"
00017
00018 #include <QSharedPointer>
00019 #include <QPoint>
00020 #include <QUndoCommand>
00021 #include <QQueue>
00022 #include <QStack>
00023 #include <QList>
00024
00025 #include <limits>
00026
00027 #include <queue>
00028 #include <vector>
00029 #include <stack>
00030 using namespace std;
00031
00032 #ifdef TESTING_DRAWING
00033 # define DBGLOG_DRAW(x) DBGLOG_("DRAWING", x)
00034 #else
00035 # define DBGLOG_DRAW(x)
00036 #endif
00037
00038
00039
00040 const int BaseDrawAlgorithm::X_STEP = GRID_STEP*3;
00041 const int BaseDrawAlgorithm::Y_STEP = GRID_STEP*3;
00042
00043 State* createState(Editor *editor, const QPoint &pos,
00044 const QSharedPointer<IState> &state)
00045 {
00046 StateManager *stateManager = StateManager::getInstance();
00047 TransitionManager *trManager = TransitionManager::getInstance();
00048
00049 State *newState = stateManager->createState(state->isFinal() ? "FinalState" : "State",
00050 editor, pos,
00051 state->getLabel(), state->getName(), false);
00052
00053 if (state->isInitial())
00054 {
00055 Transition *newTransition = trManager->createOneStateTransition("Initial", editor,
00056 newState, "", NORTH_WEST, false);
00057 newTransition->assign();
00058 }
00059
00060 return newState;
00061 }
00062
00063 IState::TIStateList BaseDrawAlgorithm::getBFSSortedStates
00064 (const QSharedPointer<IAutomaton> &automaton) const
00065 {
00066 IState::TIStateList sortedStateList;
00067
00068 QQueue<QSharedPointer<IState> > openedStates;
00069 openedStates << automaton->getInitialStates();
00070
00071 IState::TIStateNameSet foundStates;
00072 QSharedPointer<IState> currentState;
00073
00074 while (!openedStates.empty())
00075 {
00076 currentState = openedStates.dequeue();
00077 foundStates << currentState->getName();
00078 sortedStateList << currentState;
00079
00080 foreach(const QSharedPointer<ITransition> &tr, currentState->getTransitions())
00081 {
00082 QString workState = tr->getDestinationState();
00083 if (foundStates.contains(workState)) continue;
00084
00085 foundStates << workState;
00086 openedStates << automaton->getState(workState);
00087 }
00088 }
00089
00090 return sortedStateList;
00091 }
00092
00093
00094 void BaseDrawAlgorithm::initPaths(const IState::TIStateList &states, const QString& fromStateName,
00095 TDistanceMap &distances, TPredecessorMap &predecessors) const
00096 {
00097 foreach(const QSharedPointer<IState> &state, states)
00098 {
00099 distances[state->getName()] = std::numeric_limits<unsigned int>::max();
00100 predecessors[state->getName()] = "";
00101 }
00102 distances[fromStateName] = 0;
00103 DBGLOG_DRAW(DBGPAR(distances));
00104 }
00105
00106 void BaseDrawAlgorithm::relax(const QString &u, const QString &v,
00107 TDistanceMap &distances, TPredecessorMap &predecessors) const
00108 {
00109
00110 if (distances[v] > distances[u] + 1 && distances[u] != std::numeric_limits<unsigned int>::max())
00111 {
00112 distances[v] = distances[u] + 1;
00113 predecessors[v] = u;
00114 }
00115 }
00116
00117 class DistanceComparator
00118 {
00119 public:
00120 DistanceComparator(const BaseDrawAlgorithm::TDistanceMap &dist)
00121 : d(&dist)
00122 {}
00123
00124 bool operator()(const QSharedPointer<IState> &s1, const QSharedPointer<IState> &s2) const
00125 {
00126 return (*d)[s1->getName()] > (*d)[s2->getName()];
00127 }
00128
00129 protected:
00130 const BaseDrawAlgorithm::TDistanceMap *d;
00131 };
00132
00133 void BaseDrawAlgorithm::fillDijkstraShortestPaths(const QSharedPointer<IAutomaton> &automaton,
00134 const QString &fromStateName,
00135 TDistanceMap &distances, TPredecessorMap &predecessors) const
00136 {
00137 initPaths(automaton->getStates(), fromStateName, distances, predecessors);
00138
00139 typedef priority_queue<QSharedPointer<IState>, vector<QSharedPointer<IState> >, DistanceComparator> TQueue;
00140 TQueue stateQueue(DistanceComparator((const TDistanceMap&) distances));
00141 stack<QSharedPointer<IState> > stateStack;
00142
00143 foreach(const QSharedPointer<IState> &state, automaton->getStates())
00144 {
00145 stateQueue.push(state);
00146 }
00147
00148 while (!stateQueue.empty())
00149 {
00150 QSharedPointer<IState> uState = stateQueue.top();
00151 stateQueue.pop();
00152
00153 while (!stateQueue.empty())
00154 {
00155 stateStack.push(stateQueue.top());
00156 stateQueue.pop();
00157 }
00158
00159 IState::TIStateNameList adj = uState->getAdjacentStates();
00160 foreach(const QString &v, adj)
00161 {
00162 relax(uState->getName(), v, distances, predecessors);
00163 }
00164
00165 while(!stateStack.empty())
00166 {
00167 stateQueue.push(stateStack.top());
00168 stateStack.pop();
00169 }
00170 }
00171 }
00172
00173 IState::TIStateNameSet BaseDrawAlgorithm::getStatesInDistance
00174 (unsigned int distance, const TDistanceMap &distances) const
00175 {
00176 IState::TIStateNameSet result;
00177
00178 TDistanceMap::const_iterator it = distances.begin();
00179 while(it != distances.end())
00180 {
00181 if (it.value() == distance) result << it.key();
00182 ++it;
00183 }
00184
00185 return result;
00186 }
00187
00188 unsigned int BaseDrawAlgorithm::getMaxDistance(const TDistanceMap &distances) const
00189 {
00190 unsigned int result = 0;
00191
00192 TDistanceMap::const_iterator it = distances.begin();
00193 while(it != distances.end())
00194 {
00195 if (it.value() > result && it.value() != std::numeric_limits<unsigned int>::max())
00196 result = it.value();
00197 ++it;
00198 }
00199
00200 return result;
00201 }
00202
00203 int transitionCountBetween(const State &s1, const State &s2)
00204 {
00205 int result = 0;
00206
00207 QList<Transition*> trList = s1.getOutgoingTransitions();
00208 foreach(Transition *tr, trList)
00209 {
00210 if (tr->getDestinationState() == s2.getName())
00211 result++;
00212 }
00213
00214 trList = s2.getOutgoingTransitions();
00215 foreach(Transition *tr, trList)
00216 {
00217 if (tr->getDestinationState() == s1.getName())
00218 result++;
00219 }
00220
00221 return result;
00222 }
00223
00224 void setParams(const State &s1, const State &s2,
00225 const QPoint &startPos, const int xStep, const int yStep,
00226 QString &typeName, float &arcAngle, bool &leftOriented)
00227 {
00228 int count = transitionCountBetween(s1, s2);
00229
00230 const bool leftToRight = s1.pos().x() <= s2.pos().x();
00231
00232 if (count == 0 &&
00233 abs(s1.pos().x() - s2.pos().x()) <= xStep &&
00234 abs(s1.pos().y() - s2.pos().y()) <= yStep)
00235 {
00236 typeName = "Edge";
00237 leftOriented = leftToRight ? s1.pos().y() <= startPos.y()
00238 : s1.pos().y() > startPos.y();
00239 return;
00240 }
00241
00242 typeName = "VArc";
00243
00244 const float angleStep = 30;
00245
00246 if (s1.pos().y() <= startPos.y())
00247 {
00248 arcAngle = (count % 2 == 0) ?
00249 (leftToRight ? angleStep * (count/2 + 1) : -angleStep * (count/2 + 1)) :
00250 (leftToRight ? -angleStep * ((count-1)/2 + 1) : angleStep * ((count-1)/2 + 1));
00251
00252 leftOriented = leftToRight ?
00253 (count % 2 == 0) ? true : false
00254 :
00255 (count % 2 == 0) ? false : true;
00256 }
00257 else
00258 {
00259 arcAngle = (count % 2 == 0) ?
00260 (leftToRight ? -angleStep * (count/2 + 1) : angleStep * (count/2 + 1)) :
00261 (leftToRight ? angleStep * ((count-1)/2 + 1) : -angleStep * ((count-1)/2 + 1));
00262
00263 leftOriented = leftToRight ?
00264 (count % 2 == 0) ? false : true
00265 :
00266 (count % 2 == 0) ? true : false;
00267 }
00268 }
00269
00270 #ifdef USE_TRANSITION_GROUPING_IN_DRAWING_ALGORITHM
00271
00272 ITransition::TITransitionList BaseDrawAlgorithm::getGroupedTransitions(const QSharedPointer<IAutomaton> &automaton) const
00273 {
00274 ITransition::TITransitionList transitions = automaton->getTransitions();
00275
00276 typedef QPair<QString, QString> TNamePair;
00277 typedef QMap<TNamePair, QSharedPointer<TransitionImpl> > TTransitionMap;
00278 TTransitionMap transitionMap;
00279 QSharedPointer<TransitionImpl> groupedTr(NULL);
00280
00281
00282 foreach(const QSharedPointer<ITransition> &transition, transitions)
00283 {
00284 TNamePair namePair(transition->getSourceState(), transition->getDestinationState());
00285
00286 if (transitionMap.contains(namePair))
00287 {
00288 groupedTr = transitionMap[namePair];
00289 groupedTr->setCharacters(groupedTr->getCharacters() | transition->getCharacters());
00290 }
00291
00292 if (!groupedTr)
00293 {
00294 groupedTr = QSharedPointer<TransitionImpl>(
00295 new TransitionImpl(transition->getSourceState(),
00296 transition->getDestinationState(),
00297 transition->getCharacters(),
00298 NULL));
00299 }
00300
00301 Q_ASSERT(groupedTr);
00302 transitionMap[namePair] = groupedTr;
00303
00304 groupedTr.clear();
00305 Q_ASSERT(groupedTr == NULL);
00306 }
00307
00308 ITransition::TITransitionList groupedTransitions;
00309
00310 for (TTransitionMap::Iterator trIt = transitionMap.begin();
00311 trIt != transitionMap.end();
00312 ++trIt)
00313 {
00314 if ((*trIt)->passOn(automaton->getEpsilonSymbol()))
00315 {
00316 groupedTransitions << QSharedPointer<TransitionImpl>(
00317 new TransitionImpl((*trIt)->getSourceState(), (*trIt)->getDestinationState(),
00318 ITransition::TCharSet() << automaton->getEpsilonSymbol(), NULL));
00319
00320 if ((*trIt)->getCharacters().count() == 1) continue;
00321 }
00322
00323 Q_ASSERT(!((*trIt)->getCharacters()-(ITransition::TCharSet() << automaton->getEpsilonSymbol())).isEmpty());
00324
00325 groupedTransitions << QSharedPointer<TransitionImpl>(
00326 new TransitionImpl((*trIt)->getSourceState(), (*trIt)->getDestinationState(),
00327 (*trIt)->getCharacters()-(ITransition::TCharSet() << automaton->getEpsilonSymbol()),
00328 NULL));
00329 }
00330
00331 return groupedTransitions;
00332 }
00333
00334 #endif
00335
00336 void BaseDrawAlgorithm::drawTransitions(Editor *editor,
00337 const Editor::TStateMap &states,
00338 const QSharedPointer<IAutomaton> &automaton,
00339 const ITransition::TITransitionList &transitions,
00340 const QPoint &startPoint) const
00341 {
00342 TransitionManager *trManager = TransitionManager::getInstance();
00343 Transition *newTransition;
00344
00345 DBGLOG_DRAW(DBGPAR(states));
00346
00347 foreach(const QSharedPointer<ITransition> &tr, transitions)
00348 {
00349 State *s1 = editor->getStateByName(states, tr->getSourceState());
00350 DBGLOG_DRAW(DBGPAR(tr->getSourceState()));
00351 Q_ASSERT(s1);
00352
00353 QString label = charactersToLabel(automaton, tr);
00354
00355 if (tr->getSourceState() == tr->getDestinationState())
00356 {
00357 newTransition = trManager->createOneStateTransition(
00358 "Loop",
00359 editor,
00360 s1,
00361 label,
00362 s1->pos().y() < startPoint.y() ? NORTH : SOUTH,
00363 false);
00364 }
00365 else
00366 {
00367 State *s2 = editor->getStateByName(states, tr->getDestinationState());
00368 Q_ASSERT(s2);
00369
00370 float arcAngle = 30;
00371 bool leftOriented = true;
00372 QString typeName = "Edge";
00373 setParams(*s1, *s2, startPoint, X_STEP, Y_STEP, typeName, arcAngle, leftOriented);
00374
00375 newTransition = trManager->createTwoStatesTransition
00376 (typeName,
00377 editor,
00378 s1,
00379 s2,
00380 label,
00381 leftOriented,
00382 false);
00383
00384 newTransition->setArcAngle(arcAngle);
00385 }
00386
00387 newTransition->adjust();
00388 newTransition->assign();
00389 }
00390 }
00391
00392 QString BaseDrawAlgorithm::charactersToLabel(const QSharedPointer<IAutomaton> &automaton,
00393 const QSharedPointer<ITransition> &transition) const
00394 {
00395 const int charCount = transition->getCharacters().count();
00396 const int alphCount = automaton->getAlphabet().count();
00397 QString label = charCount == alphCount ? "A" :
00398 charCount > alphCount/2 ? QString("A - \\{%1\\}").arg(
00399 QStringList((automaton->getAlphabet()-transition->getCharacters()).toList()).join(",")) :
00400 QStringList(transition->getCharacters().toList()).join(",");
00401
00402 return label;
00403 }
00404
00405
00406
00407
00408
00409
00410
00411 QList<State*> NaiveDrawAlgorithm::drawAutomaton(Editor *editor, const QSharedPointer<IAutomaton> &automaton)
00412 {
00413 StateManager *stateManager = StateManager::getInstance();
00414 TransitionManager *trManager = TransitionManager::getInstance();
00415
00416 IState::TIStateList automataStates = getBFSSortedStates(automaton);
00417 QPoint statePos(QPoint(1,1));
00418 int i = 0;
00419
00420 Editor::TStateMap states;
00421 State *newState;
00422 Transition *newTransition;
00423 foreach(const QSharedPointer<IState> &state, automataStates)
00424 {
00425 newState = stateManager->createState("State", editor, statePos,
00426 state->getLabel(), state->getName(), false);
00427
00428 if (state->isInitial())
00429 {
00430 newTransition = trManager->createOneStateTransition("Initial", editor, newState, "", WEST, false);
00431 newTransition->assign();
00432 }
00433
00434 if (state->isFinal())
00435 newState->setDoubleBorder(true);
00436
00437 states[newState->getName()] = newState;
00438
00439 statePos += QPoint(GRID_STEP*2,GRID_STEP*2);
00440 ++i;
00441 }
00442
00443 foreach(const QSharedPointer<IState> &state, automataStates)
00444 {
00445 foreach(const QSharedPointer<ITransition> &tr, state->getTransitions())
00446 {
00447 State *s1 = editor->getStateByName(states, state->getName());
00448 QString label = QStringList(tr->getCharacters().toList()).join(",");
00449 if (tr->getSourceState() == tr->getDestinationState())
00450 {
00451 newTransition = trManager->createOneStateTransition("Loop", editor, s1, label, NORTH, false);
00452 }
00453 else
00454 {
00455 State *s2 = editor->getStateByName(states, tr->getDestinationState());
00456 newTransition = trManager->createTwoStatesTransition("Edge", editor, s1, s2, label, true, false);
00457 }
00458
00459 newTransition->adjust();
00460 newTransition->assign();
00461 }
00462 }
00463
00464 return states.values();
00465 }
00466
00467
00468
00469
00470
00471
00472
00473 QList<State*> FarthestFinalDrawAlgorithm::drawAutomaton
00474 (Editor *editor, const QSharedPointer<IAutomaton> &automaton)
00475 {
00476 DBGLOG_DRAW("state count=" << automaton->getStates().count());
00477 if (automaton->getStates().isEmpty()) return QList<State*>();
00478
00479 Editor::TStateMap states;
00480 QPoint startPoint(editor->toScenePos(QPoint(1,1)));
00481
00482
00483 TDistanceMap distances;
00484 TPredecessorMap predecessors;
00485
00486 IState::TIStateList initialStates = automaton->getInitialStates();
00487 QSharedPointer<IState> initialState = initialStates.isEmpty() ? automaton->getStates()[0]
00488 : initialStates[0];
00489
00490 fillDijkstraShortestPaths(automaton, initialState->getName(), distances, predecessors);
00491
00492 DBGLOG_DRAW(DBGPAR(distances));
00493 DBGLOG_DRAW(DBGPAR(predecessors));
00494
00495 QSharedPointer<IState> farthestFinalState(initialState);
00496 unsigned int farthest = 0;
00497 IState::TIStateList finalStates = automaton->getFinalStates();
00498 if (finalStates.isEmpty())
00499 {
00500 finalStates = automaton->getStates();
00501 }
00502
00503 foreach(const QSharedPointer<IState> &state, finalStates)
00504 {
00505 const unsigned int &distance = distances[state->getName()];
00506 if (distance > farthest &&
00507 distance != UINT_MAX)
00508 {
00509 farthest = distance;
00510 farthestFinalState = state;
00511 }
00512 }
00513
00514 DBGLOG_DRAW(DBGPAR(farthestFinalState->getName()));
00515
00516 QSharedPointer<IState> currentState;
00517 QString currentStateName;
00518 QPoint statePos(0,0);
00519
00520 QStack<QSharedPointer<IState> > statesToBeDraw;
00521 statesToBeDraw << farthestFinalState;
00522 currentStateName = farthestFinalState->getName();
00523 while(predecessors[currentStateName] != "")
00524 {
00525 currentState = automaton->getState(predecessors[currentStateName]);
00526 statesToBeDraw << currentState;
00527 currentStateName = currentState->getName();
00528 }
00529
00530 #ifndef QT_NO_DEBUG_OUTPUT
00531 foreach(const QSharedPointer<IState> &state, statesToBeDraw)
00532 {
00533 DBGLOG_DRAW("draw:" << state->getName());
00534 }
00535 #endif
00536
00537 unsigned int i = 0;
00538 State *newState;
00539
00540 const unsigned int maxDistance = getMaxDistance(distances);
00541 Q_ASSERT(maxDistance != UINT_MAX);
00542
00543
00544 while(!statesToBeDraw.empty())
00545 {
00546 currentState = statesToBeDraw.pop();
00547 newState = createState(editor, statePos + startPoint, currentState);
00548
00549 states[newState->getName()] = newState;
00550
00551 if (statesToBeDraw.count() == 1)
00552 statePos = QPoint(X_STEP * maxDistance, 0);
00553 else
00554 statePos += QPoint(X_STEP, 0);
00555
00556 ++i;
00557 }
00558
00559 int max_j = 1;
00560
00561 for (unsigned int d = 1; d <= maxDistance; ++d)
00562 {
00563 IState::TIStateNameSet levelStates = getStatesInDistance(d, distances);
00564 foreach(const QString &stateName, levelStates)
00565 {
00566 if (!states.contains(stateName))
00567 statesToBeDraw << automaton->getState(stateName);
00568 }
00569
00570
00571 int j = 1;
00572
00573 while(!statesToBeDraw.empty())
00574 {
00575 QPoint curStatePos(X_STEP * d,
00576 Y_STEP * (j % 2 ? -j : j-1));
00577 DBGLOG_DRAW(DBGPAR(curStatePos));
00578
00579 currentState = statesToBeDraw.pop();
00580 newState = createState(editor, curStatePos + startPoint, currentState);
00581
00582 states[newState->getName()] = newState;
00583
00584 ++j;
00585 ++i;
00586 }
00587
00588 if (j > max_j) max_j = j;
00589 }
00590
00591
00592 IState::TIStateNameSet inaccessibleStates = automaton->getStateNameList().toSet();
00593 inaccessibleStates -= states.keys().toSet();
00594 DBGLOG_DRAW(DBGPAR(inaccessibleStates));
00595
00596
00597 const unsigned int minimalSBS = 5;
00598 const unsigned int sbs = (maxDistance > minimalSBS) ? maxDistance : minimalSBS;
00599
00600 int row = max_j;
00601 i = 0;
00602 foreach(const QString &stateName, inaccessibleStates)
00603 {
00604 QSharedPointer<IState> state = automaton->getState(stateName);
00605 Q_ASSERT(state);
00606
00607 QPoint curStatePos(X_STEP * i,
00608 Y_STEP * ( row % 2 ? -row : row-1));
00609 DBGLOG_DRAW(DBGPAR(curStatePos));
00610
00611 newState = createState(editor, curStatePos + startPoint, state);
00612 states[newState->getName()] = newState;
00613
00614 ++i;
00615 if (i >= sbs) { i = 0; row++; }
00616 }
00617
00618 #ifdef USE_TRANSITION_GROUPING_IN_DRAWING_ALGORITHM
00619 drawTransitions(editor, states, automaton, getGroupedTransitions(automaton), startPoint);
00620 #else
00621 drawTransitions(editor, states, automaton, automaton->getTransitions(), startPoint);
00622 #endif
00623
00624 return states.values();
00625 }
00626
00627
00628
00629
00630
00631
00632
00633 GraphVizDrawAlgorithm::GraphVizDrawAlgorithm(IGraphViz *graphVizWrapper)
00634 : m_graphVizWrapper(graphVizWrapper)
00635 {
00636
00637 }
00638
00639 QList<State*> GraphVizDrawAlgorithm::drawAutomaton
00640 (Editor *editor, const QSharedPointer<IAutomaton> &automaton)
00641 {
00642 DBGLOG_DRAW("state count=" << automaton->getStates().count());
00643 if (automaton->getStates().isEmpty()) return QList<State*>();
00644
00645 QSharedPointer<IGVGraph> graph = m_graphVizWrapper->createGraph();
00646
00647 IState::TIStateList states = automaton->getStates();
00648 foreach(const QSharedPointer<IState> &state, states)
00649 {
00650 graph->addNode(state->getName());
00651 }
00652
00653 ITransition::TITransitionList transitions = automaton->getTransitions();
00654 foreach(const QSharedPointer<ITransition> &transition, transitions)
00655 {
00656 graph->addEdge(transition->getSourceState(), transition->getDestinationState(),
00657 charactersToLabel(automaton, transition));
00658 }
00659
00660 graph->layoutGraphUsingDot();
00661
00662 #ifdef TESTING_GRAPHVIZDRAWER
00663 graph->renderToFile("testGraphVizDrawer.png");
00664 #endif
00665
00666 Editor::TStateMap newStates;
00667
00668 foreach(const QSharedPointer<IState> &state, states)
00669 {
00670 QPoint pos = graph->getNode(state->getName())->getPos();
00671 pos.setY(editor->scene()->height() - pos.y());
00672
00673 State *newState = createState(editor, pos , state);
00674 newStates[newState->getName()] = newState;
00675 }
00676
00677 drawTransitionsAccordingToGV(editor, newStates, automaton, graph);
00678
00679 return newStates.values();
00680 }
00681
00682 void GraphVizDrawAlgorithm::drawTransitionsAccordingToGV(
00683 Editor *editor,
00684 const Editor::TStateMap &states,
00685 const QSharedPointer<IAutomaton> &automaton,
00686 const QSharedPointer<IGVGraph> &graph) const
00687 {
00688
00689
00690 TransitionManager *trManager = TransitionManager::getInstance();
00691
00692 QSharedPointer<IGVNode> node = graph->getFirstNode();
00693 while(node)
00694 {
00695 int e_idx = 0;
00696 QSharedPointer<IState> state = automaton->getState(node->getName());
00697 int outTrSize = state->getTransitions().size();
00698 QSharedPointer<IGVEdge> edge = node->getFirstOutEdge();
00699 while(edge)
00700 {
00701 IGVEdge::TCPList bezierCP = convertCPToBezierCP(edge);
00702 Transition *newTr = NULL;
00703 Q_ASSERT(e_idx < outTrSize); Q_UNUSED(outTrSize)
00704 QString label = edge->getLabel();
00705 bool dir;
00706 ETransitionType type = getTransitionType(edge, bezierCP);
00707
00708 State *s1 = states[edge->getTailName()];
00709 State *s2 = states[edge->getHeadName()];
00710
00711 switch (type)
00712 {
00713 case eLoop:
00714 DBGLOG_DRAW("eLoop");
00715 dir = bezierCP[0].y() < bezierCP[1].y() ? NORTH : SOUTH;
00716 newTr = trManager->createOneStateTransition("Loop", editor, s1, label, dir, false);
00717 break;
00718 case eLine:
00719 DBGLOG_DRAW("eLine");
00720 dir = bezierCP[0].x() < bezierCP[1].x();
00721 newTr = trManager->createTwoStatesTransition("Edge", editor, s1, s2, label, dir, false);
00722 break;
00723 case eCurve:
00724 DBGLOG_DRAW("eCurve");
00725 {
00726 dir = false;
00727 newTr = trManager->createTwoStatesTransition("VCurve", editor, s1, s2, label, dir, false);
00728
00729 const QPoint p11 = QPoint(s1->pos().x(), s1->pos().y());
00730 const QPoint p21 = QPoint(s2->pos().x(), s2->pos().y());
00731 const QPoint p12 = QPoint(bezierCP[0].x(), editor->scene()->height()-bezierCP[0].y());
00732 const QPoint p22 = QPoint(bezierCP[3].x(), editor->scene()->height()-bezierCP[3].y());
00733
00734 const int arcAngle = qRound(QLineF(p11, p12).angle());
00735 const int arcAngleB = qRound(QLineF(p21, p22).angle());
00736 newTr->setArcAngle(arcAngle);
00737 newTr->setArcAngleB(arcAngleB);
00738
00739 newTr->setNCurv(0.8f);
00740 }
00741 break;
00742 default:
00743 Q_ASSERT(0 && "undefined value!");
00744 break;
00745 }
00746
00747 newTr->adjust();
00748 newTr->assign();
00749 e_idx++;
00750 edge = edge->getNextOutEdge();
00751 }
00752 node = node->getNextNode();
00753 }
00754 }
00755
00756 IGVEdge::TCPList GraphVizDrawAlgorithm::convertCPToBezierCP(const QSharedPointer<IGVEdge> &edge) const
00757 {
00758 IGVEdge::TCPList controlPoints = edge->getControlPoints();
00759 Q_ASSERT(controlPoints.size() >= 4);
00760 DBGLOG_DRAW(DBGPAR(controlPoints));
00761
00762 IGVEdge::TCPList bezierCP;
00763 bezierCP << controlPoints[0];
00764
00765
00766 const int pos = controlPoints.size() / 4 + (controlPoints.size() % 4 ? 1 : 0);
00767 Q_ASSERT(controlPoints.size() > pos);
00768 bezierCP << controlPoints[pos];
00769 bezierCP << controlPoints[controlPoints.size()-pos-1];
00770
00771 bezierCP << controlPoints[controlPoints.size()-1];
00772 DBGLOG_DRAW(DBGPAR(bezierCP));
00773
00774 return bezierCP;
00775 }
00776
00777 GraphVizDrawAlgorithm::ETransitionType GraphVizDrawAlgorithm::getTransitionType
00778 (const QSharedPointer<IGVEdge> &edge, const IGVEdge::TCPList &bezierCP) const
00779 {
00780
00781 if (edge->getHeadName() == edge->getTailName()) return eLoop;
00782 QLineF line = QLineF(bezierCP.first(), bezierCP.last());
00783 const qreal angle = line.angle();
00784 const int bound = 2;
00785 for(int i=1; i<bezierCP.size()-1; ++i)
00786 {
00787 line.setP2(bezierCP[i]);
00788 const qreal angle2 = line.angle();
00789 if (angle < angle2-bound || angle > angle2+bound) return eCurve;
00790 }
00791 return eLine;
00792 }
00793
00794