diff options
35 files changed, 672 insertions, 234 deletions
diff --git a/examples/barchart/main.cpp b/examples/barchart/main.cpp index 673ed05e..c51aa12f 100644 --- a/examples/barchart/main.cpp +++ b/examples/barchart/main.cpp @@ -70,6 +70,9 @@ ChartDataGenerator::ChartDataGenerator(Q3DBars *barchart, QTableWidget *tableWid m_rowCount(50), m_tableWidget(tableWidget) { + m_chart->setRowAxis(new QCategoryAxis); + m_chart->setColumnAxis(new QCategoryAxis); + m_chart->setValueAxis(new QValueAxis); // Set up bar specifications; make the bars as wide as they are deep, // and add a small space between the bars m_chart->setBarSpecs(1.0, QSizeF(0.2, 0.2)); diff --git a/examples/qmlbarchart/qml/qmlbarchart/main.qml b/examples/qmlbarchart/qml/qmlbarchart/main.qml index 887cb3d7..01eafcad 100644 --- a/examples/qmlbarchart/qml/qmlbarchart/main.qml +++ b/examples/qmlbarchart/qml/qmlbarchart/main.qml @@ -101,12 +101,20 @@ Item { "July", "August", "September", "October", "November", "December"] } ValueAxis { - id: valueAxis + id: incomeAxis min: 0 max: 35 - labelFormat: "%.1f M\u20AC" - title: "Annual expenses" + labelFormat: "%.2f M\u20AC" + title: "Monthly income" } + ValueAxis { + id: expensesAxis + min: 0 + max: 35 + labelFormat: "-%.2f M\u20AC" + title: "Monthly expenses" + } + Bars3D { id: testchart width: dataView.width @@ -122,14 +130,14 @@ Item { barSpacing: Qt.size(0.5, 0.5) barSpacingRelative: false barType: Bars3D.BevelBars - axisX: rowAxis - axisY: valueAxis - axisZ: columnAxis + rowAxis: rowAxis + columnAxis: columnAxis + valueAxis: expensesAxis itemLabelFormat: "@valueTitle for @colLabel, @rowLabel: @valueLabel" onDataResolved: { // Can't select a bar until data has been resolved from model to proxy - selectedBarPos = Qt.point(0, 5) + //selectedBarPos = Qt.point(0, 5) } } @@ -204,11 +212,11 @@ Item { if (valueMapping.valueRole == "expenses") { valueMapping.valueRole = "income" mappingButtonText.text = "Show Expenses" - valueAxis.title = "Annual income" + testchart.valueAxis = incomeAxis } else { valueMapping.valueRole = "expenses" mappingButtonText.text = "Show Income" - valueAxis.title = "Annual expenses" + testchart.valueAxis = expensesAxis } } } diff --git a/examples/rainfall/rainfallchart.cpp b/examples/rainfall/rainfallchart.cpp index ce670546..5b0d5dd9 100644 --- a/examples/rainfall/rainfallchart.cpp +++ b/examples/rainfall/rainfallchart.cpp @@ -51,6 +51,9 @@ RainfallChart::RainfallChart(Q3DBars *rainfall) // Set axis labels and titles QStringList months; months << "January" << "February" << "March" << "April" << "May" << "June" << "July" << "August" << "September" << "October" << "November" << "December"; + m_chart->setRowAxis(new QCategoryAxis); + m_chart->setColumnAxis(new QCategoryAxis); + m_chart->setValueAxis(new QValueAxis); m_chart->rowAxis()->setTitle("Year"); m_chart->columnAxis()->setTitle("Month"); m_chart->valueAxis()->setTitle(QString("rainfall in city %1").arg(m_city - 1)); diff --git a/examples/scatterchart/scatterchart.cpp b/examples/scatterchart/scatterchart.cpp index 7af80b85..3379de50 100644 --- a/examples/scatterchart/scatterchart.cpp +++ b/examples/scatterchart/scatterchart.cpp @@ -38,6 +38,9 @@ ScatterDataModifier::ScatterDataModifier(Q3DScatter *scatter) m_chart->setTheme(QDataVis::ThemeBrownSand); m_chart->setShadowQuality(QDataVis::ShadowHigh); m_chart->setCameraPreset(QDataVis::PresetFront); + m_chart->setAxisX(new QValueAxis); + m_chart->setAxisY(new QValueAxis); + m_chart->setAxisZ(new QValueAxis); QScatterDataProxy *proxy = new QScatterDataProxy; proxy->setItemLabelFormat("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"); @@ -59,12 +62,12 @@ void ScatterDataModifier::start() void ScatterDataModifier::addData() { // Add labels - m_chart->valueAxisX()->setTitle("X"); - m_chart->valueAxisY()->setTitle("Y"); - m_chart->valueAxisZ()->setTitle("Z"); - m_chart->valueAxisX()->setRange(-50.0, 50.0); - m_chart->valueAxisY()->setRange(-1.0, 1.0); - m_chart->valueAxisZ()->setRange(-50.0, 50.0); + m_chart->axisX()->setTitle("X"); + m_chart->axisY()->setTitle("Y"); + m_chart->axisZ()->setTitle("Z"); + m_chart->axisX()->setRange(-50.0, 50.0); + m_chart->axisY()->setRange(-1.0, 1.0); + m_chart->axisZ()->setRange(-50.0, 50.0); QScatterDataArray *dataArray = new QScatterDataArray; dataArray->resize(numberOfItems); diff --git a/examples/spectrum/spectrumapp/main.cpp b/examples/spectrum/spectrumapp/main.cpp index 0b17d064..e5994b20 100644 --- a/examples/spectrum/spectrumapp/main.cpp +++ b/examples/spectrum/spectrumapp/main.cpp @@ -71,6 +71,7 @@ MainApp::MainApp(Q3DBars *window) m_chart->setGridVisible(false); // Disable auto-scaling of height by defining explicit range // By setting count to 0 we avoid getting any grid + m_chart->setValueAxis(new QValueAxis); m_chart->valueAxis()->setSegmentCount(0); m_chart->valueAxis()->setRange(0.0, 1.0); // Disable shadows diff --git a/examples/surfacechart/chartmodifier.cpp b/examples/surfacechart/chartmodifier.cpp index 03f55dc9..0b4fb98d 100644 --- a/examples/surfacechart/chartmodifier.cpp +++ b/examples/surfacechart/chartmodifier.cpp @@ -17,7 +17,6 @@ ****************************************************************************/ #include "chartmodifier.h" -#include <QCategoryAxis> #include <QValueAxis> #include <qmath.h> @@ -31,6 +30,9 @@ ChartModifier::ChartModifier(Q3DSurface *chart) m_xCount(10), m_zCount(10) { + m_chart->setAxisX(new QValueAxis); + m_chart->setAxisY(new QValueAxis); + m_chart->setAxisZ(new QValueAxis); } ChartModifier::~ChartModifier() @@ -75,7 +77,7 @@ void ChartModifier::toggleSqrtSin(bool enable) m_chart->setSegmentCount(4, 0.5f); // Going to be obsolete m_chart->appendSeries(series, m_xCount, m_zCount); - m_chart->valueAxisZ()->setSegmentCount(7); + m_chart->axisZ()->setSegmentCount(7); qDebug() << "biggest = " << biggest << ", smallest = " << smallest; } else { @@ -98,10 +100,10 @@ void ChartModifier::togglePlane(bool enable) m_chart->setSegmentCount(4, 0.5f); m_chart->appendSeries(series, m_xCount, m_zCount); - m_chart->valueAxisX()->setSegmentCount(m_xCount - 1); - m_chart->valueAxisY()->setSegmentCount(4); - m_chart->valueAxisY()->setRange(0.0, 2.0); - m_chart->valueAxisZ()->setSegmentCount(m_zCount - 1); + m_chart->axisX()->setSegmentCount(m_xCount - 1); + m_chart->axisY()->setSegmentCount(4); + m_chart->axisY()->setRange(0.0, 2.0); + m_chart->axisZ()->setSegmentCount(m_zCount - 1); } } diff --git a/examples/widget/chart.cpp b/examples/widget/chart.cpp index 32985ada..957ec8e9 100644 --- a/examples/widget/chart.cpp +++ b/examples/widget/chart.cpp @@ -41,22 +41,75 @@ ChartModifier::ChartModifier(Q3DBars *barchart) m_subSegments(3), m_minval(-20.0), // TODO Barchart Y-axis currently only properly supports zero-centered ranges m_maxval(20.0), - m_selectedBarPos(-1, -1) + m_selectedBarPos(-1, -1), + m_autoAdjustingAxis(new QValueAxis), + m_fixedRangeAxis(new QValueAxis), + m_temperatureAxis(new QValueAxis), + m_yearAxis(new QCategoryAxis), + m_monthAxis(new QCategoryAxis), + m_genericRowAxis(new QCategoryAxis), + m_genericColumnAxis(new QCategoryAxis) { // Don't set any styles or specifications, start from defaults // Generate generic labels + QStringList genericRowLabels; + QStringList genericColumnLabels; for (int i = 0; i < 200; i++) { if (i % 5) - m_genericRowLabels << QString(); + genericRowLabels << QString(); else - m_genericRowLabels << QStringLiteral("Row %1").arg(i); + genericRowLabels << QStringLiteral("Row %1").arg(i); } for (int i = 0; i < 200; i++) { if (i % 5) - m_genericColumnLabels << QString(); + genericColumnLabels << QString(); else - m_genericColumnLabels << QStringLiteral("Column %1").arg(i); + genericColumnLabels << QStringLiteral("Column %1").arg(i); } + + m_months << "January" << "February" << "March" << "April" << "May" << "June" << "July" << "August" << "September" << "October" << "November" << "December"; + m_years << "2006" << "2007" << "2008" << "2009" << "2010" << "2011" << "2012"; + + QString labelFormat(QStringLiteral("%.3f")); + QString axisTitle("Generic Value"); + + m_autoAdjustingAxis->setLabelFormat(labelFormat); + m_autoAdjustingAxis->setTitle(axisTitle); + m_autoAdjustingAxis->setSegmentCount(m_segments * 2); + m_autoAdjustingAxis->setSubSegmentCount(1); + m_autoAdjustingAxis->setAutoAdjustRange(true); + + m_fixedRangeAxis->setLabelFormat(labelFormat); + m_fixedRangeAxis->setTitle(axisTitle); + m_fixedRangeAxis->setSegmentCount(m_segments); + m_fixedRangeAxis->setSubSegmentCount(m_subSegments); + m_fixedRangeAxis->setRange(0.0, 100.0); + + m_genericRowAxis->setTitle("Generic Row"); + m_genericRowAxis->setCategoryLabels(genericRowLabels); + + m_genericColumnAxis->setTitle("Generic Column"); + m_genericColumnAxis->setCategoryLabels(genericColumnLabels); + + m_temperatureAxis->setTitle("Average temperature"); + m_temperatureAxis->setSegmentCount(m_segments); + m_temperatureAxis->setSubSegmentCount(m_subSegments); + m_temperatureAxis->setRange(m_minval, m_maxval); + m_temperatureAxis->setLabelFormat(QString(QStringLiteral("%d ") + celsiusString)); + + m_yearAxis->setTitle("Year"); + m_yearAxis->setCategoryLabels(m_years); + + m_monthAxis->setTitle("Month"); + m_monthAxis->setCategoryLabels(m_months); + + m_chart->addAxis(m_autoAdjustingAxis); + m_chart->addAxis(m_fixedRangeAxis); + m_chart->addAxis(m_temperatureAxis); + m_chart->addAxis(m_yearAxis); + m_chart->addAxis(m_monthAxis); + m_chart->addAxis(m_genericRowAxis); + m_chart->addAxis(m_genericColumnAxis); } ChartModifier::~ChartModifier() @@ -66,8 +119,9 @@ ChartModifier::~ChartModifier() void ChartModifier::start() { - if (m_static) - addDataSet(); + m_chart->setFont(QFont("Times Roman", 20)); + + restart(false); } void ChartModifier::restart(bool dynamicData) @@ -75,31 +129,32 @@ void ChartModifier::restart(bool dynamicData) m_static = !dynamicData; if (m_static) { - start(); - // Set selection mode to zoom row - m_chart->setSelectionMode(QDataVis::ModeSliceRow); - m_chart->setFont(QFont("Times Roman", 20)); + resetData(); + + m_chart->setTitle(QStringLiteral("Average temperatures in Oulu, Finland (2006-2012)")); + + m_chart->setValueAxis(m_temperatureAxis); + m_chart->setRowAxis(m_yearAxis); + m_chart->setColumnAxis(m_monthAxis); + + m_chart->setDataWindow(m_years.size(), m_months.size()); + m_chart->setSelectionMode(QDataVis::ModeItem); + m_chart->dataProxy()->setItemLabelFormat(QStringLiteral("@valueTitle for @colLabel @rowLabel: @valueLabel")); + } else { + m_chart->dataProxy()->resetArray(0); - m_chart->dataProxy()->setItemLabelFormat(QStringLiteral("@valueTitle for (@rowIdx, @colIdx): @valueLabel")); - // Set up sample space + + m_chart->setTitle(QStringLiteral("Generic data")); + + m_chart->setValueAxis(m_fixedRangeAxis); + m_chart->setRowAxis(m_genericRowAxis); + m_chart->setColumnAxis(m_genericColumnAxis); + m_chart->setDataWindow(m_rowCount, m_columnCount); - // Set selection mode to full - m_chart->setSelectionMode(QDataVis::ModeSliceRow); - m_chart->valueAxis()->setSegmentCount(m_segments * 2); - m_chart->valueAxis()->setSubSegmentCount(1); - m_chart->valueAxis()->setAutoAdjustRange(true); - m_chart->valueAxis()->setLabelFormat(QString(QStringLiteral("%.3f"))); - - m_chart->rowAxis()->setTitle("Generic Row"); - m_chart->columnAxis()->setTitle("Generic Column"); - m_chart->valueAxis()->setTitle("Generic Value"); - - if (m_chart->rowAxis()->labels().size() < m_rowCount) - m_chart->rowAxis()->setCategoryLabels(m_genericRowLabels.mid(0, m_rowCount)); - - if (m_chart->columnAxis()->labels().size() < m_rowCount) - m_chart->columnAxis()->setCategoryLabels(m_genericColumnLabels.mid(0, m_columnCount)); + m_chart->setSelectionMode(QDataVis::ModeItem); + m_chart->dataProxy()->setItemLabelFormat(QStringLiteral("@valueTitle for (@rowIdx, @colIdx): @valueLabel")); + } } @@ -113,53 +168,49 @@ void ChartModifier::selectBar() m_chart->setSelectedBarPos(noSelection); } -void ChartModifier::addDataSet() +void ChartModifier::swapAxis() { - // Prepare data to be visualized - // Use QDataSet adder + static int counter = 0; + int state = ++counter % 3; - // Set window title - m_chart->setTitle(QStringLiteral("Average temperatures in Oulu, Finland (2006-2012)")); + if (state == 0) { + m_chart->setValueAxis(m_fixedRangeAxis); + qDebug() << "Fixed range axis"; + } else if (state == 1) { + m_chart->setValueAxis(m_autoAdjustingAxis); + qDebug() << "Automatic range axis"; + } else { + m_chart->setValueAxis(0); + qDebug() << "default axis"; + } +} - // Set up row and column names - QStringList months; - months << "January" << "February" << "March" << "April" << "May" << "June" << "July" << "August" << "September" << "October" << "November" << "December"; - QStringList years; - years << "2006" << "2007" << "2008" << "2009" << "2010" << "2011" << "2012"; +void ChartModifier::resetData() +{ // Set up data - float temp[7][12] = {{-6.7f, -11.7f, -9.7f, 3.3f, 9.2f, 14.0f, 16.3f, 17.8f, 10.2f, 2.1f, -2.6f, -0.3f}, // 2006 - {-6.8f, -13.3f, 0.2f, 1.5f, 7.9f, 13.4f, 16.1f, 15.5f, 8.2f, 5.4f, -2.6f, -0.8f}, // 2007 - {-4.2f, -4.0f, -4.6f, 1.9f, 7.3f, 12.5f, 15.0f, 12.8f, 7.6f, 5.1f, -0.9f, -1.3f}, // 2008 - {-7.8f, -8.8f, -4.2f, 0.7f, 9.3f, 13.2f, 15.8f, 15.5f, 11.2f, 0.6f, 0.7f, -8.4f}, // 2009 - {-14.4f, -12.1f, -7.0f, 2.3f, 11.0f, 12.6f, 18.8f, 13.8f, 9.4f, 3.9f, -5.6f, -13.0f}, // 2010 - {-9.0f, -15.2f, -3.8f, 2.6f, 8.3f, 15.9f, 18.6f, 14.9f, 11.1f, 5.3f, 1.8f, -0.2f}, // 2011 - {-8.7f, -11.3f, -2.3f, 0.4f, 7.5f, 12.2f, 16.4f, 14.1f, 9.2f, 3.1f, 0.3f, -12.1f}}; // 2012 + static const float temp[7][12] = { + {-6.7f, -11.7f, -9.7f, 3.3f, 9.2f, 14.0f, 16.3f, 17.8f, 10.2f, 2.1f, -2.6f, -0.3f}, // 2006 + {-6.8f, -13.3f, 0.2f, 1.5f, 7.9f, 13.4f, 16.1f, 15.5f, 8.2f, 5.4f, -2.6f, -0.8f}, // 2007 + {-4.2f, -4.0f, -4.6f, 1.9f, 7.3f, 12.5f, 15.0f, 12.8f, 7.6f, 5.1f, -0.9f, -1.3f}, // 2008 + {-7.8f, -8.8f, -4.2f, 0.7f, 9.3f, 13.2f, 15.8f, 15.5f, 11.2f, 0.6f, 0.7f, -8.4f}, // 2009 + {-14.4f, -12.1f, -7.0f, 2.3f, 11.0f, 12.6f, 18.8f, 13.8f, 9.4f, 3.9f, -5.6f, -13.0f}, // 2010 + {-9.0f, -15.2f, -3.8f, 2.6f, 8.3f, 15.9f, 18.6f, 14.9f, 11.1f, 5.3f, 1.8f, -0.2f}, // 2011 + {-8.7f, -11.3f, -2.3f, 0.4f, 7.5f, 12.2f, 16.4f, 14.1f, 9.2f, 3.1f, 0.3f, -12.1f} // 2012 + }; // Use default data proxy to feed data directly in expected format QBarDataProxy *proxy = m_chart->dataProxy(); - // Add labels - m_chart->rowAxis()->setTitle("Year"); - m_chart->columnAxis()->setTitle("Month"); - m_chart->valueAxis()->setTitle("Average temperature"); - m_chart->rowAxis()->setCategoryLabels(years); - m_chart->columnAxis()->setCategoryLabels(months); - m_chart->valueAxis()->setSegmentCount(m_segments); - m_chart->valueAxis()->setSubSegmentCount(m_subSegments); - m_chart->valueAxis()->setRange(m_minval, m_maxval); - m_chart->valueAxis()->setLabelFormat(QString(QStringLiteral("%d ") + celsiusString)); - m_chart->setSelectionMode(QDataVis::ModeSliceRow); - // Create data rows QBarDataArray *dataSet = new QBarDataArray; QBarDataRow *dataRow; - dataSet->reserve(years.size()); - for (int year = 0; year < years.size(); year++) { - dataRow = new QBarDataRow(months.size()); + dataSet->reserve(m_years.size()); + for (int year = 0; year < m_years.size(); year++) { + dataRow = new QBarDataRow(m_months.size()); // Create data items - for (int month = 0; month < months.size(); month++) { + for (int month = 0; month < m_months.size(); month++) { // Add data to rows (*dataRow)[month].setValue(temp[year][month]); } @@ -167,12 +218,9 @@ void ChartModifier::addDataSet() dataSet->append(dataRow); } - // Set up sample space based on prepared data - m_chart->setDataWindow(years.size(), months.size()); // Add data to chart (chart assumes ownership) proxy->resetArray(dataSet); - proxy->setItemLabelFormat(QStringLiteral("@valueTitle for @colLabel @rowLabel: @valueLabel")); } void ChartModifier::addRow() @@ -446,14 +494,10 @@ void ChartModifier::setSampleCountX(int samples) { m_columnCount = samples; m_chart->setDataWindow(m_rowCount, m_columnCount); - if (m_chart->columnAxis()->labels().size() < m_columnCount) - m_chart->columnAxis()->setCategoryLabels(m_genericColumnLabels.mid(0, m_columnCount)); } void ChartModifier::setSampleCountZ(int samples) { m_rowCount = samples; m_chart->setDataWindow(m_rowCount, m_columnCount); - if (m_chart->rowAxis()->labels().size() < m_rowCount) - m_chart->rowAxis()->setCategoryLabels(m_genericRowLabels.mid(0, m_rowCount)); } diff --git a/examples/widget/chart.h b/examples/widget/chart.h index c8b14246..36766336 100644 --- a/examples/widget/chart.h +++ b/examples/widget/chart.h @@ -24,6 +24,7 @@ #include <QFont> #include <QDebug> #include <QStringList> +#include <QPointer> using namespace QtDataVis3D; @@ -34,7 +35,7 @@ public: explicit ChartModifier(Q3DBars *barchart); ~ChartModifier(); - void addDataSet(); + void resetData(); void addRow(); void addRows(); void changeItem(); @@ -62,6 +63,7 @@ public: void start(); void restart(bool dynamicData); void selectBar(); + void swapAxis(); public slots: void changeShadowQuality(int quality); @@ -86,9 +88,16 @@ private: int m_subSegments; qreal m_minval; qreal m_maxval; - QStringList m_genericRowLabels; - QStringList m_genericColumnLabels; + QStringList m_months; + QStringList m_years; QPoint m_selectedBarPos; + QValueAxis *m_autoAdjustingAxis; + QValueAxis *m_fixedRangeAxis; + QValueAxis *m_temperatureAxis; + QCategoryAxis *m_yearAxis; + QCategoryAxis *m_monthAxis; + QCategoryAxis *m_genericRowAxis; + QCategoryAxis *m_genericColumnAxis; }; #endif diff --git a/examples/widget/main.cpp b/examples/widget/main.cpp index 3c0e44cf..84e1565e 100644 --- a/examples/widget/main.cpp +++ b/examples/widget/main.cpp @@ -98,6 +98,10 @@ int main(int argc, char **argv) QPushButton *setSelectedBarButton = new QPushButton(widget); setSelectedBarButton->setText(QStringLiteral("Select/deselect bar at (5,5)")); + QPushButton *swapAxisButton = new QPushButton(widget); + swapAxisButton->setText(QStringLiteral("Swap value axis")); + swapAxisButton->setEnabled(false); + QCheckBox *backgroundCheckBox = new QCheckBox(widget); backgroundCheckBox->setText(QStringLiteral("Show background")); backgroundCheckBox->setChecked(true); @@ -196,6 +200,7 @@ int main(int argc, char **argv) vLayout->addWidget(cameraButton, 0, Qt::AlignTop); vLayout->addWidget(selectionButton, 0, Qt::AlignTop); vLayout->addWidget(setSelectedBarButton, 0, Qt::AlignTop); + vLayout->addWidget(swapAxisButton, 0, Qt::AlignTop); vLayout->addWidget(backgroundCheckBox); vLayout->addWidget(gridCheckBox); vLayout->addWidget(new QLabel(QStringLiteral("Adjust shadow quality"))); @@ -254,6 +259,8 @@ int main(int argc, char **argv) &ChartModifier::changeSelectionMode); QObject::connect(setSelectedBarButton, &QPushButton::clicked, modifier, &ChartModifier::selectBar); + QObject::connect(swapAxisButton, &QPushButton::clicked, modifier, + &ChartModifier::swapAxis); QObject::connect(fontList, &QFontComboBox::currentFontChanged, modifier, &ChartModifier::changeFont); @@ -290,6 +297,8 @@ int main(int argc, char **argv) &QSlider::setEnabled); QObject::connect(staticCheckBox, &QCheckBox::stateChanged, sampleSliderZ, &QSlider::setEnabled); + QObject::connect(staticCheckBox, &QCheckBox::stateChanged, swapAxisButton, + &QSlider::setEnabled); QObject::connect(staticCheckBox, &QCheckBox::stateChanged, modifier, &ChartModifier::restart); modifier->start(); diff --git a/src/datavis3d/axis/qabstractaxis.cpp b/src/datavis3d/axis/qabstractaxis.cpp index 5129dfab..0b233903 100644 --- a/src/datavis3d/axis/qabstractaxis.cpp +++ b/src/datavis3d/axis/qabstractaxis.cpp @@ -124,7 +124,8 @@ QAbstractAxisPrivate::QAbstractAxisPrivate(QAbstractAxis *q, QAbstractAxis::Axis : QObject(0), q_ptr(q), m_orientation(QAbstractAxis::AxisOrientationNone), - m_type(type) + m_type(type), + m_isDefaultAxis(false) { } diff --git a/src/datavis3d/axis/qabstractaxis.h b/src/datavis3d/axis/qabstractaxis.h index aac2ee30..e2c127ad 100644 --- a/src/datavis3d/axis/qabstractaxis.h +++ b/src/datavis3d/axis/qabstractaxis.h @@ -80,6 +80,7 @@ private: Q_DISABLE_COPY(QAbstractAxis) friend class Abstract3DController; + friend class Bars3dController; }; QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/axis/qabstractaxis_p.h b/src/datavis3d/axis/qabstractaxis_p.h index 5b73ce17..6422868f 100644 --- a/src/datavis3d/axis/qabstractaxis_p.h +++ b/src/datavis3d/axis/qabstractaxis_p.h @@ -28,6 +28,7 @@ #include "datavis3dglobal_p.h" #include "qabstractaxis.h" +#include "abstract3dcontroller_p.h" #ifndef QABSTRACTAXIS_P_H #define QABSTRACTAXIS_P_H @@ -43,6 +44,9 @@ public: void setOrientation(QAbstractAxis::AxisOrientation orientation); + inline bool isDefaultAxis() { return m_isDefaultAxis; } + inline void setDefaultAxis(bool isDefault) { m_isDefaultAxis = isDefault; } + protected: virtual void updateLabels(); @@ -52,6 +56,7 @@ protected: QStringList m_labels; QAbstractAxis::AxisOrientation m_orientation; QAbstractAxis::AxisType m_type; + bool m_isDefaultAxis; friend class QAbstractAxis; friend class QValueAxis; diff --git a/src/datavis3d/axis/qcategoryaxis.h b/src/datavis3d/axis/qcategoryaxis.h index d162d34b..ab82e8d6 100644 --- a/src/datavis3d/axis/qcategoryaxis.h +++ b/src/datavis3d/axis/qcategoryaxis.h @@ -35,7 +35,7 @@ class QT_DATAVIS3D_EXPORT QCategoryAxis : public QAbstractAxis public: explicit QCategoryAxis(QObject *parent = 0); - ~QCategoryAxis(); + virtual ~QCategoryAxis(); QStringList categoryLabels() const; diff --git a/src/datavis3d/axis/qvalueaxis.cpp b/src/datavis3d/axis/qvalueaxis.cpp index 67bb9a38..9520cacd 100644 --- a/src/datavis3d/axis/qvalueaxis.cpp +++ b/src/datavis3d/axis/qvalueaxis.cpp @@ -219,7 +219,9 @@ QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q) m_max(10.0), m_segmentCount(5), m_subSegmentCount(1), - m_autoAdjust(true) + m_autoAdjust(true), + m_labelFormat(Utils::defaultLabelFormat()), + m_labelsDirty(true) { } @@ -307,9 +309,6 @@ void QValueAxisPrivate::updateLabels() qreal segmentStep = (m_max - m_min) / m_segmentCount; QString formatString(m_labelFormat); - if (formatString.isEmpty()) - formatString = Utils::defaultLabelFormat(); - Utils::ParamType paramType = Utils::findFormatParamType(formatString); QByteArray formatArray = formatString.toUtf8(); diff --git a/src/datavis3d/axis/qvalueaxis.h b/src/datavis3d/axis/qvalueaxis.h index 6bc84c15..1bffcb15 100644 --- a/src/datavis3d/axis/qvalueaxis.h +++ b/src/datavis3d/axis/qvalueaxis.h @@ -37,7 +37,7 @@ class QT_DATAVIS3D_EXPORT QValueAxis : public QAbstractAxis public: explicit QValueAxis(QObject *parent = 0); - ~QValueAxis(); + virtual ~QValueAxis(); qreal min() const; qreal max() const; diff --git a/src/datavis3d/data/barrenderitem_p.h b/src/datavis3d/data/barrenderitem_p.h index 0b7dc639..67e1e256 100644 --- a/src/datavis3d/data/barrenderitem_p.h +++ b/src/datavis3d/data/barrenderitem_p.h @@ -77,14 +77,12 @@ protected: void BarRenderItem::setValue(qreal value) { - if (m_value != value) { - m_value = value; - // Force reformatting on next access by setting label string to null string - if (!m_sliceLabel.isNull()) - setSliceLabel(QString()); - if (!m_selectionLabel.isNull()) - setSelectionLabel(QString()); - } + m_value = value; + // Force reformatting on next access by setting label string to null string + if (!m_sliceLabel.isNull()) + setSliceLabel(QString()); + if (!m_selectionLabel.isNull()) + setSelectionLabel(QString()); } typedef QVector<BarRenderItem> BarRenderItemRow; diff --git a/src/datavis3d/engine/abstract3dcontroller.cpp b/src/datavis3d/engine/abstract3dcontroller.cpp index de80bd41..06d81021 100644 --- a/src/datavis3d/engine/abstract3dcontroller.cpp +++ b/src/datavis3d/engine/abstract3dcontroller.cpp @@ -20,6 +20,7 @@ #include "camerahelper_p.h" #include "qabstractaxis_p.h" #include "qvalueaxis.h" +#include "qcategoryaxis.h" #include "abstract3drenderer_p.h" #if defined(Q_OS_ANDROID) @@ -63,9 +64,8 @@ Abstract3DController::Abstract3DController(QRect boundRect, QObject *parent) : Abstract3DController::~Abstract3DController() { delete m_cameraHelper; - delete m_axisX; - delete m_axisY; - delete m_axisZ; + + // Attached axes are children, so no need to explicitly delete them } void Abstract3DController::setRenderer(Abstract3DRenderer *renderer) @@ -383,6 +383,8 @@ void Abstract3DController::setAxisX(QAbstractAxis *axis) QAbstractAxis *Abstract3DController::axisX() { + if (m_axisX->d_ptr->isDefaultAxis()) + return 0; return m_axisX; } @@ -393,6 +395,8 @@ void Abstract3DController::setAxisY(QAbstractAxis *axis) QAbstractAxis *Abstract3DController::axisY() { + if (m_axisY->d_ptr->isDefaultAxis()) + return 0; return m_axisY; } @@ -403,9 +407,57 @@ void Abstract3DController::setAxisZ(QAbstractAxis *axis) QAbstractAxis *Abstract3DController::axisZ() { + if (m_axisZ->d_ptr->isDefaultAxis()) + return 0; return m_axisZ; } +void Abstract3DController::addAxis(QAbstractAxis *axis) +{ + Q_ASSERT(axis); + Abstract3DController *owner = qobject_cast<Abstract3DController *>(axis->parent()); + if (owner != this) { + Q_ASSERT_X(!owner, "addAxis", "Axis already attached to a graph."); + axis->setParent(this); + } + if (!m_axes.contains(axis)) + m_axes.append(axis); +} + +void Abstract3DController::releaseAxis(QAbstractAxis *axis) +{ + if (axis && m_axes.contains(axis)) { + // If the axis is in use, replace it with a temporary one + switch (axis->orientation()) { + case QAbstractAxis::AxisOrientationX: + setAxisX(0); + break; + case QAbstractAxis::AxisOrientationY: + setAxisY(0); + break; + case QAbstractAxis::AxisOrientationZ: + setAxisZ(0); + break; + default: + break; + } + + m_axes.removeAll(axis); + axis->setParent(0); + } +} + +QList<QAbstractAxis *> Abstract3DController::axes() const +{ + QList<QAbstractAxis *> retList; + foreach (QAbstractAxis *axis, m_axes) { + if (!axis->d_ptr->isDefaultAxis()) + retList.append(axis); + } + + return retList; +} + int Abstract3DController::zoomLevel() { return m_zoomLevel; @@ -658,25 +710,48 @@ void Abstract3DController::handleAxisLabelFormatChanged(const QString &format) void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) { - if (sender == m_axisX) + // Label format changing needs to dirty the data so that labels are reset. + if (sender == m_axisX) { + m_isDataDirty = true; m_changeTracker.axisXLabelFormatChanged = true; - else if (sender == m_axisY) + } else if (sender == m_axisY) { + m_isDataDirty = true; m_changeTracker.axisYLabelFormatChanged = true; - else if (sender == m_axisZ) + } else if (sender == m_axisZ) { + m_isDataDirty = true; m_changeTracker.axisZLabelFormatChanged = true; - else + } else { qWarning() << __FUNCTION__ << "invoked for invalid axis"; + } } void Abstract3DController::setAxisHelper(QAbstractAxis::AxisOrientation orientation, QAbstractAxis *axis, QAbstractAxis **axisPtr) { - Q_ASSERT(axis); + // Setting null axis indicates using default axis + if (axis == 0) + axis = createDefaultAxis(orientation); + + // If old axis is default axis, delete it + QAbstractAxis *oldAxis = *axisPtr; + if (oldAxis) { + if (oldAxis->d_ptr->isDefaultAxis()) { + m_axes.removeAll(oldAxis); + delete oldAxis; + oldAxis = 0; + } else { + // Disconnect the old axis from use + QObject::disconnect(oldAxis, 0, this, 0); + oldAxis->d_ptr->setOrientation(QAbstractAxis::AxisOrientationNone); + } + } - delete *axisPtr; + // Assume ownership + addAxis(axis); + + // Connect the new axis *axisPtr = axis; - axis->setParent(0); // Assume ownership axis->d_ptr->setOrientation(orientation); QObject::connect(axis, &QAbstractAxis::titleChanged, @@ -716,4 +791,37 @@ void Abstract3DController::setAxisHelper(QAbstractAxis::AxisOrientation orientat } } +QAbstractAxis *Abstract3DController::createDefaultAxis(QAbstractAxis::AxisOrientation orientation) +{ + Q_UNUSED(orientation) + + // The default default axis is a value axis. If the chart type has a different default axis + // for some orientation, this function needs to be overridden. + QAbstractAxis *defaultAxis = createDefaultValueAxis(); + return defaultAxis; +} + +QValueAxis *Abstract3DController::createDefaultValueAxis() +{ + // Default value axis has single segment, empty label format, and auto scaling + // TODO: Grid should be also hidden, but that is not currently controlled by axis + QValueAxis *defaultAxis = new QValueAxis; + defaultAxis->setSegmentCount(1); + defaultAxis->setSubSegmentCount(1); + defaultAxis->setAutoAdjustRange(true); + defaultAxis->setLabelFormat(QString()); + defaultAxis->d_ptr->setDefaultAxis(true); + + return defaultAxis; +} + +QCategoryAxis *Abstract3DController::createDefaultCategoryAxis() +{ + // Default category axis has no labels + // TODO: Grid should be also hidden, but that is not currently controlled by axis. + QCategoryAxis *defaultAxis = new QCategoryAxis; + defaultAxis->d_ptr->setDefaultAxis(true); + return defaultAxis; +} + QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/abstract3dcontroller_p.h b/src/datavis3d/engine/abstract3dcontroller_p.h index 4868e3eb..3123a5d7 100644 --- a/src/datavis3d/engine/abstract3dcontroller_p.h +++ b/src/datavis3d/engine/abstract3dcontroller_p.h @@ -156,9 +156,12 @@ protected: QAbstract3DInputHandler *m_inputHandler; CameraHelper *m_cameraHelper; int m_zoomLevel; + // Active axes QAbstractAxis *m_axisX; QAbstractAxis *m_axisY; QAbstractAxis *m_axisZ; + + QList<QAbstractAxis *> m_axes; // List of all added axes Abstract3DRenderer *m_renderer; bool m_isDataDirty; @@ -201,6 +204,9 @@ public: virtual QAbstractAxis *axisY(); virtual void setAxisZ(QAbstractAxis *axis); virtual QAbstractAxis *axisZ(); + virtual void addAxis(QAbstractAxis *axis); + virtual void releaseAxis(QAbstractAxis *axis); + virtual QList<QAbstractAxis *> axes() const; // Omits default axes virtual int zoomLevel(); virtual void setZoomLevel(int zoomLevel); @@ -283,6 +289,11 @@ signals: void gridEnabledChanged(bool enable); // TODO: Should be handled via axes? void meshFileNameChanged(QString fileName); +protected: + virtual QAbstractAxis *createDefaultAxis(QAbstractAxis::AxisOrientation orientation); + QValueAxis *createDefaultValueAxis(); + QCategoryAxis *createDefaultCategoryAxis(); + private: void setAxisHelper(QAbstractAxis::AxisOrientation orientation, QAbstractAxis *axis, QAbstractAxis **axisPtr); diff --git a/src/datavis3d/engine/abstract3drenderer.cpp b/src/datavis3d/engine/abstract3drenderer.cpp index 2b40955c..a1800ba8 100644 --- a/src/datavis3d/engine/abstract3drenderer.cpp +++ b/src/datavis3d/engine/abstract3drenderer.cpp @@ -111,8 +111,6 @@ void Abstract3DRenderer::render(CameraHelper *camera, const GLuint defaultFboHan QString Abstract3DRenderer::generateValueLabel(const QString &format, qreal value) { QString valueLabelFormat = format; - if (valueLabelFormat.isEmpty()) - valueLabelFormat = Utils::defaultLabelFormat(); Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat); QByteArray valueFormatArray = valueLabelFormat.toUtf8(); return Utils::formatLabel(valueFormatArray, valueParamType, value); diff --git a/src/datavis3d/engine/axisrendercache.cpp b/src/datavis3d/engine/axisrendercache.cpp index 4374d545..0ca92247 100644 --- a/src/datavis3d/engine/axisrendercache.cpp +++ b/src/datavis3d/engine/axisrendercache.cpp @@ -52,11 +52,21 @@ void AxisRenderCache::setType(QAbstractAxis::AxisType type) { m_type = type; - // If type is set, it means completely new axis instance, so clear all generated label items. + // If type is set, it means completely new axis instance, so clear all old data + m_labels.clear(); + m_title.clear(); + m_min = 0.0; + m_max = 10.0; + m_segmentCount = 5; + m_subSegmentCount = 1; + m_labelFormat.clear(); + m_titleItem.clear(); foreach (LabelItem *label, m_labelItems) delete label; m_labelItems.clear(); + m_segmentStep = 10.0f; + m_subSegmentStep = 10.0f; } void AxisRenderCache::setTitle(const QString &title) @@ -80,10 +90,10 @@ void AxisRenderCache::setLabels(const QStringList &labels) m_labelItems.reserve(newSize); - if (m_drawer) { - for (int i = 0; i < newSize; i++) { - if (i >= oldSize) - m_labelItems.append(new LabelItem); + for (int i = 0; i < newSize; i++) { + if (i >= oldSize) + m_labelItems.append(new LabelItem); + if (m_drawer) { if (labels.at(i).isEmpty()) m_labelItems[i]->clear(); else if (i >= oldSize || labels.at(i) != m_labels.at(i)) diff --git a/src/datavis3d/engine/bars3dcontroller.cpp b/src/datavis3d/engine/bars3dcontroller.cpp index 13dce382..36a00319 100644 --- a/src/datavis3d/engine/bars3dcontroller.cpp +++ b/src/datavis3d/engine/bars3dcontroller.cpp @@ -44,15 +44,17 @@ Bars3dController::Bars3dController(QRect boundRect) m_renderer(0), m_data(0) { - // Default axes - setAxisX(new QCategoryAxis()); - setAxisY(new QValueAxis()); - setAxisZ(new QCategoryAxis()); - // Default bar type; specific to bars setBarType(QDataVis::Bars, false); setDataProxy(new QBarDataProxy); + + // Setting a null axis creates a new default axis according to orientation and chart type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); } Bars3dController::~Bars3dController() @@ -502,4 +504,16 @@ void Bars3dController::adjustValueAxisRange() } } +QAbstractAxis *Bars3dController::createDefaultAxis(QAbstractAxis::AxisOrientation orientation) +{ + QAbstractAxis *defaultAxis = 0; + + if (orientation == QAbstractAxis::AxisOrientationY) + defaultAxis = createDefaultValueAxis(); + else + defaultAxis = createDefaultCategoryAxis(); + + return defaultAxis; +} + QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/bars3dcontroller_p.h b/src/datavis3d/engine/bars3dcontroller_p.h index f7016860..bdff63b3 100644 --- a/src/datavis3d/engine/bars3dcontroller_p.h +++ b/src/datavis3d/engine/bars3dcontroller_p.h @@ -152,6 +152,9 @@ signals: void barSpecsChanged(GLfloat thicknessRatio, QSizeF spacing, bool relative); void selectedBarPosChanged(QPoint position); +protected: + virtual QAbstractAxis *createDefaultAxis(QAbstractAxis::AxisOrientation orientation); + private: void adjustValueAxisRange(); diff --git a/src/datavis3d/engine/bars3drenderer.cpp b/src/datavis3d/engine/bars3drenderer.cpp index ce05b0b9..ce7dd0e4 100644 --- a/src/datavis3d/engine/bars3drenderer.cpp +++ b/src/datavis3d/engine/bars3drenderer.cpp @@ -1360,7 +1360,10 @@ void Bars3dRenderer::drawScene(CameraHelper *camera, labelText.replace(valueTitleTag, m_axisCacheY.title()); if (labelText.contains(valueLabelTag)) { - QString valueLabelText = generateValueLabel(m_axisCacheY.labelFormat(), selectedBar->value()); + QString labelFormat = m_axisCacheY.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, selectedBar->value()); labelText.replace(valueLabelTag, valueLabelText); } diff --git a/src/datavis3d/engine/drawer.cpp b/src/datavis3d/engine/drawer.cpp index d2e3ddaf..9ea958ba 100644 --- a/src/datavis3d/engine/drawer.cpp +++ b/src/datavis3d/engine/drawer.cpp @@ -321,18 +321,20 @@ void Drawer::generateLabelItem(LabelItem &item, const QString &text) item.clear(); - // Create labels - // Print label into a QImage using QPainter - QImage label = Utils::printTextToImage(m_font, - text, - m_theme.m_textBackgroundColor, - m_theme.m_textColor, - m_transparency); - - // Set label size - item.setSize(label.size()); - // Insert text texture into label (also deletes the old texture) - item.setTextureId(m_textureHelper->create2DTexture(label, true, true)); + if (!text.isEmpty()) { + // Create labels + // Print label into a QImage using QPainter + QImage label = Utils::printTextToImage(m_font, + text, + m_theme.m_textBackgroundColor, + m_theme.m_textColor, + m_transparency); + + // Set label size + item.setSize(label.size()); + // Insert text texture into label (also deletes the old texture) + item.setTextureId(m_textureHelper->create2DTexture(label, true, true)); + } } QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/q3dbars.cpp b/src/datavis3d/engine/q3dbars.cpp index cf196ac8..5c2cf0c8 100644 --- a/src/datavis3d/engine/q3dbars.cpp +++ b/src/datavis3d/engine/q3dbars.cpp @@ -20,6 +20,7 @@ #include "q3dbars_p.h" #include "bars3dcontroller_p.h" #include "qvalueaxis.h" +#include "qcategoryaxis.h" #include <QMouseEvent> @@ -394,7 +395,7 @@ QPoint Q3DBars::selectedBarPos() const */ void Q3DBars::setShadowQuality(QDataVis::ShadowQuality quality) { - return d_ptr->m_shared->setShadowQuality(quality); + d_ptr->m_shared->setShadowQuality(quality); } QDataVis::ShadowQuality Q3DBars::shadowQuality() const @@ -403,33 +404,65 @@ QDataVis::ShadowQuality Q3DBars::shadowQuality() const } /*! - * \return category axis for rows. + * Sets a user-defined row \a axis. Implicitly calls addAxis() to transfer ownership of + * the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set row axis at all, a temporary + * default axis with no labels is used. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DBars::setRowAxis(QCategoryAxis *axis) +{ + d_ptr->m_shared->setAxisX(axis); +} + +/*! + * \return category axis for rows. Returns null pointer if default axis is in use. */ QCategoryAxis *Q3DBars::rowAxis() const { - return reinterpret_cast<QCategoryAxis *>(d_ptr->m_shared->axisX()); + return static_cast<QCategoryAxis *>(d_ptr->m_shared->axisX()); +} + +/*! + * Sets a user-defined column \a axis. Implicitly calls addAxis() to transfer ownership of + * the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set column axis at all, a temporary + * default axis with no labels is used. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DBars::setColumnAxis(QCategoryAxis *axis) +{ + d_ptr->m_shared->setAxisZ(axis); } /*! - * \return category axis for columns. + * \return category axis for columns. Returns null pointer if default axis is in use. */ QCategoryAxis *Q3DBars::columnAxis() const { - return reinterpret_cast<QCategoryAxis *>(d_ptr->m_shared->axisZ()); + return static_cast<QCategoryAxis *>(d_ptr->m_shared->axisZ()); } /*! - * Sets a user-defined value \a axis (Y-axis). Ownership of the axis is transferred to Q3DBars. + * Sets a user-defined value \a axis (the Y-axis). Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() */ void Q3DBars::setValueAxis(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisY(axis); + d_ptr->m_shared->setAxisY(axis); } /*! - * \return used value axis (Y-axis). + * \return used value axis (Y-axis). Returns null pointer if default axis is in use. */ QValueAxis *Q3DBars::valueAxis() const { @@ -437,6 +470,39 @@ QValueAxis *Q3DBars::valueAxis() const } /*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setValueAxis(), setRowAxis(), setColumnAxis() + */ +void Q3DBars::addAxis(QAbstractAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * If the released \a axis is in use, a temporary default axis will be set active. + * + * \sa addAxis(), setValueAxis(), setRowAxis(), setColumnAxis() + */ +void Q3DBars::releaseAxis(QAbstractAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<QAbstractAxis *> Q3DBars::axes() const +{ + return d_ptr->m_shared->axes(); +} + +/*! * Sets a user-defined data \a proxy. Ownership of the proxy is transferred to Q3DBars. */ void Q3DBars::setDataProxy(QBarDataProxy *proxy) diff --git a/src/datavis3d/engine/q3dbars.h b/src/datavis3d/engine/q3dbars.h index ff6a6fad..b3e695d3 100644 --- a/src/datavis3d/engine/q3dbars.h +++ b/src/datavis3d/engine/q3dbars.h @@ -26,6 +26,7 @@ QT_DATAVIS3D_BEGIN_NAMESPACE class Q3DBarsPrivate; +class QAbstractAxis; class QCategoryAxis; class QValueAxis; class QBarDataProxy; @@ -93,10 +94,15 @@ public: void setShadowQuality(QDataVis::ShadowQuality quality); QDataVis::ShadowQuality shadowQuality() const; + void setRowAxis(QCategoryAxis *axis); QCategoryAxis *rowAxis() const; + void setColumnAxis(QCategoryAxis *axis); QCategoryAxis *columnAxis() const; void setValueAxis(QValueAxis *axis); QValueAxis *valueAxis() const; + void addAxis(QAbstractAxis *axis); + void releaseAxis(QAbstractAxis *axis); + QList<QAbstractAxis *> axes() const; void setDataProxy(QBarDataProxy *proxy); QBarDataProxy *dataProxy(); diff --git a/src/datavis3d/engine/q3dscatter.cpp b/src/datavis3d/engine/q3dscatter.cpp index 7fc6f628..bd9a884f 100644 --- a/src/datavis3d/engine/q3dscatter.cpp +++ b/src/datavis3d/engine/q3dscatter.cpp @@ -365,60 +365,109 @@ QDataVis::ShadowQuality Q3DScatter::shadowQuality() const } /*! - * Sets a user-defined value \a axis (X-axis). Ownership of the axis is transferred to Q3DScatter. + * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() */ -void Q3DScatter::setValueAxisX(QValueAxis *axis) +void Q3DScatter::setAxisX(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisX(axis); + d_ptr->m_shared->setAxisX(axis); } /*! - * \return used value axis (X-axis). + * \return used X-axis. Returns null pointer if default axis is in use. */ -QValueAxis *Q3DScatter::valueAxisX() const +QValueAxis *Q3DScatter::axisX() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisX()); } /*! - * Sets a user-defined value \a axis (Y-axis). Ownership of the axis is transferred to Q3DScatter. + * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() */ -void Q3DScatter::setValueAxisY(QValueAxis *axis) +void Q3DScatter::setAxisY(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisY(axis); + d_ptr->m_shared->setAxisY(axis); } /*! - * \return used value axis (Y-axis). + * \return used Y-axis. Returns null pointer if default axis is in use. */ -QValueAxis *Q3DScatter::valueAxisY() const +QValueAxis *Q3DScatter::axisY() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisY()); } /*! - * Sets a user-defined value \a axis (Z-axis). Ownership of the axis is transferred to Q3DScatter. + * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() */ -void Q3DScatter::setValueAxisZ(QValueAxis *axis) +void Q3DScatter::setAxisZ(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisZ(axis); + d_ptr->m_shared->setAxisZ(axis); } /*! - * \return used value axis (Z-axis). + * \return used Z-axis. Returns null pointer if default axis is in use. */ -QValueAxis *Q3DScatter::valueAxisZ() const +QValueAxis *Q3DScatter::axisZ() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisZ()); } /*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DScatter::addAxis(QValueAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * + * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DScatter::releaseAxis(QValueAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<QValueAxis *> Q3DScatter::axes() const +{ + QList<QAbstractAxis *> abstractAxes = d_ptr->m_shared->axes(); + QList<QValueAxis *> retList; + foreach (QAbstractAxis *axis, abstractAxes) + retList.append(static_cast<QValueAxis *>(axis)); + + return retList; +} + +/*! * Sets a user-defined data \a proxy. Ownership of the proxy is transferred to Q3DScatter. */ void Q3DScatter::setDataProxy(QScatterDataProxy *proxy) diff --git a/src/datavis3d/engine/q3dscatter.h b/src/datavis3d/engine/q3dscatter.h index 26e3da08..a432b101 100644 --- a/src/datavis3d/engine/q3dscatter.h +++ b/src/datavis3d/engine/q3dscatter.h @@ -86,14 +86,15 @@ public: void setShadowQuality(QDataVis::ShadowQuality quality); QDataVis::ShadowQuality shadowQuality() const; - void setValueAxisX(QValueAxis *axis); - QValueAxis *valueAxisX() const; - - void setValueAxisY(QValueAxis *axis); - QValueAxis *valueAxisY() const; - - void setValueAxisZ(QValueAxis *axis); - QValueAxis *valueAxisZ() const; + void setAxisX(QValueAxis *axis); + QValueAxis *axisX() const; + void setAxisY(QValueAxis *axis); + QValueAxis *axisY() const; + void setAxisZ(QValueAxis *axis); + QValueAxis *axisZ() const; + void addAxis(QValueAxis *axis); + void releaseAxis(QValueAxis *axis); + QList<QValueAxis *> axes() const; void setDataProxy(QScatterDataProxy *proxy); QScatterDataProxy *dataProxy(); diff --git a/src/datavis3d/engine/q3dsurface.cpp b/src/datavis3d/engine/q3dsurface.cpp index d4b5f2f1..2201053d 100644 --- a/src/datavis3d/engine/q3dsurface.cpp +++ b/src/datavis3d/engine/q3dsurface.cpp @@ -154,42 +154,109 @@ void Q3DSurface::setSegmentCount(int segmentCount, qreal step, qreal minimum) d_ptr->m_shared->setSegmentCount(GLint(segmentCount), GLfloat(step), GLfloat(minimum)); } -void Q3DSurface::setValueAxisX(QValueAxis *axis) +/*! + * Sets a user-defined X-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisX(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisX(axis); + d_ptr->m_shared->setAxisX(axis); } -QValueAxis *Q3DSurface::valueAxisX() +/*! + * \return used X-axis. Returns null pointer if default axis is in use. + */ +QValueAxis *Q3DSurface::axisX() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisX()); } -void Q3DSurface::setValueAxisY(QValueAxis *axis) +/*! + * Sets a user-defined Y-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisY(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisY(axis); + d_ptr->m_shared->setAxisY(axis); } -QValueAxis *Q3DSurface::valueAxisY() +/*! + * \return used Y-axis. Returns null pointer if default axis is in use. + */ +QValueAxis *Q3DSurface::axisY() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisY()); } -void Q3DSurface::setValueAxisZ(QValueAxis *axis) +/*! + * Sets a user-defined Z-axis. Implicitly calls addAxis() to transfer ownership + * of the \a axis to this graph. + * + * If the \a axis is null, or if user doesn't explicitly set value axis at all, a temporary + * default axis with no labels and automatic range adjusting is used. + * + * \sa addAxis(), releaseAxis() + */ +void Q3DSurface::setAxisZ(QValueAxis *axis) { - Q_ASSERT(axis); - - return d_ptr->m_shared->setAxisZ(axis); + d_ptr->m_shared->setAxisZ(axis); } -QValueAxis *Q3DSurface::valueAxisZ() +/*! + * \return used Z-axis. Returns null pointer if default axis is in use. + */ +QValueAxis *Q3DSurface::axisZ() const { return static_cast<QValueAxis *>(d_ptr->m_shared->axisZ()); } +/*! + * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use, + * addAxis is simply used to give the ownership of the \a axis to the graph. + * The \a axis must not be null or added to another graph. + * + * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DSurface::addAxis(QValueAxis *axis) +{ + d_ptr->m_shared->addAxis(axis); +} + +/*! + * Releases the ownership of the \a axis back to the caller, if it is added to this graph. + * + * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ() + */ +void Q3DSurface::releaseAxis(QValueAxis *axis) +{ + d_ptr->m_shared->releaseAxis(axis); +} + +/*! + * \return list of all added axes. + * + * \sa addAxis() + */ +QList<QValueAxis *> Q3DSurface::axes() const +{ + QList<QAbstractAxis *> abstractAxes = d_ptr->m_shared->axes(); + QList<QValueAxis *> retList; + foreach (QAbstractAxis *axis, abstractAxes) + retList.append(static_cast<QValueAxis *>(axis)); + + return retList; +} + void Q3DSurface::setGradientColorAt(qreal pos, const QColor &color) { d_ptr->m_shared->setGradientColorAt(pos, color); diff --git a/src/datavis3d/engine/q3dsurface.h b/src/datavis3d/engine/q3dsurface.h index 357d65bd..c46a3710 100644 --- a/src/datavis3d/engine/q3dsurface.h +++ b/src/datavis3d/engine/q3dsurface.h @@ -58,14 +58,15 @@ public: void setGradientColorAt(qreal pos, const QColor &color); // Axes - void setValueAxisX(QValueAxis *axis); - QValueAxis *valueAxisX(); - - void setValueAxisY(QValueAxis *axis); - QValueAxis *valueAxisY(); - - void setValueAxisZ(QValueAxis *axis); - QValueAxis *valueAxisZ(); + void setAxisX(QValueAxis *axis); + QValueAxis *axisX() const; + void setAxisY(QValueAxis *axis); + QValueAxis *axisY() const; + void setAxisZ(QValueAxis *axis); + QValueAxis *axisZ() const; + void addAxis(QValueAxis *axis); + void releaseAxis(QValueAxis *axis); + QList<QValueAxis *> axes() const; // TODO: Remove when axes handling in use void setSegmentCount(int segmentCount, qreal step, qreal minimum = 0.0f); diff --git a/src/datavis3d/engine/scatter3dcontroller.cpp b/src/datavis3d/engine/scatter3dcontroller.cpp index 3b0a2c1f..c5ed1fed 100644 --- a/src/datavis3d/engine/scatter3dcontroller.cpp +++ b/src/datavis3d/engine/scatter3dcontroller.cpp @@ -38,15 +38,17 @@ Scatter3DController::Scatter3DController(QRect boundRect) m_data(0), m_selectedItemIndex(noSelectionIndex()) { - // Default axes - setAxisX(new QValueAxis()); - setAxisY(new QValueAxis()); - setAxisZ(new QValueAxis()); - // Default object type; specific to scatter setObjectType(QDataVis::Spheres, false); setDataProxy(new QScatterDataProxy); + + // Setting a null axis creates a new default axis according to orientation and chart type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); } Scatter3DController::~Scatter3DController() diff --git a/src/datavis3d/engine/scatter3drenderer.cpp b/src/datavis3d/engine/scatter3drenderer.cpp index 600726f1..bee1ee5c 100644 --- a/src/datavis3d/engine/scatter3drenderer.cpp +++ b/src/datavis3d/engine/scatter3drenderer.cpp @@ -1324,17 +1324,26 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, labelText.replace(zTitleTag, m_axisCacheZ.title()); if (labelText.contains(xLabelTag)) { - QString valueLabelText = generateValueLabel(m_axisCacheX.labelFormat(), + QString labelFormat = m_axisCacheX.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, selectedItem->position().x()); labelText.replace(xLabelTag, valueLabelText); } if (labelText.contains(yLabelTag)) { - QString valueLabelText = generateValueLabel(m_axisCacheY.labelFormat(), + QString labelFormat = m_axisCacheY.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, selectedItem->position().y()); labelText.replace(yLabelTag, valueLabelText); } if (labelText.contains(zLabelTag)) { - QString valueLabelText = generateValueLabel(m_axisCacheZ.labelFormat(), + QString labelFormat = m_axisCacheZ.labelFormat(); + if (labelFormat.isEmpty()) + labelFormat = Utils::defaultLabelFormat(); + QString valueLabelText = generateValueLabel(labelFormat, selectedItem->position().z()); labelText.replace(zLabelTag, valueLabelText); } diff --git a/src/datavis3d/engine/surface3dcontroller.cpp b/src/datavis3d/engine/surface3dcontroller.cpp index 89ec4fe6..dd21f388 100644 --- a/src/datavis3d/engine/surface3dcontroller.cpp +++ b/src/datavis3d/engine/surface3dcontroller.cpp @@ -38,10 +38,12 @@ Surface3dController::Surface3dController(QRect rect) m_mouseState(MouseNone), m_mousePos(QPoint(0, 0)) { - // Default axes - setAxisX(new QValueAxis()); // Or QCategoryAxis - setAxisY(new QValueAxis()); - setAxisZ(new QValueAxis()); // Or QCategoryAxis + // Setting a null axis creates a new default axis according to orientation and chart type. + // Note: These cannot be set in Abstract3DController constructor, as they will call virtual + // functions implemented by subclasses. + setAxisX(0); + setAxisY(0); + setAxisZ(0); } Surface3dController::~Surface3dController() diff --git a/src/datavis3dqml2/declarativebars.cpp b/src/datavis3dqml2/declarativebars.cpp index 6c63bda4..32ed5c57 100644 --- a/src/datavis3dqml2/declarativebars.cpp +++ b/src/datavis3dqml2/declarativebars.cpp @@ -125,32 +125,32 @@ void DeclarativeBars::setMapping(QItemModelBarDataMapping *mapping) static_cast<QItemModelBarDataProxy *>(m_shared->dataProxy())->setMapping(mapping); } -QCategoryAxis *DeclarativeBars::axisX() const +QCategoryAxis *DeclarativeBars::rowAxis() const { return static_cast<QCategoryAxis *>(m_shared->axisX()); } -void DeclarativeBars::setAxisX(QCategoryAxis *axis) +void DeclarativeBars::setRowAxis(QCategoryAxis *axis) { m_shared->setAxisX(axis); } -QValueAxis *DeclarativeBars::axisY() const +QValueAxis *DeclarativeBars::valueAxis() const { return static_cast<QValueAxis *>(m_shared->axisY()); } -void DeclarativeBars::setAxisY(QValueAxis *axis) +void DeclarativeBars::setValueAxis(QValueAxis *axis) { m_shared->setAxisY(axis); } -QCategoryAxis *DeclarativeBars::axisZ() const +QCategoryAxis *DeclarativeBars::columnAxis() const { return static_cast<QCategoryAxis *>(m_shared->axisZ()); } -void DeclarativeBars::setAxisZ(QCategoryAxis *axis) +void DeclarativeBars::setColumnAxis(QCategoryAxis *axis) { m_shared->setAxisZ(axis); } diff --git a/src/datavis3dqml2/declarativebars_p.h b/src/datavis3dqml2/declarativebars_p.h index 5a8fb165..6ada9a35 100644 --- a/src/datavis3dqml2/declarativebars_p.h +++ b/src/datavis3dqml2/declarativebars_p.h @@ -48,9 +48,9 @@ class DeclarativeBars : public QQuickItem Q_OBJECT Q_PROPERTY(QAbstractItemModel *data READ data WRITE setData) Q_PROPERTY(QItemModelBarDataMapping *mapping READ mapping WRITE setMapping) - Q_PROPERTY(QCategoryAxis *axisX READ axisX WRITE setAxisX) - Q_PROPERTY(QValueAxis *axisY READ axisY WRITE setAxisY) - Q_PROPERTY(QCategoryAxis *axisZ READ axisZ WRITE setAxisZ) + Q_PROPERTY(QCategoryAxis *rowAxis READ rowAxis WRITE setRowAxis) + Q_PROPERTY(QValueAxis *valueAxis READ valueAxis WRITE setValueAxis) + Q_PROPERTY(QCategoryAxis *columnAxis READ columnAxis WRITE setColumnAxis) Q_PROPERTY(QtDataVis3D::QDataVis::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode) Q_PROPERTY(QtDataVis3D::QDataVis::LabelTransparency labelTransparency READ labelTransparency WRITE setLabelTransparency) Q_PROPERTY(QtDataVis3D::QDataVis::ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality) @@ -103,18 +103,18 @@ public: QItemModelBarDataMapping *mapping() const; void setMapping(QItemModelBarDataMapping *mapping); - QCategoryAxis *axisX() const; - void setAxisX(QCategoryAxis *axis); - QValueAxis *axisY() const; - void setAxisY(QValueAxis *axis); - QCategoryAxis *axisZ() const; - void setAxisZ(QCategoryAxis *axis); + QCategoryAxis *rowAxis() const; + void setRowAxis(QCategoryAxis *axis); + QValueAxis *valueAxis() const; + void setValueAxis(QValueAxis *axis); + QCategoryAxis *columnAxis() const; + void setColumnAxis(QCategoryAxis *axis); - // Set bar thickness. Y -component sets the thickness of z -direction. + // Set bar thickness. void setBarThickness(qreal thicknessRatio); qreal barThickness(); - // Set spacing between bars. Y -component sets the spacing of z -direction. + // Set spacing between bars. Y-component sets the spacing of Z-direction. // If spacing is relative, 0.0f means side-to-side and 1.0f = one thickness in between. void setBarSpacing(QSizeF spacing); QSizeF barSpacing(); |