File indexing completed on 2024-05-19 15:27:29
0001 /* 0002 * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License as 0008 * published by the Free Software Foundation; either version 2 of 0009 * the License, or (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "ReverseMapper.h" 0021 0022 #include <math.h> 0023 0024 #include <QRect> 0025 #include <QtDebug> 0026 #include <QPolygonF> 0027 #include <QPainterPath> 0028 #include <QGraphicsScene> 0029 0030 #include "KChartAbstractDiagram.h" 0031 #include "ChartGraphicsItem.h" 0032 0033 using namespace KChart; 0034 0035 ReverseMapper::ReverseMapper() 0036 : m_scene( nullptr ) 0037 , m_diagram( nullptr ) 0038 { 0039 } 0040 0041 ReverseMapper::ReverseMapper( AbstractDiagram* diagram ) 0042 : m_scene( nullptr ) 0043 , m_diagram( diagram ) 0044 { 0045 } 0046 0047 ReverseMapper::~ReverseMapper() 0048 { 0049 delete m_scene; m_scene = nullptr; 0050 } 0051 0052 void ReverseMapper::setDiagram( AbstractDiagram* diagram ) 0053 { 0054 0055 m_diagram = diagram; 0056 } 0057 0058 void ReverseMapper::clear() 0059 { 0060 m_itemMap.clear(); 0061 delete m_scene; 0062 m_scene = new QGraphicsScene(); 0063 } 0064 0065 QModelIndexList ReverseMapper::indexesIn( const QRect& rect ) const 0066 { 0067 Q_ASSERT( m_diagram ); 0068 if ( m_scene && m_scene->sceneRect().intersects( rect ) ) { 0069 QList<QGraphicsItem *> items = m_scene->items( rect ); 0070 QModelIndexList indexes; 0071 Q_FOREACH( QGraphicsItem* item, items ) { 0072 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item ); 0073 if ( i ) { 0074 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked 0075 indexes << index; 0076 } 0077 } 0078 return indexes; 0079 } else { 0080 return QModelIndexList(); 0081 } 0082 } 0083 0084 QModelIndexList ReverseMapper::indexesAt( const QPointF& point ) const 0085 { 0086 Q_ASSERT( m_diagram ); 0087 if ( m_scene && m_scene->sceneRect().contains( point ) ) { 0088 QList<QGraphicsItem *> items = m_scene->items( point ); 0089 QModelIndexList indexes; 0090 Q_FOREACH( QGraphicsItem* item, items ) { 0091 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item ); 0092 if ( i ) { 0093 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked 0094 if ( !indexes.contains(index) ) 0095 indexes << index; 0096 } 0097 } 0098 return indexes; 0099 } else { 0100 return QModelIndexList(); 0101 } 0102 } 0103 0104 QPolygonF ReverseMapper::polygon( int row, int column ) const 0105 { 0106 if ( !m_diagram->model()->hasIndex( row, column, m_diagram->rootIndex() ) ) 0107 return QPolygon(); 0108 const QModelIndex index = m_diagram->model()->index( row, column, m_diagram->rootIndex() ); // checked 0109 return m_itemMap.contains( index ) ? m_itemMap[ index ]->polygon() : QPolygon(); 0110 } 0111 0112 QRectF ReverseMapper::boundingRect( int row, int column ) const 0113 { 0114 if ( !m_diagram->model()->hasIndex( row, column, m_diagram->rootIndex() ) ) 0115 return QRectF(); 0116 const QModelIndex index = m_diagram->model()->index( row, column, m_diagram->rootIndex() ); // checked 0117 return m_itemMap.contains( index ) ? m_itemMap[ index ]->polygon().boundingRect() : QRectF(); 0118 } 0119 0120 void ReverseMapper::addItem( ChartGraphicsItem* item ) 0121 { 0122 Q_ASSERT( m_scene ); 0123 m_scene->addItem( item ); 0124 m_itemMap.insert( m_diagram->model()->index( item->row(), item->column(), m_diagram->rootIndex() ), item ); // checked 0125 } 0126 0127 void ReverseMapper::addRect( int row, int column, const QRectF& rect ) 0128 { 0129 addPolygon( row, column, QPolygonF( rect ) ); 0130 } 0131 0132 void ReverseMapper::addPolygon( int row, int column, const QPolygonF& polygon ) 0133 { 0134 ChartGraphicsItem* item = new ChartGraphicsItem( row, column ); 0135 item->setPolygon( polygon ); 0136 addItem( item ); 0137 } 0138 0139 void ReverseMapper::addCircle( int row, int column, const QPointF& location, const QSizeF& diameter ) 0140 { 0141 QPainterPath path; 0142 QPointF ossfet( -0.5*diameter.width(), -0.5*diameter.height() ); 0143 path.addEllipse( QRectF( location + ossfet, diameter ) ); 0144 addPolygon( row, column, QPolygonF( path.toFillPolygon() ) ); 0145 } 0146 0147 void ReverseMapper::addLine( int row, int column, const QPointF& from, const QPointF& to ) 0148 { 0149 // that's no line, dude... make a small circle around that point, instead 0150 if ( from == to ) 0151 { 0152 addCircle( row, column, from, QSizeF( 1.5, 1.5 ) ); 0153 return; 0154 } 0155 // lines do not make good polygons to click on. we calculate a 2 0156 // pixel wide rectangle, where the original line is excatly 0157 // centered in. 0158 // make a 3 pixel wide polygon from the line: 0159 QPointF left, right; 0160 if ( from.x() < to.x() ) { 0161 left = from; 0162 right = to; 0163 } else { 0164 right = from; 0165 left = to; 0166 } 0167 const QPointF lineVector( right - left ); 0168 const qreal lineVectorLength = sqrt( lineVector.x() * lineVector.x() + lineVector.y() * lineVector.y() ); 0169 const QPointF lineVectorUnit( lineVector / lineVectorLength ); 0170 const QPointF normOfLineVectorUnit( -lineVectorUnit.y(), lineVectorUnit.x() ); 0171 // now the four polygon end points: 0172 const QPointF one( left - lineVectorUnit + normOfLineVectorUnit ); 0173 const QPointF two( left - lineVectorUnit - normOfLineVectorUnit ); 0174 const QPointF three( right + lineVectorUnit - normOfLineVectorUnit ); 0175 const QPointF four( right + lineVectorUnit + normOfLineVectorUnit ); 0176 addPolygon( row, column, QPolygonF() << one << two << three << four ); 0177 }