KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 00020 ** 00021 **********************************************************************/ 00022 00023 #include "ReverseMapper.h" 00024 00025 #include <math.h> 00026 00027 #include <QRect> 00028 #include <QtDebug> 00029 #include <QPolygonF> 00030 #include <QPainterPath> 00031 #include <QGraphicsScene> 00032 00033 #include "KDChartAbstractDiagram.h" 00034 #include "ChartGraphicsItem.h" 00035 00036 using namespace KDChart; 00037 00038 ReverseMapper::ReverseMapper() 00039 : m_scene( 0 ) 00040 , m_diagram( 0 ) 00041 { 00042 } 00043 00044 ReverseMapper::ReverseMapper( AbstractDiagram* diagram ) 00045 : m_scene( 0 ) 00046 , m_diagram( diagram ) 00047 { 00048 } 00049 00050 ReverseMapper::~ReverseMapper() 00051 { 00052 delete m_scene; m_scene = 0; 00053 } 00054 00055 void ReverseMapper::setDiagram( AbstractDiagram* diagram ) 00056 { 00057 00058 m_diagram = diagram; 00059 } 00060 00061 void ReverseMapper::clear() 00062 { 00063 m_itemMap.clear(); 00064 delete m_scene; 00065 m_scene = new QGraphicsScene(); 00066 } 00067 00068 QModelIndexList ReverseMapper::indexesIn( const QRect& rect ) const 00069 { 00070 Q_ASSERT( m_diagram ); 00071 if ( m_scene && m_scene->sceneRect().intersects( rect ) ) { 00072 QList<QGraphicsItem *> items = m_scene->items( rect ); 00073 QModelIndexList indexes; 00074 Q_FOREACH( QGraphicsItem* item, items ) { 00075 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item ); 00076 if ( i ) { 00077 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked 00078 indexes << index; 00079 } 00080 } 00081 return indexes; 00082 } else { 00083 return QModelIndexList(); 00084 } 00085 } 00086 00087 QModelIndexList ReverseMapper::indexesAt( const QPointF& point ) const 00088 { 00089 Q_ASSERT( m_diagram ); 00090 if ( m_scene && m_scene->sceneRect().contains( point ) ) { 00091 QList<QGraphicsItem *> items = m_scene->items( point ); 00092 QModelIndexList indexes; 00093 Q_FOREACH( QGraphicsItem* item, items ) { 00094 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item ); 00095 if ( i ) { 00096 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked 00097 if( !indexes.contains(index) ) 00098 indexes << index; 00099 } 00100 } 00101 return indexes; 00102 } else { 00103 return QModelIndexList(); 00104 } 00105 } 00106 00107 QPolygonF ReverseMapper::polygon( int row, int column ) const 00108 { 00109 if ( !m_diagram->model()->hasIndex( row, column, m_diagram->rootIndex() ) ) 00110 return QPolygon(); 00111 const QModelIndex index = m_diagram->model()->index( row, column, m_diagram->rootIndex() ); // checked 00112 return m_itemMap.contains( index ) ? m_itemMap[ index ]->polygon() : QPolygon(); 00113 } 00114 00115 QRectF ReverseMapper::boundingRect( int row, int column ) const 00116 { 00117 if ( !m_diagram->model()->hasIndex( row, column, m_diagram->rootIndex() ) ) 00118 return QRectF(); 00119 const QModelIndex index = m_diagram->model()->index( row, column, m_diagram->rootIndex() ); // checked 00120 return m_itemMap.contains( index ) ? m_itemMap[ index ]->polygon().boundingRect() : QRectF(); 00121 } 00122 00123 void ReverseMapper::addItem( ChartGraphicsItem* item ) 00124 { 00125 Q_ASSERT( m_scene ); 00126 m_scene->addItem( item ); 00127 m_itemMap.insert( m_diagram->model()->index( item->row(), item->column(), m_diagram->rootIndex() ), item ); // checked 00128 } 00129 00130 void ReverseMapper::addRect( int row, int column, const QRectF& rect ) 00131 { 00132 addPolygon( row, column, QPolygonF( rect ) ); 00133 } 00134 00135 void ReverseMapper::addPolygon( int row, int column, const QPolygonF& polygon ) 00136 { 00137 ChartGraphicsItem* item = new ChartGraphicsItem( row, column ); 00138 item->setPolygon( polygon ); 00139 addItem( item ); 00140 } 00141 00142 void ReverseMapper::addCircle( int row, int column, const QPointF& location, const QSizeF& diameter ) 00143 { 00144 QPainterPath path; 00145 QPointF ossfet( -0.5*diameter.width(), -0.5*diameter.height() ); 00146 path.addEllipse( QRectF( location + ossfet, diameter ) ); 00147 addPolygon( row, column, QPolygonF( path.toFillPolygon() ) ); 00148 } 00149 00150 void ReverseMapper::addLine( int row, int column, const QPointF& from, const QPointF& to ) 00151 { 00152 // that's no line, dude... make a small circle around that point, instead 00153 if( from == to ) 00154 { 00155 addCircle( row, column, from, QSizeF( 1.5, 1.5 ) ); 00156 return; 00157 } 00158 // lines do not make good polygons to click on. we calculate a 2 00159 // pixel wide rectangle, where the original line is excatly 00160 // centered in. 00161 // make a 3 pixel wide polygon from the line: 00162 static const QPointF pixel( 1.0, 1.0 ); 00163 QPointF left, right; 00164 if ( from.x() < to.x() ) { 00165 left = from; 00166 right = to; 00167 } else { 00168 right = from; 00169 left = to; 00170 } 00171 const QPointF lineVector( right - left ); 00172 const qreal lineVectorLength = sqrt( lineVector.x() * lineVector.x() + lineVector.y() * lineVector.y() ); 00173 const QPointF lineVectorUnit( lineVector / lineVectorLength ); 00174 const QPointF normOfLineVectorUnit( -lineVectorUnit.y(), lineVectorUnit.x() ); 00175 // now the four polygon end points: 00176 const QPointF one( left - lineVectorUnit + normOfLineVectorUnit ); 00177 const QPointF two( left - lineVectorUnit - normOfLineVectorUnit ); 00178 const QPointF three( right + lineVectorUnit - normOfLineVectorUnit ); 00179 const QPointF four( right + lineVectorUnit + normOfLineVectorUnit ); 00180 addPolygon( row, column, QPolygonF() << one << two << three << four ); 00181 }