1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, 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.
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"
24 #include "QtxRubberBand.h"
26 #include <QApplication>
29 #include <QMouseEvent>
32 /****************************************************************
33 ** Class: OCCViewer_ViewSketcher
35 *****************************************************************/
37 OCCViewer_ViewSketcher::OCCViewer_ViewSketcher( OCCViewer_ViewWindow* vw, int type )
39 mySketchButton( Qt::LeftButton ),
49 OCCViewer_ViewSketcher::~OCCViewer_ViewSketcher()
53 void OCCViewer_ViewSketcher::activate()
55 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
57 mySavedCursor = avp->cursor();
58 avp->setCursor( Qt::PointingHandCursor );
59 avp->installEventFilter( this );
60 qApp->installEventFilter( this );
62 connect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
70 void OCCViewer_ViewSketcher::deactivate()
72 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
74 disconnect( avp, SIGNAL( vpDrawExternal( QPainter* ) ), this, SLOT( onDrawViewPort() ) );
76 qApp->removeEventFilter( this );
77 avp->removeEventFilter( this );
78 avp->setCursor( mySavedCursor );
83 int OCCViewer_ViewSketcher::type() const
88 void* OCCViewer_ViewSketcher::data() const
93 int OCCViewer_ViewSketcher::result() const
98 int OCCViewer_ViewSketcher::buttonState() const
100 return myButtonState;
103 bool OCCViewer_ViewSketcher::isHasShift() const
108 void OCCViewer_ViewSketcher::onActivate()
112 void OCCViewer_ViewSketcher::onDeactivate()
116 bool OCCViewer_ViewSketcher::isDefault() const
121 bool OCCViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
123 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
125 QMouseEvent* me = (QMouseEvent*)e;
126 SketchState state = EnTrain;
132 case QEvent::MouseMove:
133 case QEvent::MouseButtonPress:
134 case QEvent::MouseButtonRelease:
135 case QEvent::MouseButtonDblClick:
138 myButtonState = me->buttons();
139 if ( e->type() == QEvent::MouseButtonPress )
140 myButtonState |= me->button();
142 if ( myStart.isNull() && ( myButtonState & sketchButton() ) )
152 if ( myResult != Neutral )
156 myHasShift = ( me->modifiers() & Qt::ShiftModifier );
160 case QEvent::HideToParent:
168 if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
170 ignore = onKey( (QKeyEvent*)e );
171 if ( myResult != Neutral )
180 return QObject::eventFilter( o, e );
183 void OCCViewer_ViewSketcher::onDrawViewPort()
188 bool OCCViewer_ViewSketcher::onKey( QKeyEvent* )
193 void OCCViewer_ViewSketcher::onMouse( QMouseEvent* )
197 int OCCViewer_ViewSketcher::sketchButton()
199 return mySketchButton;
202 void OCCViewer_ViewSketcher::setSketchButton( int b )
207 /****************************************************************
208 ** Class: OCCViewer_RectSketcher
210 *****************************************************************/
212 OCCViewer_RectSketcher::OCCViewer_RectSketcher( OCCViewer_ViewWindow* vw, int typ )
213 : OCCViewer_ViewSketcher( vw, typ )
217 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
218 mypRectRB = new QtxRectRubberBand( avp );
222 OCCViewer_RectSketcher::~OCCViewer_RectSketcher()
224 delete (QRect*)mypData;
227 void OCCViewer_RectSketcher::onActivate()
229 mypData = new QRect();
232 void OCCViewer_RectSketcher::onDeactivate()
234 delete (QRect*)mypData;
236 mypRectRB->clearGeometry();
239 bool OCCViewer_RectSketcher::onKey( QKeyEvent* e )
241 if ( e->key() == Qt::Key_Escape )
243 else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
249 void OCCViewer_RectSketcher::onMouse( QMouseEvent* e )
251 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
253 if ( avp->rect().contains( myCurr ) )
254 avp->setCursor( Qt::PointingHandCursor );
256 avp->setCursor( Qt::ForbiddenCursor );
258 if ( e->type() == QEvent::MouseButtonRelease && e->button() == sketchButton() )
261 QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
262 e->globalPos(), e->button(),
263 e->buttons(), e->modifiers() ) );
267 void OCCViewer_RectSketcher::onSketch( SketchState state )
269 //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
273 QRect* sketchRect = (QRect*)data();
274 if ( myButtonState & sketchButton() )
276 QRect rect = QRect( myStart, myCurr ).normalized();
277 /*QRect rect( qMin( myStart.x(), myCurr.x() ), qMin( myStart.y(), myCurr.y() ),
278 qAbs( myStart.x() - myCurr.x() ), qAbs( myStart.y() - myCurr.y() ) );
280 p.setPen( Qt::white );
281 p.setCompositionMode( QPainter::CompositionMode_Xor );
284 //if ( state != Debut && !sketchRect->isEmpty() )
285 // p.drawRect( *sketchRect );
288 if ( !rect.isEmpty() && state != Fin )
290 //p.drawRect( *sketchRect );
291 mypRectRB->initGeometry( rect );
301 QApplication::syncX(); /* force rectangle redrawing */
302 mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
306 /****************************************************************
307 ** Class: OCCViewer_PolygonSketcher
309 *****************************************************************/
311 OCCViewer_PolygonSketcher::OCCViewer_PolygonSketcher( OCCViewer_ViewWindow* vw, int typ )
312 : OCCViewer_ViewSketcher( vw, typ ),
319 mySketchButton = Qt::RightButton;
322 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
323 mypPolyRB = new QtxPolyRubberBand( avp );
327 OCCViewer_PolygonSketcher::~OCCViewer_PolygonSketcher()
330 delete (QPolygon*)mypData;
333 void OCCViewer_PolygonSketcher::onActivate()
336 mypData = new QPolygon( 0 );
337 //mypPoints = new QPolygon( 0 );
339 switch ( sketchButton() )
342 myAddButton = Qt::RightButton;
343 myDelButton = Qt::MidButton;
346 myAddButton = Qt::LeftButton;
347 myDelButton = Qt::RightButton;
349 case Qt::RightButton:
351 myAddButton = Qt::LeftButton;
352 myDelButton = Qt::MidButton;
357 void OCCViewer_PolygonSketcher::onDeactivate()
361 delete (QPolygon*)mypData;
365 mypPolyRB->clearGeometry();
368 bool OCCViewer_PolygonSketcher::onKey( QKeyEvent* e )
370 if ( e->key() == Qt::Key_Escape )
375 else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
377 QPolygon* points = (QPolygon*)data();
378 if ( points->count() )
380 QPoint last = points->point( points->count() - 1 );
381 if ( last != myCurr )
383 points->resize( points->count() + 1 );
384 points->setPoint( points->count() - 1, myCurr );
390 else if ( e->key() == Qt::Key_Backspace && e->type() == QEvent::KeyRelease )
392 QPolygon* points = (QPolygon*)data();
393 if ( points->count() > 1 )
394 points->resize( points->count() - 1 );
402 void OCCViewer_PolygonSketcher::onMouse( QMouseEvent* e )
404 OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
406 QPolygon* points = (QPolygon*)data();
407 if ( !points->count() && !myStart.isNull() )
409 points->resize( points->count() + 1 );
410 points->setPoint( points->count() - 1, myStart );
414 bool valid = avp->rect().contains( myCurr );
415 if ( !myStart.isNull() )
417 QRect aRect( myStart.x() - myToler.width(), myStart.y() - myToler.height(),
418 2 * myToler.width(), 2 * myToler.height() );
419 closed = aRect.contains( myCurr );
421 valid = valid && isValid( points, myCurr );
422 if ( closed && !valid )
426 avp->setCursor( Qt::CrossCursor );
428 avp->setCursor( Qt::PointingHandCursor );
430 avp->setCursor( Qt::ForbiddenCursor );
435 if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & sketchButton() ) )
438 QApplication::postEvent( avp, new QMouseEvent( e->type(), e->pos(),
439 e->globalPos(), e->button(),
440 e->buttons(), e->modifiers() ) );
442 else if ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myAddButton ) )
448 if ( myStart.isNull() )
452 QPoint last = points->point( points->count() - 1 );
453 if ( last != myCurr && valid )
455 points->resize( points->count() + 1 );
456 points->setPoint( points->count() - 1, myCurr );
458 if ( valid && myDbl )
463 else if ( ( e->type() == QEvent::MouseButtonRelease && ( e->button() & myDelButton ) ) ||
464 ( e->type() == QEvent::MouseButtonDblClick && ( e->button() & myDelButton ) ) )
466 if ( points->count() > 1 )
467 points->resize( points->count() - 1 );
470 myDbl = e->type() == QEvent::MouseButtonDblClick && ( e->button() & myAddButton );
473 void OCCViewer_PolygonSketcher::onSketch( SketchState state )
475 //OCCViewer_ViewPort3d* avp = mypViewWindow->getViewPort();
477 QPolygon* points = (QPolygon*)data();
479 p.setPen( Qt::white );
480 p.setCompositionMode( QPainter::CompositionMode_Xor );
481 if ( state != Debut )
482 p.drawPolyline( *mypPoints );
484 if ( points->count() )
486 mypPoints->resize( points->count() + 1 );
487 for ( uint i = 0; i < points->count(); i++ )
488 mypPoints->setPoint( i, points->point( i ) );
489 mypPoints->setPoint( points->count(), myCurr );
491 p.drawPolyline( *mypPoints );
495 mypPolyRB->setUpdatesEnabled ( false );
496 if ( !mypPolyRB->isVisible() )
498 //if ( state != Debut )
499 // mypPolyRB->repaint();
501 if ( state != Fin && points->count() )
502 mypPolyRB->initGeometry( QPolygon(*points) << myCurr );
503 //mypPolyRB->addNode( myCurr );
505 //if ( state != Fin )
506 // mypPolyRB->repaint();
507 mypPolyRB->setUpdatesEnabled ( true );
508 //mypPolyRB->repaint();
515 mypPolyRB->clearGeometry();
518 QApplication::syncX();
519 mypViewWindow->activateSketching( OCCViewer_ViewWindow::NoSketching );
523 bool OCCViewer_PolygonSketcher::isValid( const QPolygon* aPoints, const QPoint& aCur ) const
525 if ( !aPoints->count() )
528 if ( aPoints->count() == 1 && aPoints->point( 0 ) == aCur )
531 const QPoint& aLast = aPoints->point( aPoints->count() - 1 );
537 for ( uint i = 0; i < aPoints->count() - 1 && res; i++ )
539 const QPoint& aStart = aPoints->point( i );
540 const QPoint& anEnd = aPoints->point( i + 1 );
541 res = !isIntersect( aStart, anEnd, aCur, aLast );
547 bool OCCViewer_PolygonSketcher::isIntersect( const QPoint& aStart1, const QPoint& anEnd1,
548 const QPoint& aStart2, const QPoint& anEnd2 ) const
550 if ( ( aStart1 == aStart2 && anEnd1 == anEnd2 ) ||
551 ( aStart1 == anEnd2 && anEnd1 == aStart2 ) )
554 if ( aStart1 == aStart2 || aStart2 == anEnd1 ||
555 aStart1 == anEnd2 || anEnd1 == anEnd2 )
558 double x11 = aStart1.x() * 1.0;
559 double x12 = anEnd1.x() * 1.0;
560 double y11 = aStart1.y() * 1.0;
561 double y12 = anEnd1.y() * 1.0;
563 double x21 = aStart2.x() * 1.0;
564 double x22 = anEnd2.x() * 1.0;
565 double y21 = aStart2.y() * 1.0;
566 double y22 = anEnd2.y() * 1.0;
568 double k1 = x12 == x11 ? 0 : ( y12 - y11 ) / ( x12 - x11 );
569 double k2 = x22 == x21 ? 0 : ( y22 - y21 ) / ( x22 - x21 );
571 double b1 = y11 - k1 * x11;
572 double b2 = y21 - k2 * x21;
579 return !( ( qMax( x11, x12 ) <= qMin( x21, x22 ) ||
580 qMin( x11, x12 ) >= qMax( x21, x22 ) ) &&
581 ( qMax( y11, y12 ) <= qMin( y21, y22 ) ||
582 qMin( y11, y12 ) >= qMax( y21, y22 ) ) );
586 double x0 = ( b2 - b1 ) / ( k1 - k2 );
587 double y0 = ( k1 * b2 - k2 * b1 ) / ( k1 - k2 );
589 if ( qMin( x11, x12 ) < x0 && x0 < qMax( x11, x12 ) &&
590 qMin( y11, y12 ) < y0 && y0 < qMax( y11, y12 ) &&
591 qMin( x21, x22 ) < x0 && x0 < qMax( x21, x22 ) &&
592 qMin( y21, y22 ) < y0 && y0 < qMax( y21, y22 ) )