KChart

ReverseMapper.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KD Chart library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "ReverseMapper.h"
10
11#include <math.h>
12
13#include <QRect>
14#include <QtDebug>
15#include <QPolygonF>
16#include <QPainterPath>
17#include <QGraphicsScene>
18
19#include "KChartAbstractDiagram.h"
20#include "ChartGraphicsItem.h"
21
22using namespace KChart;
23
24ReverseMapper::ReverseMapper()
25 : m_diagram( nullptr )
26 , m_scene( nullptr )
27{
28}
29
30ReverseMapper::ReverseMapper( AbstractDiagram* diagram )
31 : m_diagram( diagram )
32 , m_scene( nullptr )
33{
34}
35
36ReverseMapper::~ReverseMapper()
37{
38 delete m_scene;
39 m_scene = nullptr;
40}
41
42void ReverseMapper::setDiagram( AbstractDiagram* diagram )
43{
44 m_diagram = diagram;
45}
46
47void ReverseMapper::clear()
48{
49 m_polygons.clear();
50 if (m_scene)
51 m_scene->clear();
52 m_sceneDirty = true;
53}
54
55QModelIndexList ReverseMapper::indexesIn( const QRect& rect ) const
56{
57 populateScene();
58
59 if ( m_scene->sceneRect().intersects( rect ) ) {
60 const QList<QGraphicsItem *> items = m_scene->items( rect );
61 QModelIndexList indexes;
62 for ( QGraphicsItem* item : items ) {
63 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item );
64 if ( i ) {
65 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked
66 indexes << index;
67 }
68 }
69 return indexes;
70 } else {
71 return QModelIndexList();
72 }
73}
74
75QModelIndexList ReverseMapper::indexesAt( const QPointF& point ) const
76{
77 populateScene();
78
79 if ( m_scene->sceneRect().contains( point ) ) {
80 const QList<QGraphicsItem *> items = m_scene->items( point );
81 QModelIndexList indexes;
82 for ( QGraphicsItem* item : items ) {
83 ChartGraphicsItem* i = qgraphicsitem_cast<ChartGraphicsItem*>( item );
84 if ( i ) {
85 QModelIndex index ( m_diagram->model()->index( i->row(), i->column(), m_diagram->rootIndex() ) ); // checked
86 if ( !indexes.contains(index) )
87 indexes << index;
88 }
89 }
90 return indexes;
91 } else {
92 return QModelIndexList();
93 }
94}
95
96QPolygonF ReverseMapper::polygon( int row, int column ) const
97{
98 if ( !m_diagram->model()->hasIndex( row, column, m_diagram->rootIndex() ) )
99 return QPolygon();
100 const QModelIndex index = m_diagram->model()->index( row, column, m_diagram->rootIndex() ); // checked
101 return m_polygons.value(index);
102}
103
104QRectF ReverseMapper::boundingRect( int row, int column ) const
105{
106 return polygon(row, column).boundingRect();
107}
108
109void ReverseMapper::addRect( int row, int column, const QRectF& rect )
110{
111 addPolygon( row, column, QPolygonF( rect ) );
112}
113
114void ReverseMapper::addPolygon( int row, int column, const QPolygonF& polygon )
115{
116 const auto index = m_diagram->model()->index( row, column, m_diagram->rootIndex() );
117 auto &value = m_polygons[index];
118 if (value.isEmpty()) {
119 value = polygon;
120 } else {
121 value = value.united(polygon);
122 }
123
124 m_sceneDirty = true;
125}
126
127void ReverseMapper::addCircle( int row, int column, const QPointF& location, const QSizeF& diameter )
128{
130 QPointF ossfet( -0.5*diameter.width(), -0.5*diameter.height() );
131 path.addEllipse( QRectF( location + ossfet, diameter ) );
132 addPolygon( row, column, QPolygonF( path.toFillPolygon() ) );
133}
134
135void ReverseMapper::addLine( int row, int column, const QPointF& from, const QPointF& to )
136{
137 // that's no line, dude... make a small circle around that point, instead
138 if ( from == to )
139 {
140 addCircle( row, column, from, QSizeF( 1.5, 1.5 ) );
141 return;
142 }
143 // lines do not make good polygons to click on. we calculate a 2
144 // pixel wide rectangle, where the original line is exactly
145 // centered in.
146 // make a 3 pixel wide polygon from the line:
148 if ( from.x() < to.x() ) {
149 left = from;
150 right = to;
151 } else {
152 right = from;
153 left = to;
154 }
155 const QPointF lineVector( right - left );
156 const qreal lineVectorLength = sqrt( lineVector.x() * lineVector.x() + lineVector.y() * lineVector.y() );
157 const QPointF lineVectorUnit( lineVector / lineVectorLength );
158 const QPointF normOfLineVectorUnit( -lineVectorUnit.y(), lineVectorUnit.x() );
159 // now the four polygon end points:
160 const QPointF one( left - lineVectorUnit + normOfLineVectorUnit );
161 const QPointF two( left - lineVectorUnit - normOfLineVectorUnit );
162 const QPointF three( right + lineVectorUnit - normOfLineVectorUnit );
163 const QPointF four( right + lineVectorUnit + normOfLineVectorUnit );
164 addPolygon( row, column, QPolygonF() << one << two << three << four );
165}
166
167void ReverseMapper::populateScene() const
168{
169 // we populate the scene lazily...
170
171 Q_ASSERT( m_diagram );
172
173 if (!m_sceneDirty) {
174 return;
175 }
176
177 if (!m_scene) {
178 m_scene = new QGraphicsScene;
179 }
180
181 QRectF boundingRect;
182 for (auto it = m_polygons.constBegin(), end = m_polygons.constEnd(); it != end; ++it) {
183 auto* item = new ChartGraphicsItem( it.key().row(), it.key().column() );
184 item->setPolygon( it.value() );
185 m_scene->addItem( item );
186 boundingRect |= it.value().boundingRect();
187 }
188
189 m_scene->setSceneRect(boundingRect);
190 m_sceneDirty = false;
191}
AbstractDiagram defines the interface for diagram classes.
Graphics item used inside of the ReverseMapper.
QString path(const QString &relativePath)
const QList< QKeySequence > & end()
bool hasIndex(int row, int column, const QModelIndex &parent) const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
QAbstractItemModel * model() const const
QModelIndex rootIndex() const const
void addItem(QGraphicsItem *item)
QList< QGraphicsItem * > items(Qt::SortOrder order) const const
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
T value(const Key &key) const const
qreal x() const const
QRectF boundingRect() const const
QPolygonF united(const QPolygonF &r) const const
qreal height() const const
qreal width() const const
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:24 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.