geom/src/DependencyTree/DependencyTree_Arrow.cxx
2022-05-05 15:01:15 +03:00

265 lines
10 KiB
C++

// Copyright (C) 2014-2022 CEA/DEN, EDF R&D, OPEN CASCADE
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
// internal includes
#include "DependencyTree_Arrow.h"
#include "DependencyTree_Object.h"
// GUI includes
#include <SUIT_Session.h>
#include <SUIT_ResourceMgr.h>
// Qt includes
#include <QPainter>
#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>
const qreal arrowSize = 20;
DependencyTree_Arrow::DependencyTree_Arrow( DependencyTree_Object* theStartItem,
DependencyTree_Object* theEndItem,
QGraphicsItem* parent, QGraphicsScene* /*scene*/ )
:QGraphicsLineItem( parent ),
myStartItem( theStartItem ),
myEndItem( theEndItem ),
myIsBiLink( false )
{
SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
myColor = resMgr->colorValue( "Geometry", "dependency_tree_arrow_color", QColor( 0, 0, 130 ) );
myHighlightColor = resMgr->colorValue( "Geometry", "dependency_tree_highlight_arrow_color", QColor( 0, 0, 255 ) );
mySelectColor = resMgr->colorValue( "Geometry", "dependency_tree_select_arrow_color", QColor( 255, 0, 0 ) );
myStartItem = theStartItem;
myEndItem = theEndItem;
myLine = QLineF( myStartItem->pos(), myEndItem->pos() );
myArrowHead = createArrowHead( myStartItem->pos(), myEndItem->pos() );
myReverseArrowHead = createArrowHead( myEndItem->pos(), myStartItem->pos() );
mySelfDependencyArrow = QRectF();
setPen( QPen( myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
setColor( myColor );
setFlag( QGraphicsItem::ItemIsSelectable, true );
setZValue( -1000.0 );
}
DependencyTree_Arrow::~DependencyTree_Arrow()
{
}
//=================================================================================
// function : boundingRect()
// purpose : return the outer bounds of the item as a rectangle.
// QGraphicsView uses this to determine whether the item requires redrawing
//=================================================================================
QRectF DependencyTree_Arrow::boundingRect() const
{
qreal extra;
QRectF boundingRect;
if( myStartItem == myEndItem ) {
extra = arrowSize / 2.0 + 2.0;
boundingRect = mySelfDependencyArrow;
}
else {
extra = ( pen().width() + 20 ) / 2.0;
boundingRect = QRectF( myLine.p1(), QSizeF( myLine.p2().x() - myLine.p1().x(),
myLine.p2().y() - myLine.p1().y() ) );
}
return boundingRect.normalized().adjusted( -extra, -extra, extra, extra );
}
//=================================================================================
// function : shape()
// purpose : return the shape of this item to define an area of preselection
//=================================================================================
QPainterPath DependencyTree_Arrow::shape() const
{
QPainterPath path;
if( myStartItem == myEndItem ) {
qreal extra = 5;
QPolygonF aPolygonBigger( mySelfDependencyArrow.normalized()
.adjusted( -extra, -extra, extra, extra ) );
QPolygonF aPolygonSmaller( mySelfDependencyArrow.normalized()
.adjusted( extra, extra, -extra, -extra ) );
path.addPolygon( aPolygonBigger.subtracted( aPolygonSmaller ) );
path.addPolygon(myArrowHead);
}
else {
QPolygonF aShapePolygon;
QPolygon anArrowHead = myArrowHead.toPolygon();
QPolygon anReverseArrowHead = myReverseArrowHead.toPolygon();
aShapePolygon << anArrowHead.point(1) << anArrowHead.point(0) << anArrowHead.point(2) <<
anReverseArrowHead.point(1) << anReverseArrowHead.point(0) << anReverseArrowHead.point(2);
path.addPolygon( aShapePolygon );
}
return path;
}
//=================================================================================
// function : setColor()
// purpose : set default color for arrow
//=================================================================================
void DependencyTree_Arrow::setColor( const QColor& theColor )
{
myColor = theColor;
}
//=================================================================================
// function : setHighlightColor()
// purpose : set color for highlighted arrow
//=================================================================================
void DependencyTree_Arrow::setHighlightColor( const QColor& theColor )
{
myHighlightColor = theColor;
}
//=================================================================================
// function : setSelectColor()
// purpose : set color for selected arrow
//=================================================================================
void DependencyTree_Arrow::setSelectColor( const QColor& theColor )
{
mySelectColor = theColor;
}
//=================================================================================
// function : getStartItem()
// purpose : get start item of arrow
//=================================================================================
DependencyTree_Object* DependencyTree_Arrow::getStartItem() const
{
return myStartItem;
}
//=================================================================================
// function : getEndItem()
// purpose : get end item of arrow
//=================================================================================
DependencyTree_Object* DependencyTree_Arrow::getEndItem() const
{
return myEndItem;
}
//=================================================================================
// function : setIsBiLink()
// purpose : set true if current arrow is bi-directional link, else set false
//=================================================================================
void DependencyTree_Arrow::setIsBiLink( bool theIsBiLink )
{
myIsBiLink = theIsBiLink;
}
//=================================================================================
// function : paint()
// purpose : paint the contents of an item in local coordinates (called by QGraphicsView)
//=================================================================================
void DependencyTree_Arrow::paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* )
{
if( isSelected() ) {
painter->setBrush( mySelectColor );
painter->setPen( QPen( mySelectColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
}
else if( isUnderMouse() ) {
painter->setBrush( myHighlightColor );
painter->setPen( QPen( myHighlightColor, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
}
else {
painter->setBrush( myColor );
painter->setPen( QPen( myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
}
if( myStartItem == myEndItem ) {
int lineSize = 60;
QPointF p1( myStartItem->pos().x() - myStartItem->boundingRect().width()/2,
myStartItem->pos().y() );
QPointF p2( p1.x() - lineSize + myStartItem->boundingRect().height()/2, p1.y() );
QPointF p3( p2.x(), p2.y() - lineSize );
QPointF p4( p3.x() + lineSize, p3.y() );
QPointF p5( p4.x(), p4.y() + lineSize - myStartItem->boundingRect().height()/2 );
mySelfDependencyArrow = QRectF( p3.x(), p3.y(), lineSize, lineSize );
myArrowHead = createArrowHead( p4, p5, false );
QVector<QPointF> pointVector;
pointVector << p1 << p2 << p2 << p3 << p3 << p4 << p4 << p5;
painter->drawLines( pointVector);
painter->drawPolygon(myArrowHead);
}
else {
if (myStartItem->collidesWithItem(myEndItem))
return;
myArrowHead = createArrowHead( myStartItem->pos(), myEndItem->pos() );
myReverseArrowHead = createArrowHead( myEndItem->pos(), myStartItem->pos() );
painter->drawLine( myLine );
painter->drawPolygon( myArrowHead );
if( myIsBiLink )
painter->drawPolygon( myReverseArrowHead );
}
}
//=================================================================================
// function : createArrowHead()
// purpose : create a head of arrow from start point to end point
//=================================================================================
QPolygonF DependencyTree_Arrow::createArrowHead( QPointF theStartPoint, QPointF theEndPoint,
bool theIsDynamic )
{
if( theIsDynamic ) {
QLineF centerLine( theStartPoint, theEndPoint );
QPolygonF endPolygon = QPolygonF( myEndItem->boundingRect() );
QPointF p1 = endPolygon.first() + theEndPoint;
QPointF p2;
QPointF intersectPoint;
QLineF polyLine;
for( int i = 1; i < endPolygon.count(); ++i ) {
p2 = endPolygon.at(i) + theEndPoint;
polyLine = QLineF( p1, p2 );
QLineF::IntersectType intersectType = polyLine.intersect( centerLine, &intersectPoint );
if( intersectType == QLineF::BoundedIntersection )
break;
p1 = p2;
}
myLine = QLineF( intersectPoint, theStartPoint );
}
else
myLine = QLineF( theEndPoint, theStartPoint );
double angle = acos(myLine.dx() / myLine.length());
if( myLine.dy() >= 0 )
angle = ( M_PI * 2 ) - angle;
QPointF arrowP1 = myLine.p1() + QPointF( sin( angle + M_PI / 3 ) * arrowSize,
cos( angle + M_PI / 3 ) * arrowSize );
QPointF arrowP2 = myLine.p1() + QPointF( sin( angle + M_PI - M_PI / 3 ) * arrowSize,
cos( angle + M_PI - M_PI / 3 ) * arrowSize );
QPolygonF anArrowHead;
anArrowHead << myLine.p1() << arrowP1 << arrowP2;
return anArrowHead;
}