Back to index

salome-gui  6.5.0
OCCViewer_ViewSketcher.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 #include "OCCViewer_ViewSketcher.h"
00021 #include "OCCViewer_ViewWindow.h"
00022 #include "OCCViewer_ViewPort3d.h"
00023 
00024 #include "QtxRubberBand.h"
00025 
00026 #include <QApplication>
00027 #include <QPainter>
00028 #include <QPolygon>
00029 #include <QMouseEvent>
00030 #include <QKeyEvent>
00031 
00032 /****************************************************************
00033 **  Class: OCCViewer_ViewSketcher
00034 **  Level: Public
00035 *****************************************************************/
00036 
00037 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
00038 : QObject( vw ),
00039 mySketchButton( Qt::LeftButton ),
00040 mypViewWindow( vw ),
00041 myType( type ),
00042 mypData( 0 ),
00043 myResult( Neutral ),
00044 myButtonState( 0 )
00045 {
00046 }
00047 
00048 OCCViewer_ViewSketcher::~OCCViewer_ViewSketcher()
00049 {
00050 }
00051 
00052 void OCCViewer_ViewSketcher::activate()
00053 {
00054   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00055 
00056   mySavedCursor = avp->cursor();
00057   avp->setCursor( Qt::PointingHandCursor );
00058   avp->installEventFilter( this );
00059   qApp->installEventFilter( this );
00060 
00061   connect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
00062 
00063   myStart = QPoint();
00064   myResult = Neutral;
00065 
00066   onActivate();
00067 }
00068 
00069 void OCCViewer_ViewSketcher::deactivate()
00070 {
00071   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00072 
00073   disconnect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
00074 
00075   qApp->removeEventFilter( this );
00076   avp->removeEventFilter( this );
00077   avp->setCursor( mySavedCursor );
00078 
00079   onDeactivate();
00080 }
00081 
00082 int OCCViewer_ViewSketcher::type() const
00083 {
00084   return myType;
00085 }
00086 
00087 void* OCCViewer_ViewSketcher::data() const
00088 {
00089   return mypData;
00090 }
00091 
00092 int OCCViewer_ViewSketcher::result() const
00093 {
00094   return myResult;
00095 }
00096 
00097 int OCCViewer_ViewSketcher::buttonState() const
00098 {
00099   return myButtonState;
00100 }
00101 
00102 void OCCViewer_ViewSketcher::onActivate()
00103 {
00104 }
00105 
00106 void OCCViewer_ViewSketcher::onDeactivate()
00107 {
00108 }
00109 
00110 bool OCCViewer_ViewSketcher::isDefault() const
00111 {
00112   return true;
00113 }
00114 
00115 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
00116 {
00117   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00118 
00119   SketchState state = EnTrain;
00120   bool ignore = false;
00121   if ( o == avp )
00122   {
00123     switch ( e->type() )
00124     {
00125       case QEvent::MouseMove:
00126       case QEvent::MouseButtonPress:
00127       case QEvent::MouseButtonRelease:
00128       case QEvent::MouseButtonDblClick:
00129       {
00130         QMouseEvent* me = (QMouseEvent*)e;
00131 
00132         myButtonState = me->buttons();
00133         if ( e->type() == QEvent::MouseButtonPress )
00134           myButtonState |= me->button();
00135 
00136         if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
00137         {
00138           state = Debut;
00139           myStart = me->pos();
00140         }
00141 
00142         myCurr = me->pos();
00143 
00144         onMouse( me );
00145 
00146         if ( myResult != Neutral )
00147           state = Fin;
00148 
00149         ignore = true;
00150         break;
00151       }
00152       case QEvent::Hide:
00153       case QEvent::HideToParent:
00154         myResult = Reject;
00155         onSketch( Fin );
00156         break;
00157       default:
00158         break;
00159     }
00160   }
00161   if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
00162   {
00163     ignore = onKey( (QKeyEvent*)e );
00164     if ( myResult != Neutral )
00165       state = Fin;
00166   }
00167 
00168   if ( ignore )
00169   {
00170     onSketch( state );
00171     return true;
00172   }
00173   return QObject::eventFilter( o, e );
00174 }
00175 
00176 void OCCViewer_ViewSketcher::onDrawViewPort()
00177 {
00178   onSketch( Debut );
00179 }
00180 
00181 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
00182 {
00183   return false;
00184 }
00185 
00186 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
00187 {
00188 }
00189 
00190 int OCCViewer_ViewSketcher::sketchButton()
00191 {
00192   return mySketchButton;
00193 }
00194 
00195 void OCCViewer_ViewSketcher::setSketchButton( int b )
00196 {
00197   mySketchButton = b;
00198 }
00199 
00200 /****************************************************************
00201 **  Class: OCCViewer_RectSketcher
00202 **  Level: Public
00203 *****************************************************************/
00204 
00205 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
00206   : OCCViewer_ViewSketcher( vw, typ )
00207 {
00208   if ( vw )
00209     {
00210       OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00211       mypRectRB = new QtxRectRubberBand( avp );
00212     }
00213 }
00214 
00215 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
00216 {
00217   delete (QRect*)mypData;
00218 }
00219 
00220 void OCCViewer_RectSketcher::onActivate()
00221 {
00222   mypData = new QRect();
00223 }
00224 
00225 void OCCViewer_RectSketcher::onDeactivate()
00226 {
00227   delete (QRect*)mypData;
00228   mypData = 0;
00229   mypRectRB->clearGeometry();
00230 }
00231 
00232 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
00233 {
00234   if ( e->key() == Qt::Key_Escape )
00235     myResult = Reject;
00236   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
00237     myResult = Accept;
00238 
00239   return true;
00240 }
00241 
00242 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
00243 {
00244   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00245 
00246   if ( avp->rect().contains( myCurr ) )
00247     avp->setCursor( Qt::PointingHandCursor );
00248   else
00249     avp->setCursor( Qt::ForbiddenCursor );
00250 
00251   if ( e->type() == QEvent::MouseButtonRelease && e->button() == sketchButton() )
00252   {
00253     myResult = Accept;
00254     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
00255                                                    e->globalPos(), e->button(), 
00256                                                    e->buttons(), e->modifiers() ) );
00257   }
00258 }
00259 
00260 void OCCViewer_RectSketcher::onSketch( SketchState state )
00261 {
00262   //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00263 
00264   if ( mypRectRB )
00265     {      
00266       QRect* sketchRect = (QRect*)data();
00267       if ( myButtonState & sketchButton() )
00268         {   
00269           QRect rect = QRect( myStart, myCurr ).normalized();
00270           /*QRect rect( qMin( myStart.x(), myCurr.x() ), qMin( myStart.y(), myCurr.y() ),
00271                       qAbs( myStart.x() - myCurr.x() ), qAbs( myStart.y() - myCurr.y() ) );
00272           QPainter p( avp );
00273           p.setPen( Qt::white );
00274           p.setCompositionMode( QPainter::CompositionMode_Xor );
00275           */
00276           
00277           //if ( state != Debut && !sketchRect->isEmpty() )
00278           //  p.drawRect( *sketchRect );
00279 
00280           *sketchRect = rect;
00281           if ( !rect.isEmpty() && state != Fin )
00282             {
00283               //p.drawRect( *sketchRect );            
00284               mypRectRB->initGeometry( rect );
00285               mypRectRB->show();
00286             }          
00287           else
00288             mypRectRB->hide();
00289         }
00290     }
00291 
00292   if ( state == Fin )
00293   {
00294     QApplication::syncX();  /* force rectangle redrawing */
00295     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
00296   }
00297 }
00298 
00299 /****************************************************************
00300 **  Class: OCCViewer_PolygonSketcher
00301 **  Level: Public
00302 *****************************************************************/
00303 
00304 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
00305 : OCCViewer_ViewSketcher( vw, typ ),
00306   myDbl           ( false ),
00307   myToler         ( 5, 5 ),
00308   //mypPoints        ( 0L ),
00309   myAddButton     ( 0 ),
00310   myDelButton     ( 0 )
00311 {
00312   mySketchButton = Qt::RightButton;
00313   if ( vw )
00314     {
00315       OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00316       mypPolyRB = new QtxPolyRubberBand( avp );
00317     }
00318 }
00319 
00320 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
00321 {
00322   //delete mypPoints;
00323   delete (QPolygon*)mypData;
00324 }
00325 
00326 void OCCViewer_PolygonSketcher::onActivate()
00327 {
00328   myDbl = false;
00329   mypData = new QPolygon( 0 );
00330   //mypPoints = new QPolygon( 0 );
00331 
00332   switch ( sketchButton() )
00333   {
00334   case Qt::LeftButton:
00335     myAddButton = Qt::RightButton;
00336     myDelButton = Qt::MidButton;
00337     break;
00338   case Qt::MidButton:
00339     myAddButton = Qt::LeftButton;
00340     myDelButton = Qt::RightButton;
00341     break;
00342   case Qt::RightButton:
00343   default:
00344     myAddButton = Qt::LeftButton;
00345     myDelButton = Qt::MidButton;
00346     break;
00347   };
00348 }
00349 
00350 void OCCViewer_PolygonSketcher::onDeactivate()
00351 {
00352   //delete mypPoints;
00353   //mypPoints = 0;
00354   delete (QPolygon*)mypData;
00355   mypData = 0;
00356 
00357   if ( mypPolyRB )
00358     mypPolyRB->clearGeometry();  
00359 }
00360 
00361 bool OCCViewer_PolygonSketcher::onKey( QKeyEvent* e )
00362 {
00363   if ( e->key() == Qt::Key_Escape )
00364   {
00365     myResult = Reject;
00366     return true;
00367   }
00368   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
00369   {
00370     QPolygon* points = (QPolygon*)data();
00371     if ( points->count() )
00372     {
00373       QPoint last = points->point( points->count() - 1 );
00374       if ( last != myCurr )
00375       {
00376         points->resize( points->count() + 1 );
00377         points->setPoint( points->count() - 1, myCurr );
00378       }
00379     }
00380     myResult = Accept;
00381     return true;
00382   }
00383   else if ( e->key() == Qt::Key_Backspace && e->type() == QEvent::KeyRelease )
00384   {
00385     QPolygon* points = (QPolygon*)data();
00386     if ( points->count() > 1 )
00387       points->resize( points->count() - 1 );
00388     onMouse( 0 );
00389     return true;
00390   }
00391 
00392   return true;
00393 }
00394 
00395 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
00396 {
00397   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00398 
00399   QPolygon* points = (QPolygon*)data();
00400   if ( !points->count() && !myStart.isNull() )
00401   {
00402     points->resize( points->count() + 1 );
00403     points->setPoint( points->count() - 1, myStart );
00404   }
00405 
00406   bool closed = false;
00407   bool valid = avp->rect().contains( myCurr );
00408   if ( !myStart.isNull() )
00409   {
00410     QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
00411                  2 * myToler.width(), 2 * myToler.height() );
00412     closed = aRect.contains( myCurr );
00413   }
00414   valid = valid && isValid( points, myCurr );
00415   if ( closed && !valid )
00416     closed = false;
00417 
00418   if ( closed )
00419     avp->setCursor( Qt::CrossCursor );
00420   else if ( valid )
00421     avp->setCursor( Qt::PointingHandCursor );
00422   else
00423     avp->setCursor( Qt::ForbiddenCursor );
00424 
00425   if ( !e )
00426     return;
00427 
00428   if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
00429   {
00430     myResult = Reject;
00431     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
00432                                                    e->globalPos(), e->button(), 
00433                                                    e->buttons(), e->modifiers() ) );
00434   }
00435   else if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myAddButton ) )
00436   {
00437     if ( closed )
00438       myResult = Accept;
00439     else
00440     {
00441       if ( myStart.isNull() )
00442         myStart = myCurr;
00443       else
00444       {
00445         QPoint last = points->point( points->count() - 1 );
00446         if ( last != myCurr && valid )
00447         {
00448           points->resize( points->count() + 1 );
00449           points->setPoint( points->count() - 1, myCurr );
00450         }
00451         if ( valid && myDbl )
00452           myResult = Accept;
00453       }
00454     }
00455   }
00456   else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
00457             ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
00458   {
00459     if ( points->count() > 1 )
00460       points->resize( points->count() - 1 );
00461     onMouse( 0 );
00462   }
00463   myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
00464 }
00465 
00466 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
00467 {
00468   //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
00469 
00470   QPolygon* points = (QPolygon*)data();
00471   /*QPainter p( avp );
00472   p.setPen( Qt::white );
00473   p.setCompositionMode( QPainter::CompositionMode_Xor );
00474   if ( state != Debut )
00475     p.drawPolyline( *mypPoints );
00476 
00477   if ( points->count() )
00478   {
00479     mypPoints->resize( points->count() + 1 );
00480     for ( uint i = 0; i < points->count(); i++ )
00481       mypPoints->setPoint( i, points->point( i ) );
00482     mypPoints->setPoint( points->count(), myCurr );
00483     if ( state != Fin )
00484       p.drawPolyline( *mypPoints );
00485       }*/
00486   if ( mypPolyRB )
00487     {
00488       mypPolyRB->setUpdatesEnabled ( false );
00489       if ( !mypPolyRB->isVisible() )
00490         mypPolyRB->show();
00491       //if ( state != Debut )
00492       //  mypPolyRB->repaint();
00493 
00494       if ( state != Fin && points->count() )
00495         mypPolyRB->initGeometry( QPolygon(*points) << myCurr );
00496       //mypPolyRB->addNode( myCurr );
00497 
00498       //if ( state != Fin )
00499       //  mypPolyRB->repaint();
00500       mypPolyRB->setUpdatesEnabled ( true );
00501       //mypPolyRB->repaint();
00502     }
00503       
00504   if ( state == Fin )
00505   {
00506     if ( mypPolyRB )
00507       {
00508         mypPolyRB->clearGeometry();
00509         mypPolyRB->hide();
00510       }
00511     QApplication::syncX();
00512     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
00513   }
00514 }
00515 
00516 bool OCCViewer_PolygonSketcher::isValid( const QPolygon* aPoints, const QPoint& aCur ) const
00517 {
00518   if ( !aPoints->count() )
00519     return true;
00520 
00521   if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
00522     return false;
00523 
00524   const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
00525 
00526   if ( aLast == aCur )
00527     return true;
00528 
00529   bool res = true;
00530   for ( uint i = 0; i < aPoints->count() - 1 && res; i++ )
00531   {
00532     const QPoint& aStart = aPoints->point( i );
00533     const QPoint& anEnd  = aPoints->point( i + 1 );
00534     res = !isIntersect( aStart, anEnd, aCur, aLast );
00535   }
00536 
00537   return res;
00538 }
00539 
00540 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
00541                                              const QPoint& aStart2, const QPoint& anEnd2 ) const
00542 {
00543   if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
00544        ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
00545     return true;
00546 
00547   if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
00548        aStart1 == anEnd2 || anEnd1 == anEnd2 )
00549     return false;
00550 
00551   double x11 = aStart1.x() * 1.0;
00552   double x12 = anEnd1.x() * 1.0;
00553   double y11 = aStart1.y() * 1.0;
00554   double y12 = anEnd1.y() * 1.0;
00555 
00556   double x21 = aStart2.x() * 1.0;
00557   double x22 = anEnd2.x() * 1.0;
00558   double y21 = aStart2.y() * 1.0;
00559   double y22 = anEnd2.y() * 1.0;
00560 
00561   double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
00562   double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
00563 
00564   double b1 = y11 - k1 * x11;
00565   double b2 = y21 - k2 * x21;
00566 
00567   if ( k1 == k2 )
00568   {
00569     if ( b1 != b2 )
00570       return false;
00571     else
00572       return !( ( qMax( x11, x12 ) <= qMin( x21, x22 ) ||
00573                   qMin( x11, x12 ) >= qMax( x21, x22 ) ) &&
00574                 ( qMax( y11, y12 ) <= qMin( y21, y22 ) ||
00575                   qMin( y11, y12 ) >= qMax( y21, y22 ) ) );
00576   }
00577   else
00578   {
00579     double x0 = ( b2 - b1 ) / ( k1 - k2 );
00580     double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
00581 
00582     if ( qMin( x11, x12 ) < x0 && x0 < qMax( x11, x12 ) &&
00583          qMin( y11, y12 ) < y0 && y0 < qMax( y11, y12 ) &&
00584          qMin( x21, x22 ) < x0 && x0 < qMax( x21, x22 ) &&
00585          qMin( y21, y22 ) < y0 && y0 < qMax( y21, y22 ) )
00586       return true;
00587   }
00588   return false;
00589 }
00590 
00591