1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "OCCViewer_ViewSketcher.h"
21 #include "OCCViewer_ViewWindow.h"
22 #include "OCCViewer_ViewPort3d.h"
23 #include "ViewerTools_ScreenScaling.h"
25 #include "QtxRubberBand.h"
27 #include <QApplication>
30 #include <QMouseEvent>
33 /****************************************************************
34 ** Class: OCCViewer_ViewSketcher
36 *****************************************************************/
38 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
40 mySketchButton( Qt::LeftButton ),
50 OCCViewer_ViewSketcher::~OCCViewer_ViewSketcher()
54 void OCCViewer_ViewSketcher::activate()
56 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
58 mySavedCursor = avp->cursor();
59 avp->setCursor( Qt::PointingHandCursor );
60 avp->installEventFilter( this );
61 qApp->installEventFilter( this );
63 connect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
71 void OCCViewer_ViewSketcher::deactivate()
73 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
75 disconnect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
77 qApp->removeEventFilter( this );
78 avp->removeEventFilter( this );
79 avp->setCursor( mySavedCursor );
84 int OCCViewer_ViewSketcher::type() const
89 void* OCCViewer_ViewSketcher::data() const
94 int OCCViewer_ViewSketcher::result() const
99 int OCCViewer_ViewSketcher::buttonState() const
101 return myButtonState;
104 bool OCCViewer_ViewSketcher::isHasShift() const
109 void OCCViewer_ViewSketcher::onActivate()
113 void OCCViewer_ViewSketcher::onDeactivate()
117 bool OCCViewer_ViewSketcher::isDefault() const
122 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
124 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
126 // We need to downscale only non-system events here
127 if (!e->spontaneous())
129 // Make a copy event with updated coordinates
130 e = ViewerTools_ScreenScaling::getDpiAwareEvent(e, false);
133 QMouseEvent* me = (QMouseEvent*)e;
134 SketchState state = EnTrain;
140 case QEvent::MouseMove:
141 case QEvent::MouseButtonPress:
142 case QEvent::MouseButtonRelease:
143 case QEvent::MouseButtonDblClick:
146 myButtonState = me->buttons();
147 if ( e->type() == QEvent::MouseButtonPress )
148 myButtonState |= me->button();
150 if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
160 if ( myResult != Neutral )
164 myHasShift = ( me->modifiers() & Qt::ShiftModifier );
168 case QEvent::HideToParent:
176 if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
178 ignore = onKey( (QKeyEvent*)e );
179 if ( myResult != Neutral )
188 return QObject::eventFilter( o, e );
191 void OCCViewer_ViewSketcher::onDrawViewPort()
196 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
201 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
205 int OCCViewer_ViewSketcher::sketchButton()
207 return mySketchButton;
210 void OCCViewer_ViewSketcher::setSketchButton( int b )
215 /****************************************************************
216 ** Class: OCCViewer_RectSketcher
218 *****************************************************************/
220 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
221 : OCCViewer_ViewSketcher( vw, typ )
225 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
226 mypRectRB = new QtxRectRubberBand( avp );
230 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
232 delete (QRect*)mypData;
235 void OCCViewer_RectSketcher::onActivate()
237 mypData = new QRect();
240 void OCCViewer_RectSketcher::onDeactivate()
242 delete (QRect*)mypData;
244 mypRectRB->clearGeometry();
248 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
250 if ( e->key() == Qt::Key_Escape )
252 else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
258 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
260 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
262 if ( avp->rect().contains( myCurr ) )
263 avp->setCursor( Qt::PointingHandCursor );
265 avp->setCursor( Qt::ForbiddenCursor );
267 if ( e->type() == QEvent::MouseButtonRelease && (int)e->button() == sketchButton() ) // todo Qt::MouseButton is unsigned int: comparison of int with uint
270 QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
271 e->globalPos(), e->button(),
272 e->buttons(), e->modifiers() ) );
276 void OCCViewer_RectSketcher::onSketch( SketchState state )
278 //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
282 QRect* sketchRect = (QRect*)data();
283 if ( myButtonState & sketchButton() )
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() ) );
289 p.setPen( Qt::white );
290 p.setCompositionMode( QPainter::CompositionMode_Xor );
293 //if ( state != Debut && !sketchRect->isEmpty() )
294 // p.drawRect( *sketchRect );
297 if ( !rect.isEmpty() && state != Fin )
299 //p.drawRect( *sketchRect );
300 mypRectRB->initGeometry( rect );
310 mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
314 /****************************************************************
315 ** Class: OCCViewer_PolygonSketcher
317 *****************************************************************/
319 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
320 : OCCViewer_ViewSketcher( vw, typ ),
328 mySketchButton = Qt::LeftButton;
331 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
332 mypPolyRB = new QtxPolyRubberBand( avp );
333 mypCircleRB = new QtxCircleRubberBand( avp );
335 mypData = new QPolygon( 0 );
338 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
341 delete (QPolygon*)mypData;
344 void OCCViewer_PolygonSketcher::onActivate()
347 //mypPoints = new QPolygon( 0 );
349 switch ( sketchButton() )
352 myAddButton = Qt::RightButton;
353 myDelButton = Qt::MidButton;
356 myAddButton = Qt::LeftButton;
357 myDelButton = Qt::RightButton;
359 case Qt::RightButton:
361 myAddButton = Qt::LeftButton;
362 myDelButton = Qt::MidButton;
367 void OCCViewer_PolygonSketcher::onDeactivate()
370 mypPolyRB->clearGeometry();
374 mypCircleRB->clearGeometry();
377 ((QPolygon*)mypData)->clear();
380 bool OCCViewer_PolygonSketcher::onKey(QKeyEvent* e)
383 if (aKey == Qt::Key_Escape)
388 else if (aKey == Qt::Key_Enter || aKey == Qt::Key_Return)
390 QPolygon* points = (QPolygon*)data();
393 QPoint last = points->point(points->count() - 1);
396 points->resize(points->count() + 1);
397 points->setPoint(points->count() - 1, myCurr);
403 else if (aKey == Qt::Key_Backspace && e->type() == QEvent::KeyRelease)
405 QPolygon* points = (QPolygon*)data();
406 if (points->count() > 1)
407 points->resize(points->count() - 1);
411 else if (aKey == Qt::Key_Space && e->type() == QEvent::KeyRelease)
413 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
415 QPolygon* points = (QPolygon*)data();
416 bool valid = avp->rect().contains(myCurr);
417 if (!myStart.isNull())
419 QRect aRect(myStart.x() - myToler.width(), myStart.y() - myToler.height(),
420 2 * myToler.width(), 2 * myToler.height());
421 closed = aRect.contains(myCurr);
423 valid = valid && isValid(points, myCurr);
424 if (closed && !valid)
430 if (myStart.isNull())
434 QPoint last = points->point(points->count() - 1);
435 if (last != myCurr && valid)
437 points->resize(points->count() + 1);
438 points->setPoint(points->count() - 1, myCurr);
449 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
451 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
453 QPolygon* points = (QPolygon*)data();
454 if ( !points->count() && !myStart.isNull() )
456 points->resize( points->count() + 1 );
457 points->setPoint( points->count() - 1, myStart );
461 bool valid = avp->rect().contains( myCurr );
462 if ( !myStart.isNull() )
464 QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
465 2 * myToler.width(), 2 * myToler.height() );
466 closed = aRect.contains( myCurr );
468 valid = valid && isValid( points, myCurr );
469 if ( closed && !valid )
473 avp->setCursor( Qt::CrossCursor );
475 avp->setCursor( Qt::PointingHandCursor );
477 avp->setCursor( Qt::ForbiddenCursor );
482 if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
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() ) );
489 else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
490 ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
492 if ( points->count() > 1 )
493 points->resize( points->count() - 1 );
496 myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
499 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
501 QPolygon* points = (QPolygon*)data();
506 mypPolyRB->clearGeometry();
508 mypViewWindow->activateSketching(OCCViewer_ViewWindow::NoSketching);
511 mypPolyRB->setUpdatesEnabled(false);
512 if (!mypPolyRB->isVisible())
515 if (state != Fin && points->count())
516 mypPolyRB->initGeometry(QPolygon(*points) << myCurr);
517 mypPolyRB->setUpdatesEnabled(true);
524 mypCircleRB->getPoligon(points);
525 mypCircleRB->clearGeometry();
527 if (points->size() == CIRCLE_NB_POINTS)
529 mypViewWindow->activateSketching(OCCViewer_ViewWindow::NoSketching);
532 mypCircleRB->setUpdatesEnabled(false);
535 if (mypCircleRB->isCenterDefined()) {
536 mypCircleRB->setRadius(myCurr);
537 if ((mypCircleRB->radius() > MIN_RADIUS) && (!mypCircleRB->isVisible()))
541 mypCircleRB->initGeometry(myCurr);
544 mypCircleRB->setUpdatesEnabled(true);
551 bool OCCViewer_PolygonSketcher::isValid( const QPolygon* aPoints, const QPoint& aCur ) const
553 if ( !aPoints->count() )
556 if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
559 const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
565 for ( int i = 0; i < aPoints->count() - 1 && res; i++ )
567 const QPoint& aStart = aPoints->point( i );
568 const QPoint& anEnd = aPoints->point( i + 1 );
569 res = !isIntersect( aStart, anEnd, aCur, aLast );
575 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
576 const QPoint& aStart2, const QPoint& anEnd2 ) const
578 if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
579 ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
582 if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
583 aStart1 == anEnd2 || anEnd1 == anEnd2 )
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;
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;
596 double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
597 double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
599 double b1 = y11 - k1 * x11;
600 double b2 = y21 - k2 * x21;
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 ) ) );
614 double x0 = ( b2 - b1 ) / ( k1 - k2 );
615 double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
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 ) )
627 void OCCViewer_PolygonSketcher::setSketcherMode(int theMode)
629 myMode = (SketchMode)theMode;