]> SALOME platform Git repositories - modules/gui.git/blob - src/OCCViewer/OCCViewer_ViewSketcher.cxx
Salome HOME
[bos #42871] Clipping plane remains applied after being deleted
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewSketcher.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, 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, or (at your option) any later version.
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 #include "ViewerTools_ScreenScaling.h"
24
25 #include "QtxRubberBand.h"
26
27 #include <QApplication>
28 #include <QPainter>
29 #include <QPolygon>
30 #include <QMouseEvent>
31 #include <QKeyEvent>
32
33 /****************************************************************
34 **  Class: OCCViewer_ViewSketcher
35 **  Level: Public
36 *****************************************************************/
37
38 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
39 : QObject( vw ),
40 mySketchButton( Qt::LeftButton ),
41 mypViewWindow( vw ),
42 myType( type ),
43 mypData( 0 ),
44 myResult( Neutral ),
45 myButtonState( 0 ),
46 myHasShift( false )
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 bool OCCViewer_ViewSketcher::isHasShift() const
105 {
106   return myHasShift;
107 }
108
109 void OCCViewer_ViewSketcher::onActivate()
110 {
111 }
112
113 void OCCViewer_ViewSketcher::onDeactivate()
114 {
115 }
116
117 bool OCCViewer_ViewSketcher::isDefault() const
118 {
119   return true;
120 }
121
122 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
123 {
124   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
125
126   // We need to downscale only non-system events here
127   if (!e->spontaneous())
128   {
129     // Make a copy event with updated coordinates
130     e = ViewerTools_ScreenScaling::getDpiAwareEvent(e, false);
131   }
132
133   QMouseEvent* me = (QMouseEvent*)e;
134   SketchState state = EnTrain;
135   bool ignore = false;
136   if ( o == avp )
137   {
138     switch ( e->type() )
139     {
140       case QEvent::MouseMove:
141       case QEvent::MouseButtonPress:
142       case QEvent::MouseButtonRelease:
143       case QEvent::MouseButtonDblClick:
144       {
145
146         myButtonState = me->buttons();
147         if ( e->type() == QEvent::MouseButtonPress )
148           myButtonState |= me->button();
149
150         if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
151         {
152           state = Debut;
153           myStart = me->pos();
154         }
155
156         myCurr = me->pos();
157
158         onMouse( me );
159
160         if ( myResult != Neutral )
161           state = Fin;
162
163         ignore = true;
164         myHasShift = ( me->modifiers() & Qt::ShiftModifier );
165         break;
166       }
167       case QEvent::Hide:
168       case QEvent::HideToParent:
169         myResult = Reject;
170         onSketch( Fin );
171         break;
172       default:
173         break;
174     }
175   }
176   if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
177   {
178     ignore = onKey( (QKeyEvent*)e );
179     if ( myResult != Neutral )
180       state = Fin;
181   }
182
183   if ( ignore )
184   {
185     onSketch( state );
186     return true;
187   }
188   return QObject::eventFilter( o, e );
189 }
190
191 void OCCViewer_ViewSketcher::onDrawViewPort()
192 {
193   onSketch( Debut );
194 }
195
196 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
197 {
198   return false;
199 }
200
201 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
202 {
203 }
204
205 int OCCViewer_ViewSketcher::sketchButton()
206 {
207   return mySketchButton;
208 }
209
210 void OCCViewer_ViewSketcher::setSketchButton( int b )
211 {
212   mySketchButton = b;
213 }
214
215 /****************************************************************
216 **  Class: OCCViewer_RectSketcher
217 **  Level: Public
218 *****************************************************************/
219
220 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
221   : OCCViewer_ViewSketcher( vw, typ )
222 {
223   if ( vw )
224     {
225       OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
226       mypRectRB = new QtxRectRubberBand( avp );
227     }
228 }
229
230 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
231 {
232   delete (QRect*)mypData;
233 }
234
235 void OCCViewer_RectSketcher::onActivate()
236 {
237   mypData = new QRect();
238 }
239
240 void OCCViewer_RectSketcher::onDeactivate()
241 {
242   delete (QRect*)mypData;
243   mypData = 0;
244   mypRectRB->clearGeometry();
245   mypRectRB->hide();
246 }
247
248 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
249 {
250   if ( e->key() == Qt::Key_Escape )
251     myResult = Reject;
252   else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
253     myResult = Accept;
254
255   return true;
256 }
257
258 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
259 {
260   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
261
262   if ( avp->rect().contains( myCurr ) )
263     avp->setCursor( Qt::PointingHandCursor );
264   else
265     avp->setCursor( Qt::ForbiddenCursor );
266
267   if ( e->type() == QEvent::MouseButtonRelease && (int)e->button() == sketchButton() ) // todo Qt::MouseButton is unsigned int: comparison of int with uint
268   {
269     myResult = Accept;
270     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
271                                                    e->globalPos(), e->button(), 
272                                                    e->buttons(), e->modifiers() ) );
273   }
274 }
275
276 void OCCViewer_RectSketcher::onSketch( SketchState state )
277 {
278   //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
279
280   if ( mypRectRB )
281     {      
282       QRect* sketchRect = (QRect*)data();
283       if ( myButtonState & sketchButton() )
284         {   
285           QRect rect = QRect( myStart, myCurr ).normalized();
286           /*QRect rect( qMin( myStart.x(), myCurr.x() ), qMin( myStart.y(), myCurr.y() ),
287                       qAbs( myStart.x() - myCurr.x() ), qAbs( myStart.y() - myCurr.y() ) );
288           QPainter p( avp );
289           p.setPen( Qt::white );
290           p.setCompositionMode( QPainter::CompositionMode_Xor );
291           */
292           
293           //if ( state != Debut && !sketchRect->isEmpty() )
294           //  p.drawRect( *sketchRect );
295
296           *sketchRect = rect;
297           if ( !rect.isEmpty() && state != Fin )
298             {
299               //p.drawRect( *sketchRect );            
300               mypRectRB->initGeometry( rect );
301               mypRectRB->show();
302             }          
303           else
304             mypRectRB->hide();
305         }
306     }
307
308   if ( state == Fin )
309   {
310     mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
311   }
312 }
313
314 /****************************************************************
315 **  Class: OCCViewer_PolygonSketcher
316 **  Level: Public
317 *****************************************************************/
318
319 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
320 : OCCViewer_ViewSketcher( vw, typ ),
321   myDbl           ( false ),
322   myToler         ( 5, 5 ),
323   //mypPoints        ( 0L ),
324   myAddButton     ( 0 ),
325   myDelButton     ( 0 ),
326   myMode          ( Poligone )
327 {
328   mySketchButton = Qt::LeftButton;
329   if ( vw )
330   {
331     OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
332     mypPolyRB = new QtxPolyRubberBand( avp );
333     mypCircleRB = new QtxCircleRubberBand( avp );
334   }
335   mypData = new QPolygon( 0 );
336 }
337
338 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
339 {
340   //delete mypPoints;
341   delete (QPolygon*)mypData;
342 }
343
344 void OCCViewer_PolygonSketcher::onActivate()
345 {
346   myDbl = false;
347   //mypPoints = new QPolygon( 0 );
348
349   switch ( sketchButton() )
350   {
351   case Qt::LeftButton:
352     myAddButton = Qt::RightButton;
353     myDelButton = Qt::MidButton;
354     break;
355   case Qt::MidButton:
356     myAddButton = Qt::LeftButton;
357     myDelButton = Qt::RightButton;
358     break;
359   case Qt::RightButton:
360   default:
361     myAddButton = Qt::LeftButton;
362     myDelButton = Qt::MidButton;
363     break;
364   };
365 }
366
367 void OCCViewer_PolygonSketcher::onDeactivate()
368 {
369   if (mypPolyRB) {
370     mypPolyRB->clearGeometry();
371     mypPolyRB->hide();
372   }
373   if (mypCircleRB) {
374     mypCircleRB->clearGeometry();
375     mypCircleRB->hide();
376   }
377   ((QPolygon*)mypData)->clear();
378 }
379
380 bool OCCViewer_PolygonSketcher::onKey(QKeyEvent* e)
381 {
382   int aKey = e->key();
383   if (aKey == Qt::Key_Escape)
384   {
385     myResult = Reject;
386     return true;
387   }
388   else if (aKey == Qt::Key_Enter || aKey == Qt::Key_Return)
389   {
390     QPolygon* points = (QPolygon*)data();
391     if (points->count())
392     {
393       QPoint last = points->point(points->count() - 1);
394       if (last != myCurr)
395       {
396         points->resize(points->count() + 1);
397         points->setPoint(points->count() - 1, myCurr);
398       }
399     }
400     myResult = Accept;
401     return true;
402   }
403   else if (aKey == Qt::Key_Backspace && e->type() == QEvent::KeyRelease)
404   {
405     QPolygon* points = (QPolygon*)data();
406     if (points->count() > 1)
407       points->resize(points->count() - 1);
408     onMouse(0);
409     return true;
410   }
411   else if (aKey == Qt::Key_Space && e->type() == QEvent::KeyRelease) 
412   {
413     OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
414     bool closed = false;
415     QPolygon* points = (QPolygon*)data();
416     bool valid = avp->rect().contains(myCurr);
417     if (!myStart.isNull())
418     {
419       QRect aRect(myStart.x() - myToler.width(), myStart.y() - myToler.height(),
420         2 * myToler.width(), 2 * myToler.height());
421       closed = aRect.contains(myCurr);
422     }
423     valid = valid && isValid(points, myCurr);
424     if (closed && !valid)
425       closed = false;
426     if (closed)
427       myResult = Accept;
428     else
429     {
430       if (myStart.isNull())
431         myStart = myCurr;
432       else
433       {
434         QPoint last = points->point(points->count() - 1);
435         if (last != myCurr && valid)
436         {
437           points->resize(points->count() + 1);
438           points->setPoint(points->count() - 1, myCurr);
439         }
440         if (valid && myDbl)
441           myResult = Accept;
442       }
443     }
444   }
445
446   return true;
447 }
448
449 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
450 {
451   OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
452
453   QPolygon* points = (QPolygon*)data();
454   if ( !points->count() && !myStart.isNull() )
455   {
456     points->resize( points->count() + 1 );
457     points->setPoint( points->count() - 1, myStart );
458   }
459
460   bool closed = false;
461   bool valid = avp->rect().contains( myCurr );
462   if ( !myStart.isNull() )
463   {
464     QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
465                  2 * myToler.width(), 2 * myToler.height() );
466     closed = aRect.contains( myCurr );
467   }
468   valid = valid && isValid( points, myCurr );
469   if ( closed && !valid )
470     closed = false;
471
472   if ( closed )
473     avp->setCursor( Qt::CrossCursor );
474   else if ( valid )
475     avp->setCursor( Qt::PointingHandCursor );
476   else
477     avp->setCursor( Qt::ForbiddenCursor );
478
479   if ( !e )
480     return;
481
482   if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
483   {
484     myResult = (closed && (points->count() > 2)) ? Accept : Reject;
485     QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
486                                                    e->globalPos(), e->button(), 
487                                                    e->buttons(), e->modifiers() ) );
488   }
489   else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
490             ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
491   {
492     if ( points->count() > 1 )
493       points->resize( points->count() - 1 );
494     onMouse( 0 );
495   }
496   myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
497 }
498
499 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
500 {
501   QPolygon* points = (QPolygon*)data();
502   switch (myMode) {
503   case Poligone:
504     if (mypPolyRB) {
505       if (state == Fin) {
506         mypPolyRB->clearGeometry();
507         mypPolyRB->hide();
508         mypViewWindow->activateSketching(OCCViewer_ViewWindow::NoSketching);
509       }
510       else {
511         mypPolyRB->setUpdatesEnabled(false);
512         if (!mypPolyRB->isVisible())
513           mypPolyRB->show();
514
515         if (state != Fin && points->count())
516           mypPolyRB->initGeometry(QPolygon(*points) << myCurr);
517         mypPolyRB->setUpdatesEnabled(true);
518       }
519     }
520     break;
521   case Circle:
522     if (mypCircleRB) {
523       if (state == Fin) {
524         mypCircleRB->getPoligon(points);
525         mypCircleRB->clearGeometry();
526         mypCircleRB->hide();
527         if (points->size() == CIRCLE_NB_POINTS)
528           myResult = Accept;
529         mypViewWindow->activateSketching(OCCViewer_ViewWindow::NoSketching);
530       }
531       else {
532         mypCircleRB->setUpdatesEnabled(false);
533
534         if (state != Fin) {
535           if (mypCircleRB->isCenterDefined()) {
536             mypCircleRB->setRadius(myCurr);
537             if ((mypCircleRB->radius() > MIN_RADIUS) && (!mypCircleRB->isVisible()))
538               mypCircleRB->show();
539           }
540           else {
541             mypCircleRB->initGeometry(myCurr);
542           }
543         }
544         mypCircleRB->setUpdatesEnabled(true);
545       }
546     }
547     break;
548   }
549 }
550
551 bool OCCViewer_PolygonSketcher::isValid( const QPolygon* aPoints, const QPoint& aCur ) const
552 {
553   if ( !aPoints->count() )
554     return true;
555
556   if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
557     return false;
558
559   const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
560
561   if ( aLast == aCur )
562     return true;
563
564   bool res = true;
565   for ( int i = 0; i < aPoints->count() - 1 && res; i++ )
566   {
567     const QPoint& aStart = aPoints->point( i );
568     const QPoint& anEnd  = aPoints->point( i + 1 );
569     res = !isIntersect( aStart, anEnd, aCur, aLast );
570   }
571
572   return res;
573 }
574
575 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
576                                              const QPoint& aStart2, const QPoint& anEnd2 ) const
577 {
578   if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
579        ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
580     return true;
581
582   if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
583        aStart1 == anEnd2 || anEnd1 == anEnd2 )
584     return false;
585
586   double x11 = aStart1.x() * 1.0;
587   double x12 = anEnd1.x() * 1.0;
588   double y11 = aStart1.y() * 1.0;
589   double y12 = anEnd1.y() * 1.0;
590
591   double x21 = aStart2.x() * 1.0;
592   double x22 = anEnd2.x() * 1.0;
593   double y21 = aStart2.y() * 1.0;
594   double y22 = anEnd2.y() * 1.0;
595
596   double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
597   double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
598
599   double b1 = y11 - k1 * x11;
600   double b2 = y21 - k2 * x21;
601
602   if ( k1 == k2 )
603   {
604     if ( b1 != b2 )
605       return false;
606     else
607       return !( ( qMax( x11, x12 ) <= qMin( x21, x22 ) ||
608                   qMin( x11, x12 ) >= qMax( x21, x22 ) ) &&
609                 ( qMax( y11, y12 ) <= qMin( y21, y22 ) ||
610                   qMin( y11, y12 ) >= qMax( y21, y22 ) ) );
611   }
612   else
613   {
614     double x0 = ( b2 - b1 ) / ( k1 - k2 );
615     double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
616
617     if ( qMin( x11, x12 ) < x0 && x0 < qMax( x11, x12 ) &&
618          qMin( y11, y12 ) < y0 && y0 < qMax( y11, y12 ) &&
619          qMin( x21, x22 ) < x0 && x0 < qMax( x21, x22 ) &&
620          qMin( y21, y22 ) < y0 && y0 < qMax( y21, y22 ) )
621       return true;
622   }
623   return false;
624 }
625
626
627 void OCCViewer_PolygonSketcher::setSketcherMode(int theMode)
628 {
629   myMode = (SketchMode)theMode;
630 }