• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

C:/CVUT/diplomka/Automata_editor/sources/drawAlgorithm.cpp

Go to the documentation of this file.
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> // priority 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 //<-- BaseDrawAlgorithm --------------------------------------------------------------------
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     // weights are ever 1, 2nd condition needed to avoid UINT overflow
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,                                    // in
00225                const QPoint &startPos, const int xStep, const int yStep,            // in 
00226                QString &typeName, float &arcAngle, bool &leftOriented)              // out
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     {   // no other transitions between states and states are side-by-side
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     {   // higher than backbone
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     // merge transitions between same states
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     // fill result list and dismember epsilon transition from other
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; // just epsilon transition
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" :  // whole alphabet
00398                                      charCount > alphCount/2 ? QString("A - \\{%1\\}").arg( // better to use alphabet minus syntax
00399                                          QStringList((automaton->getAlphabet()-transition->getCharacters()).toList()).join(",")) :
00400                                          QStringList(transition->getCharacters().toList()).join(","); // normal syntax
00401 
00402     return label;
00403 }
00404 
00405 //-------------------------------------------------------------------- BaseDrawAlgorithm -->
00406 
00407 
00408 
00409 //<-- NaiveDrawAlgorithm -------------------------------------------------------------------
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 //------------------------------------------------------------------- NaiveDrawAlgorithm -->
00468 
00469 
00470 
00471 //<-- FarthestFinalDrawAlgorithm -----------------------------------------------------------
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     // first find farthest final states -> it will be backbone
00483     TDistanceMap        distances;
00484     TPredecessorMap     predecessors;
00485     
00486     IState::TIStateList initialStates = automaton->getInitialStates();
00487     QSharedPointer<IState> initialState = initialStates.isEmpty() ? automaton->getStates()[0] // hack if no initial state exists!
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); // even if not final it's ok (if some final state is accessible, it has greater distatnce than 0)
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) // UINT_MAX has inaccessible states!!!
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     // draw backbone
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) // last state on backbone should be most on right
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     // draw left accessible states
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         // TODO: sort states according to predecessor state position
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     // draw inaccessible states
00592     IState::TIStateNameSet inaccessibleStates = automaton->getStateNameList().toSet();
00593     inaccessibleStates -= states.keys().toSet();
00594     DBGLOG_DRAW(DBGPAR(inaccessibleStates));
00595 
00596     // minimal count of unrelated states in single row (side-by-side)
00597     const unsigned int minimalSBS = 5; // TODO: should this be global constant in constants.h?
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 //----------------------------------------------------------- FarthestFinalDrawAlgorithm -->
00628 
00629 
00630 
00631 //<-- GraphVizDrawAlgorithm ----------------------------------------------------------------
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,                                        // in
00684         const Editor::TStateMap &states,                       // in
00685         const QSharedPointer<IAutomaton> &automaton,           // in
00686         const QSharedPointer<IGVGraph> &graph) const           // in
00687 {
00688     // TODO: implement detection of labels positions (maybe right dir will be good enough)
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     // number of control points is equal 3n+1 (n >= 1)
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     // try if it's on the same line
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 //---------------------------------------------------------------- GraphVizDrawAlgorithm -->

Generated on Tue Jan 4 2011 03:03:22 for Autoamata editor by  doxygen 1.7.0