Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewSketcher.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
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 <qapplication.h>
25 #include <qpainter.h>
26 #include <qpointarray.h>
27
28 /****************************************************************
29 **  Class: OCCViewer_ViewSketcher
30 **  Level: Public
31 *****************************************************************/
32
33 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
34 : QObject( vw ),
35 mySketchButton( Qt::LeftButton ),
36 mypViewWindow( vw ),
37 myType( type ),
38 mypData( 0 ),
39 myResult( Neutral ),
40 myButtonState( 0 )
41 {
42 }
43
44 OCCViewer_ViewSketcher::~OCCViewer_ViewSketcher()
45 {
46 }
47
48 void OCCViewer_ViewSketcher::activate()
49 {
50   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
51
52   mySavedCursor = avp->cursor();
53   avp->setCursor( Qt::PointingHandCursor );
54   avp->installEventFilter( this );
55   qApp->installEventFilter( this );
56
57   connect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
58
59   myStart = QPoint();
60   myResult = Neutral;
61
62   onActivate();
63 }
64
65 void OCCViewer_ViewSketcher::deactivate()
66 {
67   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
68
69   disconnect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
70
71   qApp->removeEventFilter( this );
72   avp->removeEventFilter( this );
73   avp->setCursor( mySavedCursor );
74
75   onDeactivate();
76 }
77
78 int OCCViewer_ViewSketcher::type() const
79 {
80   return myType;
81 }
82
83 void* OCCViewer_ViewSketcher::data() const
84 {
85   return mypData;
86 }
87
88 int OCCViewer_ViewSketcher::result() const
89 {
90   return myResult;
91 }
92
93 int OCCViewer_ViewSketcher::buttonState() const
94 {
95   return myButtonState;
96 }
97
98 void OCCViewer_ViewSketcher::onActivate()
99 {
100 }
101
102 void OCCViewer_ViewSketcher::onDeactivate()
103 {
104 }
105
106 bool OCCViewer_ViewSketcher::isDefault() const
107 {
108   return true;
109 }
110
111 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
112 {
113   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
114
115   SketchState state = EnTrain;
116   bool ignore = false;
117   if ( o == avp )
118   {
119     switch ( e->type() )
120     {
121       case QEvent::MouseMove:
122       case QEvent::MouseButtonPress:
123       case QEvent::MouseButtonRelease:
124       case QEvent::MouseButtonDblClick:
125       {
126         QMouseEvent* me = (QMouseEvent*)e;
127
128         myButtonState = me->state();
129         if ( e->type() == QEvent::MouseButtonPress )
130           myButtonState |= me->button();
131
132         if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
133         {
134           state = Debut;
135           myStart = me->pos();
136         }
137
138         myCurr = me->pos();
139
140         onMouse( me );
141
142         if ( myResult != Neutral )
143           state = Fin;
144
145         ignore = true;
146         break;
147       }
148       case QEvent::Hide:
149       case QEvent::HideToParent:
150         myResult = Reject;
151         onSketch( Fin );
152         break;
153       default:
154         break;
155     }
156   }
157   if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
158   {
159     ignore = onKey( (QKeyEvent*)e );
160     if ( myResult != Neutral )
161       state = Fin;
162   }
163
164   if ( ignore )
165   {
166     onSketch( state );
167     return true;
168   }
169   return QObject::eventFilter( o, e );
170 }
171
172 void OCCViewer_ViewSketcher::onDrawViewPort()
173 {
174   onSketch( Debut );
175 }
176
177 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
178 {
179   return false;
180 }
181
182 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
183 {
184 }
185
186 int OCCViewer_ViewSketcher::sketchButton()
187 {
188   return mySketchButton;
189 }
190
191 void OCCViewer_ViewSketcher::setSketchButton( int b )
192 {
193   mySketchButton = b;
194 }
195
196 /****************************************************************
197 **  Class: OCCViewer_RectSketcher
198 **  Level: Public
199 *****************************************************************/
200
201 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
202 : OCCViewer_ViewSketcher( vw, typ )
203 {
204 }
205
206 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
207 {
208   delete mypData;
209 }
210
211 void OCCViewer_RectSketcher::onActivate()
212 {
213   mypData = new QRect();
214 }
215
216 void OCCViewer_RectSketcher::onDeactivate()
217 {
218   delete mypData;
219   mypData = 0;
220 }
221
222 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
223 {
224   if ( e->key() == Qt::Key_Escape )
225     myResult = Reject;
226   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
227     myResult = Accept;
228
229   return true;
230 }
231
232 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
233 {
234   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
235
236   if ( avp->rect().contains( myCurr ) )
237     avp->setCursor( Qt::PointingHandCursor );
238   else
239     avp->setCursor( Qt::ForbiddenCursor );
240
241   if ( e->type() == QEvent::MouseButtonRelease && e->button() == sketchButton() )
242   {
243     myResult = Accept;
244     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
245                                                    e->globalPos(), e->state(), e->button() ) );
246   }
247 }
248
249 void OCCViewer_RectSketcher::onSketch( SketchState state )
250 {
251   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
252
253   QRect* sketchRect = (QRect*)data();
254   if ( myButtonState & sketchButton() )
255   {
256     QRect rect( QMIN( myStart.x(), myCurr.x() ), QMIN( myStart.y(), myCurr.y() ),
257                 QABS( myStart.x() - myCurr.x() ), QABS( myStart.y() - myCurr.y() ) );
258     QPainter p( avp );
259     p.setPen( Qt::white );
260     p.setRasterOp( Qt::XorROP );
261     if ( state != Debut && !sketchRect->isEmpty() )
262       p.drawRect( *sketchRect );
263     *sketchRect = rect;
264     if ( !rect.isEmpty() && state != Fin )
265       p.drawRect( *sketchRect );
266   }
267
268   if ( state == Fin )
269   {
270     QApplication::syncX();  /* force rectangle redrawing */
271     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
272   }
273 }
274
275 /****************************************************************
276 **  Class: OCCViewer_PolygonSketcher
277 **  Level: Public
278 *****************************************************************/
279
280 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
281 : OCCViewer_ViewSketcher( vw, typ ),
282   myDbl           ( false ),
283   myToler         ( 5, 5 ),
284   mypPoints        ( 0L ),
285   myAddButton     ( 0 ),
286   myDelButton     ( 0 )
287 {
288   mySketchButton = Qt::RightButton;
289 }
290
291 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
292 {
293   delete mypPoints;
294   delete mypData;
295 }
296
297 void OCCViewer_PolygonSketcher::onActivate()
298 {
299   myDbl = false;
300   mypData = new QPointArray( 0 );
301   mypPoints = new QPointArray( 0 );
302
303   switch ( sketchButton() )
304   {
305   case Qt::LeftButton:
306     myAddButton = Qt::RightButton;
307     myDelButton = Qt::MidButton;
308     break;
309   case Qt::MidButton:
310     myAddButton = Qt::LeftButton;
311     myDelButton = Qt::RightButton;
312     break;
313   case Qt::RightButton:
314   default:
315     myAddButton = Qt::LeftButton;
316     myDelButton = Qt::MidButton;
317     break;
318   };
319 }
320
321 void OCCViewer_PolygonSketcher::onDeactivate()
322 {
323   delete mypPoints;
324   mypPoints = 0;
325   delete mypData;
326   mypData = 0;
327 }
328
329 bool OCCViewer_PolygonSketcher::onKey( QKeyEvent* e )
330 {
331   if ( e->key() == Qt::Key_Escape )
332   {
333     myResult = Reject;
334     return true;
335   }
336   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
337   {
338     QPointArray* points = (QPointArray*)data();
339     if ( points->count() )
340     {
341       QPoint last = points->point( points->count() - 1 );
342       if ( last != myCurr )
343       {
344         points->resize( points->count() + 1 );
345         points->setPoint( points->count() - 1, myCurr );
346       }
347     }
348     myResult = Accept;
349     return true;
350   }
351   else if ( e->key() == Qt::Key_Backspace && e->type() == QEvent::KeyRelease )
352   {
353     QPointArray* points = (QPointArray*)data();
354     if ( points->count() > 1 )
355       points->resize( points->count() - 1 );
356     onMouse( 0 );
357     return true;
358   }
359
360   return true;
361 }
362
363 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
364 {
365   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
366
367   QPointArray* points = (QPointArray*)data();
368   if ( !points->count() && !myStart.isNull() )
369   {
370     points->resize( points->count() + 1 );
371     points->setPoint( points->count() - 1, myStart );
372   }
373
374   bool closed = false;
375   bool valid = avp->rect().contains( myCurr );
376   if ( !myStart.isNull() )
377   {
378     QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
379                  2 * myToler.width(), 2 * myToler.height() );
380     closed = aRect.contains( myCurr );
381   }
382   valid = valid && isValid( points, myCurr );
383   if ( closed && !valid )
384     closed = false;
385
386   if ( closed )
387     avp->setCursor( Qt::CrossCursor );
388   else if ( valid )
389     avp->setCursor( Qt::PointingHandCursor );
390   else
391     avp->setCursor( Qt::ForbiddenCursor );
392
393   if ( !e )
394     return;
395
396   if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
397   {
398     myResult = Reject;
399     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
400                                                    e->globalPos(), e->state(), e->button() ) );
401   }
402   else if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myAddButton ) )
403   {
404     if ( closed )
405       myResult = Accept;
406     else
407     {
408       if ( myStart.isNull() )
409         myStart = myCurr;
410       else
411       {
412         QPoint last = points->point( points->count() - 1 );
413         if ( last != myCurr && valid )
414         {
415           points->resize( points->count() + 1 );
416           points->setPoint( points->count() - 1, myCurr );
417         }
418         if ( valid && myDbl )
419           myResult = Accept;
420       }
421     }
422   }
423   else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
424             ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
425   {
426     if ( points->count() > 1 )
427       points->resize( points->count() - 1 );
428     onMouse( 0 );
429   }
430   myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
431 }
432
433 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
434 {
435   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
436
437   QPointArray* points = (QPointArray*)data();
438   QPainter p( avp );
439   p.setPen( Qt::white );
440   p.setRasterOp( Qt::XorROP );
441   if ( state != Debut )
442     p.drawPolyline( *mypPoints );
443
444   if ( points->count() )
445   {
446     mypPoints->resize( points->count() + 1 );
447     for ( uint i = 0; i < points->count(); i++ )
448       mypPoints->setPoint( i, points->point( i ) );
449     mypPoints->setPoint( points->count(), myCurr );
450     if ( state != Fin )
451       p.drawPolyline( *mypPoints );
452   }
453
454   if ( state == Fin )
455   {
456     QApplication::syncX();
457     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
458   }
459 }
460
461 bool OCCViewer_PolygonSketcher::isValid( const QPointArray* aPoints, const QPoint& aCur ) const
462 {
463   if ( !aPoints->count() )
464     return true;
465
466   if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
467     return false;
468
469   const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
470
471   if ( aLast == aCur )
472     return true;
473
474   bool res = true;
475   for ( uint i = 0; i < aPoints->count() - 1 && res; i++ )
476   {
477     const QPoint& aStart = aPoints->point( i );
478     const QPoint& anEnd  = aPoints->point( i + 1 );
479     res = !isIntersect( aStart, anEnd, aCur, aLast );
480   }
481
482   return res;
483 }
484
485 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
486                                              const QPoint& aStart2, const QPoint& anEnd2 ) const
487 {
488   if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
489        ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
490     return true;
491
492   if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
493        aStart1 == anEnd2 || anEnd1 == anEnd2 )
494     return false;
495
496   double x11 = aStart1.x() * 1.0;
497   double x12 = anEnd1.x() * 1.0;
498   double y11 = aStart1.y() * 1.0;
499   double y12 = anEnd1.y() * 1.0;
500
501   double x21 = aStart2.x() * 1.0;
502   double x22 = anEnd2.x() * 1.0;
503   double y21 = aStart2.y() * 1.0;
504   double y22 = anEnd2.y() * 1.0;
505
506   double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
507   double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
508
509   double b1 = y11 - k1 * x11;
510   double b2 = y21 - k2 * x21;
511
512   if ( k1 == k2 )
513   {
514     if ( b1 != b2 )
515       return false;
516     else
517       return !( ( QMAX( x11, x12 ) <= QMIN( x21, x22 ) ||
518                   QMIN( x11, x12 ) >= QMAX( x21, x22 ) ) &&
519                 ( QMAX( y11, y12 ) <= QMIN( y21, y22 ) ||
520                   QMIN( y11, y12 ) >= QMAX( y21, y22 ) ) );
521   }
522   else
523   {
524     double x0 = ( b2 - b1 ) / ( k1 - k2 );
525     double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
526
527     if ( QMIN( x11, x12 ) < x0 && x0 < QMAX( x11, x12 ) &&
528          QMIN( y11, y12 ) < y0 && y0 < QMAX( y11, y12 ) &&
529          QMIN( x21, x22 ) < x0 && x0 < QMAX( x21, x22 ) &&
530          QMIN( y21, y22 ) < y0 && y0 < QMAX( y21, y22 ) )
531       return true;
532   }
533   return false;
534 }
535
536