Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include <QtCharts/qcategoryaxis.h>
++ #include <QtCharts/qlogvalueaxis.h>
++ #include <QtCore/qmath.h>
++ #include <QtGui/qtextdocument.h>
++ #include <private/chartpresenter_p.h>
++ #include <private/polarchartaxisangular_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item,
++ bool intervalAxis)
++ : PolarChartAxis(axis, item, intervalAxis)
++ {
++ }
++
++ PolarChartAxisAngular::~PolarChartAxisAngular()
++ {
++ }
++
++ void PolarChartAxisAngular::updateGeometry()
++ {
++ PolarChartAxis::updateGeometry();
++
++ const QList<qreal> &layout = this->layout();
++ if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
++ return;
++
++ createAxisLabels(layout);
++ QStringList labelList = labels();
++ QPointF center = axisGeometry().center();
++ QList<QGraphicsItem *> arrowItemList = arrowItems();
++ QList<QGraphicsItem *> gridItemList = gridItems();
++ QList<QGraphicsItem *> labelItemList = labelItems();
++ QList<QGraphicsItem *> shadeItemList = shadeItems();
++ QGraphicsTextItem *title = titleItem();
++
++ QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
++ axisLine->setRect(axisGeometry());
++
++ qreal radius = axisGeometry().height() / 2.0;
++
++ QRectF previousLabelRect;
++ QRectF firstLabelRect;
++
++ qreal labelHeight = 0;
++
++ bool firstShade = true;
++ bool nextTickVisible = false;
++ if (layout.size())
++ nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
++
++ for (int i = 0; i < layout.size(); ++i) {
++ qreal angularCoordinate = layout.at(i);
++
++ QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
++ QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
++ QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
++ QGraphicsPathItem *shadeItem = 0;
++ if (i == 0)
++ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
++ else if (i % 2)
++ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
++
++ // Ignore ticks outside valid range
++ bool currentTickVisible = nextTickVisible;
++ if ((i == layout.size() - 1)
++ || layout.at(i + 1) < 0.0
++ || layout.at(i + 1) > 360.0) {
++ nextTickVisible = false;
++ } else {
++ nextTickVisible = true;
++ }
++
++ qreal labelCoordinate = angularCoordinate;
++ bool labelVisible = currentTickVisible;
++ if (intervalAxis()) {
++ qreal farEdge;
++ if (i == (layout.size() - 1))
++ farEdge = 360.0;
++ else
++ farEdge = qMin(qreal(360.0), layout.at(i + 1));
++
++ // Adjust the labelCoordinate to show it if next tick is visible
++ if (nextTickVisible)
++ labelCoordinate = qMax(qreal(0.0), labelCoordinate);
++
++ bool centeredLabel = true;
++ if (axis()->type() == QAbstractAxis::AxisTypeCategory) {
++ QCategoryAxis *categoryAxis = static_cast<QCategoryAxis *>(axis());
++ if (categoryAxis->labelsPosition() == QCategoryAxis::AxisLabelsPositionOnValue)
++ centeredLabel = false;
++ }
++ if (centeredLabel) {
++ labelCoordinate = (labelCoordinate + farEdge) / 2.0;
++ // Don't display label once the category gets too small near the axis
++ if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
++ labelVisible = false;
++ else
++ labelVisible = true;
++ } else {
++ labelVisible = nextTickVisible;
++ labelCoordinate = farEdge;
++ }
++ }
++
++ // Need this also in label calculations, so determine it first
++ QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
++ QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
++ tickLine.translate(center);
++
++ // Angular axis label
++ if (axis()->labelsVisible() && labelVisible) {
++ QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
++ labelList.at(i),
++ axis()->labelsAngle());
++ labelItem->setTextWidth(boundingRect.width());
++ labelItem->setHtml(labelList.at(i));
++ const QRectF &rect = labelItem->boundingRect();
++ QPointF labelCenter = rect.center();
++ labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
++ boundingRect.moveCenter(labelCenter);
++ QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
++
++ QPointF labelPoint;
++ if (intervalAxis()) {
++ QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
++ labelLine.translate(center);
++ labelPoint = labelLine.p2();
++ } else {
++ labelPoint = tickLine.p2();
++ }
++
++ QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
++ labelItem->setPos(labelRect.topLeft() + positionDiff);
++
++ // Store height for title calculations
++ qreal labelClearance = axisGeometry().top() - labelRect.top();
++ labelHeight = qMax(labelHeight, labelClearance);
++
++ // Label overlap detection
++ if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
++ labelVisible = false;
++ } else {
++ // Store labelRect for future comparison. Some area is deducted to make things look
++ // little nicer, as usually intersection happens at label corner with angular labels.
++ labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
++ if (firstLabelRect.isEmpty())
++ firstLabelRect = labelRect;
++
++ previousLabelRect = labelRect;
++ labelVisible = true;
++ }
++ }
++
++ labelItem->setVisible(labelVisible);
++ if (!currentTickVisible) {
++ gridLineItem->setVisible(false);
++ tickItem->setVisible(false);
++ if (shadeItem)
++ shadeItem->setVisible(false);
++ continue;
++ }
++
++ // Angular grid line
++ QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
++ gridLine.translate(center);
++ gridLineItem->setLine(gridLine);
++ gridLineItem->setVisible(true);
++
++ // Tick
++ tickItem->setLine(tickLine);
++ tickItem->setVisible(true);
++
++ // Shades
++ if (i % 2 || (i == 0 && !nextTickVisible)) {
++ QPainterPath path;
++ path.moveTo(center);
++ if (i == 0) {
++ // If first tick is also the last, we need to custom fill the first partial arc
++ // or it won't get filled.
++ path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
++ path.closeSubpath();
++ } else {
++ qreal nextCoordinate;
++ if (!nextTickVisible) // Last visible tick
++ nextCoordinate = 360.0;
++ else
++ nextCoordinate = layout.at(i + 1);
++ qreal arcSpan = angularCoordinate - nextCoordinate;
++ path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
++ path.closeSubpath();
++
++ // Add additional arc for first shade item if there is a partial arc to be filled
++ if (firstShade) {
++ QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
++ if (layout.at(i - 1) > 0.0) {
++ QPainterPath specialPath;
++ specialPath.moveTo(center);
++ specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
++ specialPath.closeSubpath();
++ specialShadeItem->setPath(specialPath);
++ specialShadeItem->setVisible(true);
++ } else {
++ specialShadeItem->setVisible(false);
++ }
++ }
++ }
++ shadeItem->setPath(path);
++ shadeItem->setVisible(true);
++ firstShade = false;
++ }
++ }
++
++ updateMinorTickGeometry();
++
++ // Title, centered above the chart
++ QString titleText = axis()->titleText();
++ if (!titleText.isEmpty() && axis()->isTitleVisible()) {
++ QRectF truncatedRect;
++ qreal availableTitleHeight = axisGeometry().height() - labelPadding() - titlePadding() * 2.0;
++ qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(),
++ QStringLiteral("...")).height();
++ availableTitleHeight -= minimumLabelHeight;
++ title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
++ axisGeometry().width(), availableTitleHeight,
++ truncatedRect));
++ title->setTextWidth(truncatedRect.width());
++
++ QRectF titleBoundingRect = title->boundingRect();
++ QPointF titleCenter = center - titleBoundingRect.center();
++ title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
++ }
++ }
++
++ Qt::Orientation PolarChartAxisAngular::orientation() const
++ {
++ return Qt::Horizontal;
++ }
++
++ void PolarChartAxisAngular::createItems(int count)
++ {
++ if (arrowItems().size() == 0) {
++ // angular axis line
++ QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
++ arrow->setPen(axis()->linePen());
++ arrowGroup()->addToGroup(arrow);
++ }
++
++ QGraphicsTextItem *title = titleItem();
++ title->setFont(axis()->titleFont());
++ title->setDefaultTextColor(axis()->titleBrush().color());
++ title->setHtml(axis()->titleText());
++
++ for (int i = 0; i < count; ++i) {
++ QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
++ QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
++ QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
++ label->document()->setDocumentMargin(ChartPresenter::textMargin());
++ arrow->setPen(axis()->linePen());
++ grid->setPen(axis()->gridLinePen());
++ label->setFont(axis()->labelsFont());
++ label->setDefaultTextColor(axis()->labelsBrush().color());
++ label->setRotation(axis()->labelsAngle());
++ arrowGroup()->addToGroup(arrow);
++ gridGroup()->addToGroup(grid);
++ labelGroup()->addToGroup(label);
++ if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
++ QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
++ shade->setPen(axis()->shadesPen());
++ shade->setBrush(axis()->shadesBrush());
++ shadeGroup()->addToGroup(shade);
++ }
++ }
++ }
++
++ void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
++ {
++ bool first = true;
++ const auto items = arrowItems();
++ for (QGraphicsItem *item : items) {
++ if (first) {
++ first = false;
++ // First arrow item is the outer circle of axis
++ static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
++ } else {
++ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
++ }
++ }
++ }
++
++ void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
++ {
++ const auto items = gridItems();
++ for (QGraphicsItem *item : items)
++ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
++ }
++
++ void PolarChartAxisAngular::handleMinorArrowPenChanged(const QPen &pen)
++ {
++ const auto items = minorArrowItems();
++ for (QGraphicsItem *item : items)
++ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
++ }
++
++ void PolarChartAxisAngular::handleMinorGridPenChanged(const QPen &pen)
++ {
++ const auto items = minorGridItems();
++ for (QGraphicsItem *item : items)
++ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
++ }
++
++ void PolarChartAxisAngular::handleGridLineColorChanged(const QColor &color)
++ {
++ const auto items = gridItems();
++ for (QGraphicsItem *item : items) {
++ QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem *>(item);
++ QPen pen = lineItem->pen();
++ pen.setColor(color);
++ lineItem->setPen(pen);
++ }
++ }
++
++ void PolarChartAxisAngular::handleMinorGridLineColorChanged(const QColor &color)
++ {
++ const auto items = minorGridItems();
++ for (QGraphicsItem *item : items) {
++ QGraphicsLineItem *lineItem = static_cast<QGraphicsLineItem *>(item);
++ QPen pen = lineItem->pen();
++ pen.setColor(color);
++ lineItem->setPen(pen);
++ }
++ }
++
++ QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
++ {
++ Q_UNUSED(which);
++ Q_UNUSED(constraint);
++ return QSizeF(-1, -1);
++ }
++
++ qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
++ {
++ qreal radius = maxSize.height() / 2.0;
++ if (maxSize.width() < maxSize.height())
++ radius = maxSize.width() / 2.0;
++
++ if (axis()->labelsVisible()) {
++ QList<qreal> layout = calculateLayout();
++ if (layout.isEmpty())
++ return radius;
++
++ createAxisLabels(layout);
++ QStringList labelList = labels();
++
++ QRectF maxRect;
++ maxRect.setSize(maxSize);
++ maxRect.moveCenter(QPointF(0.0, 0.0));
++
++ // This is a horrible way to find out the maximum radius for angular axis and its labels.
++ // It just increments the radius down until everyhing fits the constraint size.
++ // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
++ bool nextTickVisible = false;
++ for (int i = 0; i < layout.size(); ) {
++ if ((i == layout.size() - 1)
++ || layout.at(i + 1) < 0.0
++ || layout.at(i + 1) > 360.0) {
++ nextTickVisible = false;
++ } else {
++ nextTickVisible = true;
++ }
++
++ qreal labelCoordinate = layout.at(i);
++ qreal labelVisible;
++
++ if (intervalAxis()) {
++ qreal farEdge;
++ if (i == (layout.size() - 1))
++ farEdge = 360.0;
++ else
++ farEdge = qMin(qreal(360.0), layout.at(i + 1));
++
++ // Adjust the labelCoordinate to show it if next tick is visible
++ if (nextTickVisible)
++ labelCoordinate = qMax(qreal(0.0), labelCoordinate);
++
++ labelCoordinate = (labelCoordinate + farEdge) / 2.0;
++ }
++
++ if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
++ labelVisible = false;
++ else
++ labelVisible = true;
++
++ if (!labelVisible) {
++ i++;
++ continue;
++ }
++
++ QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
++ QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
++
++ boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
++ QRectF intersectRect = maxRect.intersected(boundingRect);
++ if (boundingRect.isEmpty() || intersectRect == boundingRect) {
++ i++;
++ } else {
++ qreal reduction(0.0);
++ // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
++ if (intersectRect.isEmpty()) {
++ reduction = qMin(boundingRect.height(), boundingRect.width());
++ } else {
++ // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
++ // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
++ reduction = qMax(boundingRect.height() - intersectRect.height(),
++ boundingRect.width() - intersectRect.width());
++ }
++ // Typically the approximated reduction is little low, so add one
++ radius -= (reduction + 1.0);
++
++ if (radius < 1.0) // safeguard
++ return 1.0;
++ }
++ }
++ }
++
++ if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
++ QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
++
++ radius -= titlePadding() + (titleRect.height() / 2.0);
++ if (radius < 1.0) // safeguard
++ return 1.0;
++ }
++
++ return radius;
++ }
++
++ QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
++ {
++ if (angularCoordinate == 0.0)
++ labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
++ else if (angularCoordinate < 90.0)
++ labelRect.moveBottomLeft(labelPoint);
++ else if (angularCoordinate == 90.0)
++ labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
++ else if (angularCoordinate < 180.0)
++ labelRect.moveTopLeft(labelPoint);
++ else if (angularCoordinate == 180.0)
++ labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
++ else if (angularCoordinate < 270.0)
++ labelRect.moveTopRight(labelPoint);
++ else if (angularCoordinate == 270.0)
++ labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
++ else if (angularCoordinate < 360.0)
++ labelRect.moveBottomRight(labelPoint);
++ else
++ labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
++ return labelRect;
++ }
++
++ void PolarChartAxisAngular::updateMinorTickGeometry()
++ {
++ if (!axis())
++ return;
++
++ QList<qreal> layout = ChartAxisElement::layout();
++ int minorTickCount = 0;
++ qreal tickAngle = 0.0;
++ QList<qreal> minorTickAngles;
++ switch (axis()->type()) {
++ case QAbstractAxis::AxisTypeValue: {
++ const QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
++
++ minorTickCount = valueAxis->minorTickCount();
++
++ if (valueAxis->tickCount() >= 2)
++ tickAngle = layout.at(1) - layout.at(0);
++
++ for (int i = 0; i < minorTickCount; ++i) {
++ const qreal ratio = (1.0 / qreal(minorTickCount + 1)) * qreal(i + 1);
++ minorTickAngles.append(tickAngle * ratio);
++ }
++ break;
++ }
++ case QAbstractAxis::AxisTypeLogValue: {
++ const QLogValueAxis *logValueAxis = qobject_cast<QLogValueAxis *>(axis());
++ const qreal base = logValueAxis->base();
++ const qreal logBase = qLn(base);
++
++ minorTickCount = logValueAxis->minorTickCount();
++ if (minorTickCount < 0)
++ minorTickCount = qMax(qFloor(base) - 2, 0);
++
++ // Two "virtual" ticks are required to make sure that all minor ticks
++ // are displayed properly (even for the partially visible segments of
++ // the chart).
++ if (layout.size() >= 2) {
++ // Calculate tickAngle as a difference between visible ticks
++ // whenever it is possible. Virtual ticks will not be correctly
++ // positioned when the layout is animating.
++ tickAngle = layout.at(1) - layout.at(0);
++ layout.prepend(layout.at(0) - tickAngle);
++ layout.append(layout.at(layout.size() - 1) + tickAngle);
++ } else {
++ const qreal logMax = qLn(logValueAxis->max());
++ const qreal logMin = qLn(logValueAxis->min());
++ const qreal logExtraMaxTick = qLn(qPow(base, qFloor(logMax / logBase) + 1.0));
++ const qreal logExtraMinTick = qLn(qPow(base, qCeil(logMin / logBase) - 1.0));
++ const qreal edge = qMin(logMin, logMax);
++ const qreal delta = 360.0 / qAbs(logMax - logMin);
++ const qreal extraMaxTick = edge + (logExtraMaxTick - edge) * delta;
++ const qreal extraMinTick = edge + (logExtraMinTick - edge) * delta;
++
++ // Calculate tickAngle using one (if layout.size() == 1) or two
++ // (if layout.size() == 0) "virtual" ticks. In both cases animation
++ // will not work as expected. This should be fixed later.
++ layout.prepend(extraMinTick);
++ layout.append(extraMaxTick);
++ tickAngle = layout.at(1) - layout.at(0);
++ }
++
++ const qreal minorTickStepValue = qFabs(base - 1.0) / qreal(minorTickCount + 1);
++ for (int i = 0; i < minorTickCount; ++i) {
++ const qreal x = minorTickStepValue * qreal(i + 1) + 1.0;
++ const qreal minorTickAngle = tickAngle * (qLn(x) / logBase);
++ minorTickAngles.append(minorTickAngle);
++ }
++ break;
++ }
++ default:
++ // minor ticks are not supported
++ break;
++ }
++
++ if (minorTickCount < 1 || tickAngle == 0.0 || minorTickAngles.size() != minorTickCount)
++ return;
++
++ const QPointF axisCenter = axisGeometry().center();
++ const qreal axisRadius = axisGeometry().height() / 2.0;
++
++ for (int i = 0; i < layout.size() - 1; ++i) {
++ for (int j = 0; j < minorTickCount; ++j) {
++ const int minorItemIndex = i * minorTickCount + j;
++ QGraphicsLineItem *minorGridLineItem =
++ static_cast<QGraphicsLineItem *>(minorGridItems().at(minorItemIndex));
++ QGraphicsLineItem *minorArrowLineItem =
++ static_cast<QGraphicsLineItem *>(minorArrowItems().at(minorItemIndex));
++ if (!minorGridLineItem || !minorArrowLineItem)
++ continue;
++
++ const qreal minorTickAngle = 90.0 - layout.at(i) - minorTickAngles.value(j, 0.0);
++
++ const QPointF minorArrowLinePt1 = QLineF::fromPolar(axisRadius - tickWidth() + 1,
++ minorTickAngle).p2();
++ const QPointF minorArrowLinePt2 = QLineF::fromPolar(axisRadius + tickWidth() - 1,
++ minorTickAngle).p2();
++
++ QLineF minorGridLine = QLineF::fromPolar(axisRadius, minorTickAngle);
++ minorGridLine.translate(axisCenter);
++ minorGridLineItem->setLine(minorGridLine);
++
++ QLineF minorArrowLine(minorArrowLinePt1, minorArrowLinePt2);
++ minorArrowLine.translate(axisCenter);
++ minorArrowLineItem->setLine(minorArrowLine);
++
++ // check if the minor grid line and the minor axis arrow should be shown
++ const bool minorGridLineVisible = (minorTickAngle >= -270.0 && minorTickAngle <= 90.0);
++ minorGridLineItem->setVisible(minorGridLineVisible);
++ minorArrowLineItem->setVisible(minorGridLineVisible);
++ }
++ }
++ }
++
++ void PolarChartAxisAngular::updateMinorTickItems()
++ {
++ int currentCount = minorArrowItems().size();
++ int expectedCount = 0;
++ if (axis()->type() == QAbstractAxis::AxisTypeValue) {
++ QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis());
++ expectedCount = valueAxis->minorTickCount() * (valueAxis->tickCount() - 1);
++ expectedCount = qMax(expectedCount, 0);
++ } else if (axis()->type() == QAbstractAxis::AxisTypeLogValue) {
++ QLogValueAxis *logValueAxis = qobject_cast<QLogValueAxis *>(axis());
++
++ int minorTickCount = logValueAxis->minorTickCount();
++ if (minorTickCount < 0)
++ minorTickCount = qMax(qFloor(logValueAxis->base()) - 2, 0);
++
++ expectedCount = minorTickCount * (logValueAxis->tickCount() + 1);
++ expectedCount = qMax(expectedCount, logValueAxis->minorTickCount());
++ } else {
++ // minor ticks are not supported
++ return;
++ }
++
++ int diff = expectedCount - currentCount;
++ if (diff > 0) {
++ for (int i = 0; i < diff; ++i) {
++ QGraphicsLineItem *minorGridLineItem = new QGraphicsLineItem(this);
++ minorGridLineItem->setPen(axis()->minorGridLinePen());
++ minorGridGroup()->addToGroup(minorGridLineItem);
++
++ QGraphicsLineItem *minorArrowLineItem = new QGraphicsLineItem(this);
++ minorArrowLineItem->setPen(axis()->linePen());
++ minorArrowGroup()->addToGroup(minorArrowLineItem);
++ }
++ } else {
++ QList<QGraphicsItem *> minorGridItemsList = minorGridItems();
++ QList<QGraphicsItem *> minorArrowItemsList = minorArrowItems();
++ for (int i = 0; i > diff; --i) {
++ if (!minorGridItemsList.isEmpty())
++ delete minorGridItemsList.takeLast();
++
++ if (!minorArrowItemsList.isEmpty())
++ delete minorArrowItemsList.takeLast();
++ }
++ }
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_polarchartaxisangular_p.cpp"