Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewSketcher.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "OCCViewer_ViewSketcher.h"
21 #include "OCCViewer_ViewWindow.h"
22 #include "OCCViewer_ViewPort3d.h"
23
24 #include "QtxRubberBand.h"
25
26 #include <QApplication>
27 #include <QPainter>
28 #include <QPolygon>
29 #include <QMouseEvent>
30 #include <QKeyEvent>
31
32 /****************************************************************
33 **  Class: OCCViewer_ViewSketcher
34 **  Level: Public
35 *****************************************************************/
36
37 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
38 : QObject( vw ),
39 mySketchButton( Qt::LeftButton ),
40 mypViewWindow( vw ),
41 myType( type ),
42 mypData( 0 ),
43 myResult( Neutral ),
44 myButtonState( 0 )
45 {
46 }
47
48 OCCViewer_ViewSketcher::~OCCViewer_ViewSketcher()
49 {
50 }
51
52 void OCCViewer_ViewSketcher::activate()
53 {
54   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
55
56   mySavedCursor = avp->cursor();
57   avp->setCursor( Qt::PointingHandCursor );
58   avp->installEventFilter( this );
59   qApp->installEventFilter( this );
60
61   connect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
62
63   myStart = QPoint();
64   myResult = Neutral;
65
66   onActivate();
67 }
68
69 void OCCViewer_ViewSketcher::deactivate()
70 {
71   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
72
73   disconnect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
74
75   qApp->removeEventFilter( this );
76   avp->removeEventFilter( this );
77   avp->setCursor( mySavedCursor );
78
79   onDeactivate();
80 }
81
82 int OCCViewer_ViewSketcher::type() const
83 {
84   return myType;
85 }
86
87 void* OCCViewer_ViewSketcher::data() const
88 {
89   return mypData;
90 }
91
92 int OCCViewer_ViewSketcher::result() const
93 {
94   return myResult;
95 }
96
97 int OCCViewer_ViewSketcher::buttonState() const
98 {
99   return myButtonState;
100 }
101
102 void OCCViewer_ViewSketcher::onActivate()
103 {
104 }
105
106 void OCCViewer_ViewSketcher::onDeactivate()
107 {
108 }
109
110 bool OCCViewer_ViewSketcher::isDefault() const
111 {
112   return true;
113 }
114
115 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
116 {
117   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
118
119   SketchState state = EnTrain;
120   bool ignore = false;
121   if ( o == avp )
122   {
123     switch ( e->type() )
124     {
125       case QEvent::MouseMove:
126       case QEvent::MouseButtonPress:
127       case QEvent::MouseButtonRelease:
128       case QEvent::MouseButtonDblClick:
129       {
130         QMouseEvent* me = (QMouseEvent*)e;
131
132         myButtonState = me->buttons();
133         if ( e->type() == QEvent::MouseButtonPress )
134           myButtonState |= me->button();
135
136         if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
137         {
138           state = Debut;
139           myStart = me->pos();
140         }
141
142         myCurr = me->pos();
143
144         onMouse( me );
145
146         if ( myResult != Neutral )
147           state = Fin;
148
149         ignore = true;
150         break;
151       }
152       case QEvent::Hide:
153       case QEvent::HideToParent:
154         myResult = Reject;
155         onSketch( Fin );
156         break;
157       default:
158         break;
159     }
160   }
161   if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
162   {
163     ignore = onKey( (QKeyEvent*)e );
164     if ( myResult != Neutral )
165       state = Fin;
166   }
167
168   if ( ignore )
169   {
170     onSketch( state );
171     return true;
172   }
173   return QObject::eventFilter( o, e );
174 }
175
176 void OCCViewer_ViewSketcher::onDrawViewPort()
177 {
178   onSketch( Debut );
179 }
180
181 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
182 {
183   return false;
184 }
185
186 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
187 {
188 }
189
190 int OCCViewer_ViewSketcher::sketchButton()
191 {
192   return mySketchButton;
193 }
194
195 void OCCViewer_ViewSketcher::setSketchButton( int b )
196 {
197   mySketchButton = b;
198 }
199
200 /****************************************************************
201 **  Class: OCCViewer_RectSketcher
202 **  Level: Public
203 *****************************************************************/
204
205 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
206   : OCCViewer_ViewSketcher( vw, typ )
207 {
208   if ( vw )
209     {
210       OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
211       mypRectRB = new QtxRectRubberBand( avp );
212     }
213 }
214
215 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
216 {
217   delete (QRect*)mypData;
218 }
219
220 void OCCViewer_RectSketcher::onActivate()
221 {
222   mypData = new QRect();
223 }
224
225 void OCCViewer_RectSketcher::onDeactivate()
226 {
227   delete (QRect*)mypData;
228   mypData = 0;
229   mypRectRB->clearGeometry();
230 }
231
232 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
233 {
234   if ( e->key() == Qt::Key_Escape )
235     myResult = Reject;
236   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
237     myResult = Accept;
238
239   return true;
240 }
241
242 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
243 {
244   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
245
246   if ( avp->rect().contains( myCurr ) )
247     avp->setCursor( Qt::PointingHandCursor );
248   else
249     avp->setCursor( Qt::ForbiddenCursor );
250
251   if ( e->type() == QEvent::MouseButtonRelease && e->button() == sketchButton() )
252   {
253     myResult = Accept;
254     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
255                                                    e->globalPos(), e->button(), 
256                                                    e->buttons(), e->modifiers() ) );
257   }
258 }
259
260 void OCCViewer_RectSketcher::onSketch( SketchState state )
261 {
262   //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
263
264   if ( mypRectRB )
265     {      
266       QRect* sketchRect = (QRect*)data();
267       if ( myButtonState & sketchButton() )
268         {   
269           QRect rect = QRect( myStart, myCurr ).normalized();
270           /*QRect rect( qMin( myStart.x(), myCurr.x() ), qMin( myStart.y(), myCurr.y() ),
271                       qAbs( myStart.x() - myCurr.x() ), qAbs( myStart.y() - myCurr.y() ) );
272           QPainter p( avp );
273           p.setPen( Qt::white );
274           p.setCompositionMode( QPainter::CompositionMode_Xor );
275           */
276           
277           //if ( state != Debut && !sketchRect->isEmpty() )
278           //  p.drawRect( *sketchRect );
279
280           *sketchRect = rect;
281           if ( !rect.isEmpty() && state != Fin )
282             {
283               //p.drawRect( *sketchRect );            
284               mypRectRB->initGeometry( rect );
285               mypRectRB->show();
286             }          
287           else
288             mypRectRB->hide();
289         }
290     }
291
292   if ( state == Fin )
293   {
294     QApplication::syncX();  /* force rectangle redrawing */
295     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
296   }
297 }
298
299 /****************************************************************
300 **  Class: OCCViewer_PolygonSketcher
301 **  Level: Public
302 *****************************************************************/
303
304 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
305 : OCCViewer_ViewSketcher( vw, typ ),
306   myDbl           ( false ),
307   myToler         ( 5, 5 ),
308   //mypPoints        ( 0L ),
309   myAddButton     ( 0 ),
310   myDelButton     ( 0 )
311 {
312   mySketchButton = Qt::RightButton;
313   if ( vw )
314     {
315       OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
316       mypPolyRB = new QtxPolyRubberBand( avp );
317     }
318 }
319
320 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
321 {
322   //delete mypPoints;
323   delete (QPolygon*)mypData;
324 }
325
326 void OCCViewer_PolygonSketcher::onActivate()
327 {
328   myDbl = false;
329   mypData = new QPolygon( 0 );
330   //mypPoints = new QPolygon( 0 );
331
332   switch ( sketchButton() )
333   {
334   case Qt::LeftButton:
335     myAddButton = Qt::RightButton;
336     myDelButton = Qt::MidButton;
337     break;
338   case Qt::MidButton:
339     myAddButton = Qt::LeftButton;
340     myDelButton = Qt::RightButton;
341     break;
342   case Qt::RightButton:
343   default:
344     myAddButton = Qt::LeftButton;
345     myDelButton = Qt::MidButton;
346     break;
347   };
348 }
349
350 void OCCViewer_PolygonSketcher::onDeactivate()
351 {
352   //delete mypPoints;
353   //mypPoints = 0;
354   delete (QPolygon*)mypData;
355   mypData = 0;
356
357   if ( mypPolyRB )
358     mypPolyRB->clearGeometry();  
359 }
360
361 bool OCCViewer_PolygonSketcher::onKey( QKeyEvent* e )
362 {
363   if ( e->key() == Qt::Key_Escape )
364   {
365     myResult = Reject;
366     return true;
367   }
368   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
369   {
370     QPolygon* points = (QPolygon*)data();
371     if ( points->count() )
372     {
373       QPoint last = points->point( points->count() - 1 );
374       if ( last != myCurr )
375       {
376         points->resize( points->count() + 1 );
377         points->setPoint( points->count() - 1, myCurr );
378       }
379     }
380     myResult = Accept;
381     return true;
382   }
383   else if ( e->key() == Qt::Key_Backspace && e->type() == QEvent::KeyRelease )
384   {
385     QPolygon* points = (QPolygon*)data();
386     if ( points->count() > 1 )
387       points->resize( points->count() - 1 );
388     onMouse( 0 );
389     return true;
390   }
391
392   return true;
393 }
394
395 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
396 {
397   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
398
399   QPolygon* points = (QPolygon*)data();
400   if ( !points->count() && !myStart.isNull() )
401   {
402     points->resize( points->count() + 1 );
403     points->setPoint( points->count() - 1, myStart );
404   }
405
406   bool closed = false;
407   bool valid = avp->rect().contains( myCurr );
408   if ( !myStart.isNull() )
409   {
410     QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
411                  2 * myToler.width(), 2 * myToler.height() );
412     closed = aRect.contains( myCurr );
413   }
414   valid = valid && isValid( points, myCurr );
415   if ( closed && !valid )
416     closed = false;
417
418   if ( closed )
419     avp->setCursor( Qt::CrossCursor );
420   else if ( valid )
421     avp->setCursor( Qt::PointingHandCursor );
422   else
423     avp->setCursor( Qt::ForbiddenCursor );
424
425   if ( !e )
426     return;
427
428   if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
429   {
430     myResult = Reject;
431     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
432                                                    e->globalPos(), e->button(), 
433                                                    e->buttons(), e->modifiers() ) );
434   }
435   else if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myAddButton ) )
436   {
437     if ( closed )
438       myResult = Accept;
439     else
440     {
441       if ( myStart.isNull() )
442         myStart = myCurr;
443       else
444       {
445         QPoint last = points->point( points->count() - 1 );
446         if ( last != myCurr && valid )
447         {
448           points->resize( points->count() + 1 );
449           points->setPoint( points->count() - 1, myCurr );
450         }
451         if ( valid && myDbl )
452           myResult = Accept;
453       }
454     }
455   }
456   else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
457             ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
458   {
459     if ( points->count() > 1 )
460       points->resize( points->count() - 1 );
461     onMouse( 0 );
462   }
463   myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
464 }
465
466 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
467 {
468   //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
469
470   QPolygon* points = (QPolygon*)data();
471   /*QPainter p( avp );
472   p.setPen( Qt::white );
473   p.setCompositionMode( QPainter::CompositionMode_Xor );
474   if ( state != Debut )
475     p.drawPolyline( *mypPoints );
476
477   if ( points->count() )
478   {
479     mypPoints->resize( points->count() + 1 );
480     for ( uint i = 0; i < points->count(); i++ )
481       mypPoints->setPoint( i, points->point( i ) );
482     mypPoints->setPoint( points->count(), myCurr );
483     if ( state != Fin )
484       p.drawPolyline( *mypPoints );
485       }*/
486   if ( mypPolyRB )
487     {
488       mypPolyRB->setUpdatesEnabled ( false );
489       if ( !mypPolyRB->isVisible() )
490         mypPolyRB->show();
491       //if ( state != Debut )
492       //  mypPolyRB->repaint();
493
494       if ( state != Fin && points->count() )
495         mypPolyRB->initGeometry( QPolygon(*points) << myCurr );
496       //mypPolyRB->addNode( myCurr );
497
498       //if ( state != Fin )
499       //  mypPolyRB->repaint();
500       mypPolyRB->setUpdatesEnabled ( true );
501       //mypPolyRB->repaint();
502     }
503       
504   if ( state == Fin )
505   {
506     if ( mypPolyRB )
507       {
508         mypPolyRB->clearGeometry();
509         mypPolyRB->hide();
510       }
511     QApplication::syncX();
512     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
513   }
514 }
515
516 bool OCCViewer_PolygonSketcher::isValid( const QPolygon* aPoints, const QPoint& aCur ) const
517 {
518   if ( !aPoints->count() )
519     return true;
520
521   if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
522     return false;
523
524   const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
525
526   if ( aLast == aCur )
527     return true;
528
529   bool res = true;
530   for ( uint i = 0; i < aPoints->count() - 1 && res; i++ )
531   {
532     const QPoint& aStart = aPoints->point( i );
533     const QPoint& anEnd  = aPoints->point( i + 1 );
534     res = !isIntersect( aStart, anEnd, aCur, aLast );
535   }
536
537   return res;
538 }
539
540 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
541                                              const QPoint& aStart2, const QPoint& anEnd2 ) const
542 {
543   if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
544        ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
545     return true;
546
547   if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
548        aStart1 == anEnd2 || anEnd1 == anEnd2 )
549     return false;
550
551   double x11 = aStart1.x() * 1.0;
552   double x12 = anEnd1.x() * 1.0;
553   double y11 = aStart1.y() * 1.0;
554   double y12 = anEnd1.y() * 1.0;
555
556   double x21 = aStart2.x() * 1.0;
557   double x22 = anEnd2.x() * 1.0;
558   double y21 = aStart2.y() * 1.0;
559   double y22 = anEnd2.y() * 1.0;
560
561   double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
562   double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
563
564   double b1 = y11 - k1 * x11;
565   double b2 = y21 - k2 * x21;
566
567   if ( k1 == k2 )
568   {
569     if ( b1 != b2 )
570       return false;
571     else
572       return !( ( qMax( x11, x12 ) <= qMin( x21, x22 ) ||
573                   qMin( x11, x12 ) >= qMax( x21, x22 ) ) &&
574                 ( qMax( y11, y12 ) <= qMin( y21, y22 ) ||
575                   qMin( y11, y12 ) >= qMax( y21, y22 ) ) );
576   }
577   else
578   {
579     double x0 = ( b2 - b1 ) / ( k1 - k2 );
580     double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
581
582     if ( qMin( x11, x12 ) < x0 && x0 < qMax( x11, x12 ) &&
583          qMin( y11, y12 ) < y0 && y0 < qMax( y11, y12 ) &&
584          qMin( x21, x22 ) < x0 && x0 < qMax( x21, x22 ) &&
585          qMin( y21, y22 ) < y0 && y0 < qMax( y21, y22 ) )
586       return true;
587   }
588   return false;
589 }
590
591