tdf#50934: Implement connector lines for pie-of-pie

Change-Id: Ifca083aa07b28d5c604382decaefedfe653ff8ab
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160731
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index a946616..9b14945 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -928,20 +928,26 @@ void PieChart::createShapes()
            createOneBar(SubPieType::RIGHT, aParam, xSeriesTarget,
                    xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);

            // draw connecting lines
            //
            // Draw connecting lines
            //
            double xl0, xl1, yl0, yl1, x0, y0, x1, y1, y2, y3;

            if (m_aPosHelper.m_fAngleDegreeOffset < 90.0) {
            // Get coordinates of "corners" of left composite wedge
            sal_Int32 nEnd = pDataSrc->getNPoints(pSeries, SubPieType::LEFT);
            double compFrac = pDataSrc->getData(pSeries, nEnd - 1,
                    SubPieType::LEFT) / aParam.mfLogicYSum;
            if (compFrac < 0.5) {
                xl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
                    cos(m_aPosHelper.m_fAngleDegreeOffset * M_PI / 180) +
                    m_fLeftShift;
                    cos(compFrac * M_PI) + m_fLeftShift;
                yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
                    sin(m_aPosHelper.m_fAngleDegreeOffset * M_PI / 180);
                    sin(compFrac * M_PI);
            } else {
                xl0 = m_fLeftShift;
                yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale;
            }

            // Coordinates of bar top left corner
            xl1 = m_fBarLeft;
            yl1 = m_fFullBarHeight / 2;

@@ -974,12 +980,75 @@ void PieChart::createShapes()
            break;
        }
        case PieChartSubType_PIE:
        {
            pDataSrc = &ofPieSrc;
            createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
                    xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
            createOneRing(SubPieType::RIGHT, 0, aParam, xSeriesTarget,
                    xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);

            //
            // Draw connecting lines
            //
            double xl0, xl1, yl0, yl1, x0, y0, x1, y1, y2, y3;

            // Get coordinates of "corners" of left composite wedge
            sal_Int32 nEnd = pDataSrc->getNPoints(pSeries, SubPieType::LEFT);
            double compFrac = pDataSrc->getData(pSeries, nEnd - 1,
                    SubPieType::LEFT) / aParam.mfLogicYSum;
            if (compFrac < 0.5) {
                // Translated, per below
                xl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
                    cos(compFrac * M_PI) + m_fLeftShift - m_fRightShift;
                yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
                    sin(compFrac * M_PI);
            } else {
                // Translated, per below
                xl0 = m_fLeftShift - m_fRightShift;
                yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale;
            }

            // Compute tangent point on the right-hand circle of the line
            // through (xl0, yl0). If we translate things so the right-hand
            // circle is centered on the origin, then this point (x,y)
            // satisfies these two equations, where r is the radius of the
            // right-hand circle:
            // (1) x^2 + y^2 = r^2
            // (2) (y - yl0) / (x - xl0) = -x / y
            const double r = aParam.mfUnitCircleOuterRadius * m_fRightScale;

            xl1 = (r*r * xl0 + yl0 * r * sqrt(xl0*xl0 + yl0*yl0 - r*r)) /
                (xl0*xl0 + yl0*yl0);
            yl1 = sqrt(r*r - xl1*xl1);

            // Now translate back to the coordinates we use
            xl0 += m_fRightShift;
            xl1 += m_fRightShift;

            x0 = m_aPosHelper.transformUnitCircleToScene(0, xl0, 0).PositionX;
            y0 = m_aPosHelper.transformUnitCircleToScene(90, yl0, 0).PositionY;
            x1 = m_aPosHelper.transformUnitCircleToScene(0, xl1, 0).PositionX;
            y1 = m_aPosHelper.transformUnitCircleToScene(90, yl1, 0).PositionY;
            y2 = m_aPosHelper.transformUnitCircleToScene(90, -yl0, 0).PositionY;
            y3 = m_aPosHelper.transformUnitCircleToScene(90, -yl1, 0).PositionY;

            std::vector<std::vector<css::drawing::Position3D>> linePts;
            linePts.resize(2);
            linePts[0].push_back(css::drawing::Position3D(x0, y0, aParam.mfLogicZ));
            linePts[0].push_back(css::drawing::Position3D(x1, y1, aParam.mfLogicZ));
            linePts[1].push_back(css::drawing::Position3D(x0, y2, aParam.mfLogicZ));
            linePts[1].push_back(css::drawing::Position3D(x1, y3, aParam.mfLogicZ));

            VLineProperties aVLineProperties;   // default black

            //create line
            rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes =
                getSeriesGroupShape(pSeries, xSeriesTarget);
            rtl::Reference<SvxShape> xShape = ShapeFactory::createLine2D(
                    xSeriesGroupShape_Shapes, linePts, &aVLineProperties);

            break;
        }
        default:
            assert(false); // this shouldn't happen
        }
@@ -1104,9 +1173,9 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
                        bConcentricExplosion);

            // Handle coloring of the composite wedge
            sal_Int32 nEnd = pDataSrc->getNPoints(pSeries, eType);
            const sal_Int32 nPropIdx = (
                    eType == SubPieType::LEFT && nPointIndex == nEnd - 1 ?
                    eType == SubPieType::LEFT &&
                    nPointIndex == pDataSrc->getNPoints(pSeries, SubPieType::LEFT) - 1 ?
                    pSeries->getTotalPointCount() :
                    nPointIndex);
            ///point color: