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