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

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

Go to the documentation of this file.
00001 #include "constants.h"
00002 
00003 #include "mainwindow.h"
00004 #include "editor.h"
00005 #include "transition.h"
00006 #include "state.h"
00007 #include "label.h"
00008 #include "commands.h"
00009 #include "dialogs.h"
00010 #include "transforms.h"
00011 #include "stringProcessor.h"
00012 #include "automataCreator.h"
00013 
00014 #include <QGraphicsScene>
00015 #include <QEvent>
00016 #include <QGraphicsSceneMouseEvent>
00017 #include <QFontMetrics>
00018 #include <QLineF>
00019 #include <QPolygonF>
00020 #include <QPointF>
00021 #include <QPainterPath>
00022 
00023 #include <QTextStream>
00024 
00025 #include <math.h>
00026 
00027 #include <QtDebug>
00028 
00029 #ifdef PERFORMANCE_MEASUREMENT
00030 #   include <QTime>
00031 float       g_TimeSum = 0;
00032 int         g_TimeIterations = 0;
00033 const int   g_TimeIterationsCount = 100;
00034 #endif
00035 
00036 //<-- Transition -------------------------------------------------------------
00037 
00038 Transition::Transition(Editor *parent, State *ss, State *es,
00039                        bool d)
00040 :   editor(parent), startState(ss), endState(es), startPoint(ss->pos()),
00041     dimmed(d), checked(false),
00042     checkedColor(QColor(CheckedColor::r, CheckedColor::g, 
00043                         CheckedColor::b, CheckedColor::a))
00044 {
00045     setFlag(QGraphicsItem::ItemIsMovable, false);
00046     setFlag(QGraphicsItem::ItemIsSelectable, true);
00047 
00048     if (endState) // initial/final arrow or transition // TODO: implement this better
00049     {        
00050         endPoint = endState->pos();
00051     }
00052 
00053     // edge adjustable parameters - editor
00054     edgeLineStyle = editor->edgeLineStyle;
00055     edgeLineWidth = 1;
00056     edgeLineColor = editor->edgeLineColor;
00057     edgeLabelColor = editor->edgeLabelColor;
00058     edgeLabelScale = 1;
00059     edgeLineDblStatus = editor->edgeLineDblStatus;
00060 
00061     // transition parametres preset
00062     edgeLineBorderCoef = editor->edgeLineBorderCoef; //DEF_EDGE_LINE_BORDER_COEF;
00063     edgeLineBorderColor = editor->edgeLineBorderColor; //DEF_EDGE_LINE_BORDER_COLOR;
00064 
00065     edgeLineDblCoef = editor->edgeLineDblCoef; //DEF_EDGE_LINE_DBL_COEF;
00066     edgeLineDblSep = editor->edgeLineDblSep; //DEF_EDGE_LINE_DBL_SEP;
00067 
00068     // transition parametres dimmed
00069     dimEdgeLineStyle = editor->dimEdgeLineStyle; //DEF_DIM_LINE_STYLE;
00070     dimEdgeLineColor = editor->dimEdgeLineColor; //DEF_DIM_COLOR;
00071     dimEdgeLineCoef = editor->dimEdgeLineCoef; //DEF_DIM_EDGE_LINE_COEF;
00072     dimEdgeLabelColor = editor->dimEdgeLabelColor; //DEF_DIM_COLOR;
00073     
00074     m_labelFontSize = (int) (EDGE_LABEL_SIZE * edgeLabelScale * editor->edgeLabelScale);
00075     m_lineWidth = editor->edgeLineWidth * TR_LINE_VIEW_COEF;
00076     if (dimmed)
00077         m_lineWidth *= dimEdgeLineCoef;
00078     else
00079         m_lineWidth *= edgeLineWidth;
00080 
00081     // set default arrow polygon
00082     m_arrowPoints << QPointF(0,0); // center
00083 
00084     QLineF arrowLine(QPointF(0,0), QPointF(ARROW_LEN, 0)); // line in arrow direction
00085     QLineF normArrowLine = arrowLine.normalVector(); // width vector of arrow
00086     normArrowLine.translate(ARROW_LEN,0); // move width part to end of arrow
00087 
00088     normArrowLine.setLength(ARROW_WIDTH/2);
00089     m_arrowPoints << normArrowLine.p2(); // top point of arrow
00090 
00091     arrowLine.setLength(ARROW_LEN - 2);
00092     m_arrowPoints << arrowLine.p2(); // middle point of arrow
00093 
00094     normArrowLine.setLength(-ARROW_WIDTH/2);    
00095     m_arrowPoints << normArrowLine.p2(); // bottom point of arrow
00096 }
00097 
00098 Transition::~Transition()
00099 {
00100     if (label) delete label;
00101         
00102     qDeleteAll(nextLabels.begin(), nextLabels.end());
00103     nextLabels.clear();
00104 
00105     DBGLOG("Transition::~Transition");
00106 }
00107 
00108 QString Transition::getStartStateName() const
00109 {
00110     Q_ASSERT(startState && "invalid startState!");
00111     return startState->getName(); 
00112 }
00113  
00114 QString Transition::getEndStateName() const
00115 {
00116     Q_ASSERT(getEndState() && "invalid endState!");
00117     return getEndState()->getName(); // note that trLoop implements own getEndState
00118 }
00119 
00120 LabelX *Transition::getLabel() const
00121 {
00122     return (label) ? label : NULL;
00123 }
00124 
00125 QString Transition::getLabelText() const
00126 {
00127     if (label)
00128         return label->text();
00129     else
00130         return QString("");
00131 }
00132 
00133 void Transition::setLabelText(const QString &labelText)
00134 {    
00135     prepareGeometryChange();
00136     if (!label) 
00137     {
00138         RELLOG("trying to set label text to nonexistent label");
00139         return;
00140     }
00141     
00142     label->setText(labelText);
00143     setLabelPosition();    
00144 }
00145 
00146 void Transition::setLabelPosition(LabelX *pLabel, float pos, bool isLeft, int width, int height)
00147 {
00148     Q_ASSERT(pLabel);
00149 
00150     prepareGeometryChange();
00151     // vector for label position
00152     QLineF text_v = QLineF(mapToScene(p.pointAtPercent(pos)),mapToScene(p.pointAtPercent(pos+0.1)));
00153     text_v = text_v.normalVector(); // normal vector to curve
00154   
00155     text_v.setLength(isLeft ? TEXT_DISTANCE : -TEXT_DISTANCE); // because of unstable loop orientation    
00156     
00157     float label_x, label_y;
00158     float correct_x, correct_y;
00159     correct_x = -width/2 + 
00160                 (text_v.x2() - text_v.x1()) / TEXT_DISTANCE * // cos alfa
00161                 width/2;
00162     correct_y = -height/2 + 
00163                 (text_v.y2() - text_v.y1()) / TEXT_DISTANCE * // sin alfa
00164                 height/2;
00165     label_x = text_v.x2() + correct_x;
00166     label_y = text_v.y2() + correct_y;
00167   
00168     pLabel->setPos(label_x, label_y);
00169 }
00170 
00171 void Transition::setLabelPosition()
00172 {
00173     for (TLabelXList::Iterator labelIt = nextLabels.begin();
00174          labelIt != nextLabels.end();
00175          ++labelIt)
00176     {
00177         setLabelPosition(*labelIt, (*labelIt)->posParam(), (*labelIt)->left(),
00178             (*labelIt)->getWidth(), (*labelIt)->getHeight());
00179     }
00180 }
00181 
00182 void Transition::setLabelPos(float pos)
00183 {
00184     if (label) label->setPosParam(pos);
00185 }
00186 
00187 float Transition::getLabelPos() const
00188 {
00189     if (label) return label->posParam();
00190     else return DEF_EDGE_LAB_POS;
00191 }
00192 
00193 void Transition::addNextLabel(LabelX *pLabel)
00194 {    
00195     if (dimmed)
00196         pLabel->setColor(QColor(dimEdgeLabelColor));
00197     else
00198         pLabel->setColor(QColor(edgeLabelColor));
00199     nextLabels << pLabel;
00200 }
00201 
00202 void Transition::removeNextLabel(LabelX *pLabel)
00203 {
00204     if (!nextLabels.removeOne(pLabel))
00205         RELLOG("required label was not found!");
00206 }
00207 
00208 QPainterPath Transition::createShape(const QPainterPath &path, int bounds) const
00209 {
00210     QPainterPathStroker pathStroker;
00211     pathStroker.setWidth(bounds);
00212     
00213     QPainterPath strokePath = pathStroker.createStroke(path);    
00214 
00215     strokePath.addPolygon(pa);
00216     strokePath.closeSubpath();
00217 
00218     if (label && label->text() != "")
00219     {
00220         strokePath.addPolygon(mapFromItem(label, label->boundingRect()));
00221         strokePath.closeSubpath();
00222     }
00223 
00224     for (TLabelXList::ConstIterator labelIt = nextLabels.begin();
00225          labelIt != nextLabels.end();
00226          ++labelIt)
00227     {
00228         if ((*labelIt)->text() == "") continue;
00229         strokePath.addPolygon(mapFromItem((*labelIt), (*labelIt)->boundingRect()));
00230         strokePath.closeSubpath();
00231     }
00232 
00233     strokePath.setFillRule(Qt::WindingFill);
00234 
00235     return strokePath;
00236 }
00237 
00238 QPainterPath Transition::shape() const
00239 {    
00240     return getClickPath();
00241 }
00242 
00243 QRectF Transition::boundingRect() const
00244 {
00245     QRectF rect = getClickPath().boundingRect();
00246 
00247     if (label)
00248         rect |= (mapFromItem(label, label->boundingRect())).boundingRect(); // rect over pathRect and labelRect
00249 
00250     for (TLabelXList::ConstIterator labelIt = nextLabels.begin();
00251          labelIt != nextLabels.end();
00252          ++labelIt)
00253     {
00254         rect |= (mapFromItem((*labelIt), (*labelIt)->boundingRect())).boundingRect();
00255     }
00256 
00257     rect |= pa.boundingRect();
00258 
00259     return rect.adjusted(-5,-5,5,5); // rather adjusted for different widths of lines
00260 }
00261 
00262 void Transition::paintSelectionDecoration(QPainter *painter)
00263 {
00264     if (isSelected())
00265     {
00266         const QColor selectedColor(SelectedColor::r,SelectedColor::g,
00267                                    SelectedColor::b, SelectedColor::a);
00268         painter->setPen(QPen(selectedColor,1,Qt::DashLine));
00269 
00270         painter->strokePath(getSelectionPath(), painter->pen());
00271     }
00272 }
00273 
00274 void Transition::paint (QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
00275 {
00276     QColor lineC;
00277     Qt::PenStyle lineS;
00278 
00279     if (dimmed)
00280     {
00281         lineS = dimEdgeLineStyle;
00282         lineC = dimEdgeLineColor;
00283     }
00284     else
00285     {
00286         lineS = edgeLineStyle;
00287         lineC = edgeLineColor;
00288     }
00289 
00290     if (checked)
00291     {
00292         painter->setPen(QPen(checkedColor, m_lineWidth, lineS));
00293     }
00294     else
00295     {
00296         painter->setPen(QPen(lineC, m_lineWidth, lineS));
00297     }
00298 
00299     painter->setBrush(Qt::NoBrush);
00300     painter->strokePath(p, painter->pen());
00301 
00302     // draw arrow
00303     if (checked)
00304         painter->setBrush(checkedColor);
00305     else
00306         painter->setBrush(lineC);
00307 
00308     painter->drawPolygon(pa); // computed in adjust
00309 
00310     paintSelectionDecoration(painter);
00311 
00312 #ifdef TESTING_PAINTING
00313 #   ifdef TESTING_BOUNDING_RECT_PAINTING
00314         painter->setBrush(QBrush(QColor(50,255,0,100)));
00315         painter->fillRect(boundingRect(), painter->brush());
00316 #   endif
00317 
00318     painter->setBrush(QBrush(QColor(0,0,255,150)));
00319     painter->fillPath(shape(), painter->brush());
00320 #endif
00321 }
00322 
00323 void Transition::setDimmed(bool dim)
00324 {
00325     if (dimmed == dim) return; // not necessary
00326 
00327     dimmed = dim;
00328 
00329     if (dimmed)
00330         m_lineWidth = m_lineWidth * dimEdgeLineCoef/edgeLineWidth;
00331     else
00332         m_lineWidth = m_lineWidth * edgeLineWidth/dimEdgeLineCoef;
00333     
00334     QColor color = QColor(dimmed ? dimEdgeLabelColor : edgeLabelColor);
00335 
00336     if (label) label->setColor(color);
00337 
00338     for (TLabelXList::ConstIterator labelIt = nextLabels.begin();
00339          labelIt != nextLabels.end();
00340          ++labelIt)
00341     {
00342         (*labelIt)->setColor(color);
00343     }
00344 
00345     createStrokes(p);
00346 }
00347 
00348 bool Transition::isDimmed()
00349 {
00350     return dimmed;
00351 }
00352 
00353 void Transition::setChecked(bool ch)
00354 {
00355     checked = ch;    
00356 
00357     QColor color = (ch) ? checkedColor :
00358         dimmed ? QColor(dimEdgeLabelColor) : QColor(edgeLabelColor);
00359         
00360     if (label) label->setColor(color);
00361 
00362     for (TLabelXList::ConstIterator labelIt = nextLabels.begin();
00363          labelIt != nextLabels.end();
00364          ++labelIt)
00365     {
00366         (*labelIt)->setColor(color);
00367     }
00368 
00369     update();
00370 }
00371 
00372 void Transition::setSelected(bool sel)
00373 {
00374     if (label && label->text() != "")
00375     {
00376         label->setSelected(sel);
00377     }
00378 
00379     foreach(LabelX *label, nextLabels)
00380     {
00381         label->setSelected(sel);
00382     }
00383 
00384     QGraphicsItem::setSelected(sel);
00385 }
00386 
00387 void Transition::mousePressEvent(QGraphicsSceneMouseEvent *event)
00388 {
00389     DBGLOG_ME("called");
00390     m_lastMouseClickType = eMouseNoClick;
00391     setChecked();
00392     if (event->button() == Qt::RightButton)
00393     {
00394         m_lastMouseClickType = eMouseRightClick;
00395     }
00396 }
00397 
00398 void Transition::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
00399 {
00400     DBGLOG_ME("Transition::mouseDoubleClickEvent");
00401     if (event->button() == Qt::LeftButton && editor->getAction() == Editor::eSelection)
00402     {        
00403         m_lastMouseClickType = eMouseDoubleClick;
00404         setChecked();
00405     }
00406 }
00407 
00408 void Transition::setStartState(State *state)
00409 {
00410     startState = state;
00411     adjust(); // redraw
00412 }
00413 
00414 void Transition::setEndState(State *state)
00415 {
00416     if (endState)
00417         endState = state;
00418     else RELLOG("No endState available!");
00419     adjust(); // redraw
00420 }
00421 
00422 // saving
00423 bool Transition::getVCParams(QTextStream &out, EdgePrevParams &prevParams) const
00424 {
00425   bool stChanged = false;
00426   if (!dimmed){
00427     if (edgeLineStyle != prevParams.edgeLineStyle){
00428       prevParams.edgeLineStyle = edgeLineStyle;
00429       stChanged = true;
00430       if (edgeLineStyle != editor->edgeLineStyle){
00431         out << endl << "\\ChgEdgeLineStyle{";
00432         out << trLineStyle(edgeLineStyle);
00433         out << "}" << endl;
00434         }
00435       else{
00436         out << endl << "\\RstEdgeLineStyle";
00437       } // if != editor
00438     } // if
00439     
00440     if (edgeLineWidth != prevParams.edgeLineWidth){
00441       stChanged = true;
00442       prevParams.edgeLineWidth = edgeLineWidth;
00443       if (edgeLineWidth != 1)
00444         out << endl << "\\ChgEdgeLineWidth{" << edgeLineWidth << "}"; 
00445       else
00446         out << endl << "\\RstEdgeLineWidth";
00447     } // if
00448     
00449     if (edgeLineColor != prevParams.edgeLineColor){
00450       stChanged = true;
00451       prevParams.edgeLineColor = edgeLineColor;
00452       if (edgeLineColor != editor->edgeLineColor)
00453         out << endl << "\\ChgEdgeLineColor{" << edgeLineColor.toLower() << "}"; 
00454       else
00455         out << endl << "\\RstEdgeLineColor";
00456     } // if
00457     
00458     if (edgeLabelColor != prevParams.edgeLabelColor){
00459       stChanged = true;
00460       prevParams.edgeLabelColor = edgeLabelColor;
00461       if (edgeLabelColor != editor->edgeLabelColor)
00462         out << endl << "\\ChgEdgeLabelColor{" << edgeLabelColor.toLower() << "}"; 
00463       else
00464         out << endl << "\\RstEdgeLabelColor";
00465     } // if
00466     
00467     if (edgeLabelScale != prevParams.edgeLabelScale){
00468       stChanged = true;
00469       prevParams.edgeLabelScale = edgeLabelScale;
00470       if (edgeLabelScale != 1)
00471         out << endl << "\\ChgEdgeLabelScale{" << edgeLabelScale << "}";
00472       else
00473         out << endl << "\\RstEdgeLabelScale";
00474     } // if
00475     
00476     if (edgeLineDblStatus != prevParams.edgeLineDblStatus){
00477       stChanged = true;
00478       prevParams.edgeLineDblStatus = edgeLineDblStatus;
00479       out << endl << (edgeLineDblStatus ? "\\EdgeLineDouble" : "\\EdgeLineSimple"); 
00480     } // if
00481   } // if (!dimmed)
00482   else{
00483     if (dimEdgeLineStyle != prevParams.dimEdgeLineStyle ||
00484         dimEdgeLineColor != prevParams.dimEdgeLineColor ||
00485         dimEdgeLineCoef != prevParams.dimEdgeLineCoef ||
00486         dimEdgeLabelColor != prevParams.dimEdgeLabelColor ){
00487       stChanged = true;
00488       prevParams.dimEdgeLineStyle = dimEdgeLineStyle;
00489       prevParams.dimEdgeLineColor = dimEdgeLineColor;
00490       prevParams.dimEdgeLineCoef = dimEdgeLineCoef;
00491       prevParams.dimEdgeLabelColor = dimEdgeLabelColor;
00492       out << endl <<"\\FixDimEdge{" << trLineStyle(dimEdgeLineStyle) << "}"
00493                                  "{" << dimEdgeLineCoef << "}" // TODO: compare with manual (probably bad there)!
00494                                  "{" << dimEdgeLineColor.toLower() << "}"
00495                                  "{" << dimEdgeLabelColor.toLower() << "}";
00496     } // if
00497   } // if dimmed
00498   if (edgeLineDblStatus){
00499     if (edgeLineBorderCoef != prevParams.edgeLineBorderCoef ||
00500         edgeLineBorderColor != prevParams.edgeLineBorderColor){
00501       stChanged = true;
00502       prevParams.edgeLineBorderCoef = edgeLineBorderCoef;
00503       prevParams.edgeLineBorderColor = edgeLineBorderColor;
00504       out << endl << "\\FixEdgeBorder{" << edgeLineBorderCoef << "}"
00505                                     "{" << edgeLineBorderColor.toLower() << "}"; 
00506     } // if
00507     
00508     if (edgeLineDblCoef != prevParams.edgeLineDblCoef ||
00509         edgeLineDblSep != prevParams.edgeLineDblSep){
00510       stChanged = true;
00511       prevParams.edgeLineDblCoef = edgeLineDblCoef;
00512       prevParams.edgeLineDblSep = edgeLineDblSep;
00513       out << endl << "\\FixEdgeLineDouble{" << edgeLineDblCoef << "}"
00514                                         "{" << edgeLineDblSep << "}"; 
00515     } // if
00516   } // if edgeLineDblStatus
00517   
00518   if (stChanged) out << endl;
00519   
00520   return stChanged;
00521 }
00522 
00523 QString Transition::getNextLabelsVCCommand() const
00524 {
00525     QString command = "";
00526 
00527     // if some next labels, store them
00528     int sbs_counter = 0;
00529     for(TLabelXList::ConstIterator labelIt = nextLabels.begin();
00530         labelIt != nextLabels.end();
00531         ++labelIt)
00532     {      
00533         command += (sbs_counter % SBS_LABELS) ? " " : "\n";
00534         command += "\\Label";
00535         command += (*labelIt)->left() ? "L" : "R";
00536       
00537         if ((*labelIt)->posParam() != DEF_EDGE_LAB_POS) 
00538             command += "[" + QString("%1").arg((*labelIt)->posParam()) + "]";
00539       
00540         command += "{" + (*labelIt)->text() + "}";
00541         sbs_counter++;
00542     }
00543     if (!nextLabels.isEmpty()) command += "\n";
00544     return command;
00545 }
00546 
00547 // not necessary more -> QPainterPathStroker used instead
00548 /*void Transition::makeAreas(const QPainterPath &p)
00549 {   
00550 #if QT_VERSION < 0x040600
00551     // insert increased area for clicking
00552     QPolygonF pf1, pf2;
00553 
00554     if (p.elementCount() < 2) return;
00555 
00556     QPointF startP = p.pointAtPercent(0);
00557     QPointF endP = p.pointAtPercent(1);
00558 
00559     QLineF angleLine(startP, endP);
00560     qreal angle = angleLine.angle() * M_PI/180;
00561 
00562     // make polygon form path   
00563     pf1 = p.toFillPolygon();
00564     pf2 = p.toReversed().toFillPolygon();
00565     
00566 
00567     QPolygonF selPol1(pf1);
00568     selPol1.translate(-SELECTION_BOUNDS*sin(angle),-SELECTION_BOUNDS*cos(angle));
00569     QPolygonF selPol2(pf2);
00570     selPol2.translate(SELECTION_BOUNDS*sin(angle),SELECTION_BOUNDS*cos(angle));
00571 
00572     pf1.translate(-CLICK_BOUNDS*sin(angle),-CLICK_BOUNDS*cos(angle)); // increase area
00573     pf2.translate(CLICK_BOUNDS*sin(angle),CLICK_BOUNDS*cos(angle));        
00574 
00575     Q_ASSERT(!selPol1.empty());
00576     Q_ASSERT(!selPol2.empty());
00577 
00578     Q_ASSERT(!pf1.empty());
00579     Q_ASSERT(!pf2.empty());
00580 
00581     selPol1.pop_back();
00582     selPol2.pop_back();
00583     selPol1 << selPol2;
00584 
00585     m_selectionArea = selPol1;
00586 
00587     pf1.pop_back(); // last point is automaticly joined to first point, so erase
00588     pf2.pop_back();
00589     pf1 << pf2;
00590          
00591     m_clickArea = pf1;
00592 #else
00593     if (p.elementCount() < 2)
00594         return;   
00595     
00596     QPointF startP = p.pointAtPercent(0);
00597     QPointF endP = p.pointAtPercent(1);
00598 
00599     QLineF angleLine(startP, endP);
00600     qreal angle = angleLine.angle() * M_PI/180;    
00601 
00602     //! create paths translated according to angle, distance between original and 
00603     //! translated path is CLICK_BOUNDS
00604     QPainterPath pClick1(p.translated(CLICK_BOUNDS*sin(angle), CLICK_BOUNDS*cos(angle)));
00605     QPainterPath pClick2(p.translated(-CLICK_BOUNDS*sin(angle), -CLICK_BOUNDS*cos(angle)));
00606     
00607     QPainterPath pSel1(p.translated(SELECTION_BOUNDS*sin(angle), SELECTION_BOUNDS*cos(angle)));
00608     QPainterPath pSel2(p.translated(-SELECTION_BOUNDS*sin(angle), -SELECTION_BOUNDS*cos(angle)));    
00609 
00610     //! create one closed path
00611     pClick1.connectPath(pClick2.toReversed());
00612     m_clickArea = pClick1.toFillPolygon();
00613     
00614     pSel1.connectPath(pSel2.toReversed());
00615     m_selectionArea = pSel1.toFillPolygon();
00616 #endif
00617 }*/
00618 
00619 void Transition::createStrokes(const QPainterPath &path)
00620 {
00621 #ifdef MEASURE_CREATE_STROKES 
00622     QTime timer;
00623     timer.start();
00624 #endif
00625 
00626 #if 1
00627     m_clickPath = createShape(path, ((int)m_lineWidth < CLICK_BOUNDS*2) ? CLICK_BOUNDS*2 : (int)m_lineWidth);
00628     m_selectionPath = createShape(path, (int) m_lineWidth + SELECTION_BOUNDS);
00629 #else
00630     if (p.elementCount() < 2)
00631         return;   
00632     
00633     QPointF startP = p.pointAtPercent(0);
00634     QPointF endP = p.pointAtPercent(1);
00635 
00636     QLineF angleLine(startP, endP);
00637     qreal angle = angleLine.angle() * M_PI/180;    
00638 
00639     //! create paths translated according to angle, distance between original and 
00640     //! translated path is CLICK_BOUNDS
00641     QPainterPath pClick1(p.translated(CLICK_BOUNDS*sin(angle), CLICK_BOUNDS*cos(angle)));
00642     QPainterPath pClick2(p.translated(-CLICK_BOUNDS*sin(angle), -CLICK_BOUNDS*cos(angle)));
00643     
00644     QPainterPath pSel1(p.translated(SELECTION_BOUNDS*sin(angle), SELECTION_BOUNDS*cos(angle)));
00645     QPainterPath pSel2(p.translated(-SELECTION_BOUNDS*sin(angle), -SELECTION_BOUNDS*cos(angle)));    
00646 
00647     //! create one closed path
00648     pClick1.connectPath(pClick2.toReversed());
00649     m_clickPath = pClick1;
00650     
00651     pSel1.connectPath(pSel2.toReversed());
00652     m_selectionPath = pSel1;
00653 #endif
00654 
00655 #ifdef MEASURE_CREATE_STROKES
00656     g_TimeSum += timer.elapsed();
00657     g_TimeIterations++;
00658     if (g_TimeIterations == g_TimeIterationsCount)
00659     {
00660         RELLOG("PM:" << "takes" << g_TimeSum << "ms on" << g_TimeIterationsCount << "iterations");
00661         g_TimeIterations = 0;
00662         g_TimeSum = 0;
00663     }
00664 #endif
00665 }
00666 
00667 const QPainterPath& Transition::getClickPath() const
00668 {
00669     return m_clickPath;
00670 }
00671 
00672 const QPainterPath& Transition::getSelectionPath() const
00673 {
00674     return m_selectionPath;
00675 }
00676 
00677 QPolygonF Transition::getArrowPolygon(const QPainterPath &path)
00678 {
00679     QPointF p1 = path.pointAtPercent(1);
00680     QPointF p2 = path.pointAtPercent(path.percentAtLength(path.length()-ARROW_LEN));
00681     QLineF arrowAngleLine(p1, p2);
00682     qreal angle = arrowAngleLine.angle();
00683 
00684     QMatrix matrix;
00685     matrix.rotate(-angle); 
00686     QPolygonF arrowPoints = matrix.map(m_arrowPoints); // rotate default arrowPoints to right angle
00687 
00688     arrowPoints.translate(path.pointAtPercent(1)); // move arrow to right position
00689 
00690     return arrowPoints;
00691 }
00692 
00693 QPolygonF Transition::findIntersectedPoints(const QPolygonF &curve, const QPolygonF &polygon, 
00694                                              const Transition::EIntersectionFindMethod method)
00695 {
00696     QPolygonF intersectedPoints;
00697 
00698     if (curve.size() < 2 || polygon.size() < 2)
00699     {
00700         Q_ASSERT(0 && "bad polygon given");
00701         RELLOG("bad polygons given (small size) !!!");
00702         return intersectedPoints;
00703     }
00704 
00705     QLineF curveLine, polyLine;
00706     QPointF intersectedPoint, tmpPoint;
00707     QPolygonF::ConstIterator curveIt1 = curve.end()-1; 
00708     QPolygonF::ConstIterator curveIt2 = curve.end()-2; // from endState
00709     QPolygonF::ConstIterator polyIt;
00710 
00711     int found = 0;       
00712 
00713     while (curveIt2 >= curve.begin())
00714     {        
00715         curveLine.setPoints(*curveIt1, *curveIt2);
00716 
00717         polyIt = polygon.begin();
00718         polyLine.setP2(*polyIt++);
00719         
00720         while (polyIt < polygon.end())
00721         {
00722             polyLine.setP1(polyLine.p2());
00723             polyLine.setP2(*polyIt++);
00724 
00725             if (polyLine.intersect(curveLine, &intersectedPoint) == QLineF::BoundedIntersection)
00726             {
00727                 tmpPoint = intersectedPoint;
00728                 curveIt1--;
00729                 
00730                 while (curveIt1 > curveIt2) // find more exact point
00731                 {
00732                     curveLine.setPoints(*curveIt1--, *curveIt2);
00733                     if (polyLine.intersect(curveLine, &intersectedPoint) == QLineF::BoundedIntersection)
00734                     {
00735                         tmpPoint = intersectedPoint;
00736                     }
00737                 }
00738                 
00739                 // add only new point!
00740                 if (intersectedPoints.empty() || intersectedPoints.last() != tmpPoint)
00741                 {
00742                     intersectedPoints << tmpPoint;
00743                     found++;
00744                     
00745                     if (method == eFIND_FIRST ||
00746                         (method == eFIND_TWO && found == 2))
00747                         break;
00748                 }
00749             }
00750         }
00751 
00752         if ((method == eFIND_FIRST && found == 1) ||
00753             (method == eFIND_TWO && found == 2))        
00754             break;
00755 
00756         curveIt2--;
00757     }
00758 
00759     if (found == 0)
00760         DBGLOG("no intersected point found");
00761 
00762 #ifdef TESTING_ARROW_POINTS
00763     DBGLOG(DBGPAR(intersectedPoints));
00764 #endif
00765 
00766     return intersectedPoints;
00767 }
00768 
00769 void Transition::setEdgeLabelScale(float labelScale)
00770 {
00771     if (edgeLabelScale == labelScale) return;
00772 
00773     prepareGeometryChange();
00774 
00775     m_labelFontSize = (int) (m_labelFontSize * labelScale/edgeLabelScale);
00776     edgeLabelScale = labelScale;
00777     if (label)
00778     {
00779         label->setFontSize(m_labelFontSize);
00780     }
00781     for (TLabelXList::Iterator labelIt = nextLabels.begin();
00782          labelIt != nextLabels.end();
00783          ++labelIt)
00784     {
00785         (*labelIt)->setFontSize(m_labelFontSize);
00786     }
00787 
00788     setLabelPosition(); // virtual method -> right one should be called
00789 }
00790 
00791 void Transition::setEdgeLineWidth(float lineWidth)
00792 {
00793     if (edgeLineWidth == lineWidth) return;
00794 
00795     prepareGeometryChange();
00796 
00797     if (!dimmed)
00798         m_lineWidth = m_lineWidth * lineWidth/edgeLineWidth;
00799     edgeLineWidth = lineWidth;
00800     
00801     if (!dimmed)
00802         createStrokes(p);
00803     // TODO: set label position according to line width
00804 }
00805 
00806 void Transition::setDimEdgeLineCoef(float lineCoef)
00807 {
00808     if (dimEdgeLineCoef == lineCoef) return;
00809 
00810     prepareGeometryChange();
00811     
00812     if (dimmed)
00813         m_lineWidth = m_lineWidth * lineCoef/dimEdgeLineCoef;
00814     dimEdgeLineCoef = lineCoef;
00815 
00816     if (dimmed)
00817         createStrokes(p);
00818 }
00819 
00820 // ITransition support implementation -->
00821 
00822 QString Transition::getSourceState() const
00823 {
00824     return getStartStateName();
00825 }
00826 
00827 QString Transition::getDestinationState() const
00828 {
00829     // note that this method should be never called on Initial or Final transition
00830     return getEndStateName();
00831 }
00832 
00833 void Transition::showErrorReport(const QString &reportText) const
00834 {
00835     QString report = "Incorrect transition definition (transition between states \""
00836                    + getSourceState() + "\" and \"" + getDestinationState() + "\")<br>"
00837                    + reportText;
00838     ReportDialog rd(report, editor);
00839     rd.exec();
00840 }
00841 
00842 bool Transition::getCharacters(ITransition::TCharSet &characters,
00843                                const ITransition::TCharSet &alphabet,
00844                                const QString &alphabetSymbol,
00845                                const QString &epsilonSymbol) const
00846 {
00847     LabelSyntaxChecker syntaxChecker(alphabet, alphabetSymbol, epsilonSymbol);
00848     bool empty = true;
00849     
00850     if (label)
00851     {
00852         if (!syntaxChecker.checkSyntax(label->getCharacterList()))
00853         {
00854             showErrorReport(syntaxChecker.getReport());
00855             return false;
00856         }
00857         
00858         characters |= syntaxChecker.getCharacters();
00859         empty = empty && (syntaxChecker.getPattern() == LabelSyntaxChecker::eEmptyPattern);
00860     }
00861     
00862     for(TLabelXList::ConstIterator labelIt = nextLabels.begin();
00863         labelIt != nextLabels.end();
00864         ++labelIt)
00865     {
00866         if (!syntaxChecker.checkSyntax((*labelIt)->getCharacterList()))
00867         {
00868             showErrorReport(syntaxChecker.getReport());
00869             return false;
00870         }
00871         
00872         characters |= syntaxChecker.getCharacters();
00873         empty = empty || (syntaxChecker.getPattern() == LabelSyntaxChecker::eEmptyPattern);
00874     }
00875     
00876     if (empty) // all labels are EMPTY
00877     {
00878         showErrorReport("No symbols for transition.");
00879         return false;
00880     }
00881     
00882     return true;
00883 }
00884 
00885 void Transition::getCharactersOccurences(ITransition::TCharSet &characters) const
00886 {
00887     QStringList occurences;
00888     
00889     if (label)
00890     {
00891         occurences = label->getCharacters(); 
00892         dismemberCharacters(occurences, characters);                             
00893     }
00894     
00895     for(TLabelXList::ConstIterator labelIt = nextLabels.begin();
00896         labelIt != nextLabels.end();
00897         ++labelIt)
00898     {
00899         occurences = (*labelIt)->getCharacters();
00900         dismemberCharacters(occurences, characters);
00901     }
00902 }
00903 
00904 void Transition::dismemberCharacters(const QStringList &occurences,
00905                                      ITransition::TCharSet &characters) const
00906 {
00907     foreach(const QString &character, occurences)
00908     {
00909         // special symbols // TODO: solve better
00910         if (character == "," || character == "-" || character == "\\{" || character == "\\}") continue;
00911         
00912         characters << character;
00913     }
00914 }
00915 
00916 

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