Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/chart2/source/view/main/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 26 kB image not shown  

Quelle  PlottingPositionHelper.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <PlottingPositionHelper.hxx>
#include <CommonConverters.hxx>
#include <Linear3DTransformation.hxx>
#include <VPolarTransformation.hxx>
#include <ShapeFactory.hxx>
#include <PropertyMapper.hxx>
#include <defines.hxx>

#include <com/sun/star/chart/TimeUnit.hpp>
#include <com/sun/star/chart2/AxisType.hpp>
#include <com/sun/star/drawing/Position3D.hpp>

#include <rtl/math.hxx>

namespace chart
{
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart2;

XTransformation2::~XTransformation2() {}

PlottingPositionHelper::PlottingPositionHelper()
        : m_bSwapXAndY( false )
        , m_nXResolution( 1000 )
        , m_nYResolution( 1000 )
        , m_nZResolution( 1000 )
        , m_bMaySkipPointsInRegressionCalculation( true )
        , m_bDateAxis(false)
        , m_nTimeResolution( css::chart::TimeUnit::DAY )
        , m_aNullDate(30,12,1899)
        , m_fScaledCategoryWidth(1.0)
        , m_bAllowShiftXAxisPos(false)
        , m_bAllowShiftZAxisPos(false)
{
}
PlottingPositionHelper::PlottingPositionHelper( const PlottingPositionHelper& rSource )
        : m_aScales( rSource.m_aScales )
        , m_aMatrixScreenToScene( rSource.m_aMatrixScreenToScene )
        // m_xTransformationLogicToScene( nullptr ) //should be recalculated
        , m_bSwapXAndY( rSource.m_bSwapXAndY )
        , m_nXResolution( rSource.m_nXResolution )
        , m_nYResolution( rSource.m_nYResolution )
        , m_nZResolution( rSource.m_nZResolution )
        , m_bMaySkipPointsInRegressionCalculation( rSource.m_bMaySkipPointsInRegressionCalculation )
        , m_bDateAxis( rSource.m_bDateAxis )
        , m_nTimeResolution( rSource.m_nTimeResolution )
        , m_aNullDate( rSource.m_aNullDate )
        , m_fScaledCategoryWidth( rSource.m_fScaledCategoryWidth )
        , m_bAllowShiftXAxisPos( rSource.m_bAllowShiftXAxisPos )
        , m_bAllowShiftZAxisPos( rSource.m_bAllowShiftZAxisPos )
{
}

PlottingPositionHelper::~PlottingPositionHelper()
{

}

std::unique_ptr<PlottingPositionHelper> PlottingPositionHelper::clone() const
{
    return std::make_unique<PlottingPositionHelper>(*this);
}

std::unique_ptr<PlottingPositionHelper> PlottingPositionHelper::createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale )
{
    auto pRet = clone();
    pRet->m_aScales[1]=rSecondaryScale;
    return pRet;
}

void PlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix)
{
    m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix);
    m_xTransformationLogicToScene = nullptr;
}

void PlottingPositionHelper::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis )
{
    m_aScales = std::move(rScales);
    m_bSwapXAndY = bSwapXAndYAxis;
    m_xTransformationLogicToScene = nullptr;
}

::chart::XTransformation2* PlottingPositionHelper::getTransformationScaledLogicToScene() const
{
    //this is a standard transformation for a cartesian coordinate system

    //transformation from 2) to 4) //@todo 2) and 4) need an ink to a document

    //we need to apply this transformation to each geometric object because of a bug/problem
    //of the old drawing layer (the UNO_NAME_3D_EXTRUDE_DEPTH is an integer value instead of a double )
    if(!m_xTransformationLogicToScene)
    {
        ::basegfx::B3DHomMatrix aMatrix;
        double MinX = getLogicMinX();
        double MinY = getLogicMinY();
        double MinZ = getLogicMinZ();
        double MaxX = getLogicMaxX();
        double MaxY = getLogicMaxY();
        double MaxZ = getLogicMaxZ();

        AxisOrientation nXAxisOrientation = m_aScales[0].Orientation;
        AxisOrientation nYAxisOrientation = m_aScales[1].Orientation;
        AxisOrientation nZAxisOrientation = m_aScales[2].Orientation;

        //apply scaling
        doUnshiftedLogicScaling( &MinX, &MinY, &MinZ );
        doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ);

        if(m_bSwapXAndY)
        {
            std::swap(MinX,MinY);
            std::swap(MaxX,MaxY);
            std::swap(nXAxisOrientation,nYAxisOrientation);
        }

        double fWidthX = MaxX - MinX;
        double fWidthY = MaxY - MinY;
        double fWidthZ = MaxZ - MinZ;

        double fScaleDirectionX = nXAxisOrientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0;
        double fScaleDirectionY = nYAxisOrientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0;
        double fScaleDirectionZ = nZAxisOrientation==AxisOrientation_MATHEMATICAL ? -1.0 : 1.0;

        double fScaleX = fScaleDirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthX;
        double fScaleY = fScaleDirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthY;
        double fScaleZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ;

        aMatrix.scale(fScaleX, fScaleY, fScaleZ);

        if( nXAxisOrientation==AxisOrientation_MATHEMATICAL )
            aMatrix.translate(-MinX*fScaleX, 0.0, 0.0);
        else
            aMatrix.translate(-MaxX*fScaleX, 0.0, 0.0);
        if( nYAxisOrientation==AxisOrientation_MATHEMATICAL )
            aMatrix.translate(0.0, -MinY*fScaleY, 0.0);
        else
            aMatrix.translate(0.0, -MaxY*fScaleY, 0.0);
        if( nZAxisOrientation==AxisOrientation_MATHEMATICAL )
            aMatrix.translate(0.0, 0.0, -MaxZ*fScaleZ);//z direction in draw is reverse mathematical direction
        else
            aMatrix.translate(0.0, 0.0, -MinZ*fScaleZ);

        aMatrix = m_aMatrixScreenToScene*aMatrix;

        m_xTransformationLogicToScene.reset(new Linear3DTransformation(B3DHomMatrixToHomogenMatrix( aMatrix ), m_bSwapXAndY));
    }
    return m_xTransformationLogicToScene.get();
}

drawing::Position3D PlottingPositionHelper::transformLogicToScene(
    double fX, double fY, double fZ, bool bClip ) const
{
    doLogicScaling( &fX,&fY,&fZ );
    if(bClip)
        clipScaledLogicValues( &fX,&fY,&fZ );

    return transformScaledLogicToScene( fX, fY, fZ, false );
}

drawing::Position3D PlottingPositionHelper::transformScaledLogicToScene(
    double fX, double fY, double fZ, bool bClip  ) const
{
    if( bClip )
        clipScaledLogicValues( &fX,&fY,&fZ );

    drawing::Position3D aPos( fX, fY, fZ);

    ::chart::XTransformation2* pTransformation =
        getTransformationScaledLogicToScene();
    return pTransformation->transform( aPos );
}

awt::Point PlottingPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D
                , const rtl::Reference<SvxShapeGroupAnyD>& xSceneTarget
                , sal_Int32 nDimensionCount )
{
    //@todo would like to have a cheaper method to do this transformation
    awt::Point aScreenPoint( static_cast<sal_Int32>(rScenePosition3D.PositionX), static_cast<sal_Int32>(rScenePosition3D.PositionY) );

    //transformation from scene to screen (only necessary for 3D):
    if(nDimensionCount==3)
    {
        //create 3D anchor shape
        tPropertyNameMap aDummyPropertyNameMap;
        rtl::Reference<Svx3DExtrudeObject> xShape3DAnchor = ShapeFactory::createCube( xSceneTarget
                , rScenePosition3D,drawing::Direction3D(1,1,1)
                , 0, nullptr, aDummyPropertyNameMap);
        //get 2D position from xShape3DAnchor
        aScreenPoint = xShape3DAnchor->getPosition();
        xSceneTarget->remove(xShape3DAnchor);
    }
    return aScreenPoint;
}

void PlottingPositionHelper::transformScaledLogicToScene( drawing::PolyPolygonShape3D& rPolygon ) const
{
    drawing::Position3D aScenePosition;
    auto SequenceXRange = asNonConstRange(rPolygon.SequenceX);
    auto SequenceYRange = asNonConstRange(rPolygon.SequenceY);
    auto SequenceZRange = asNonConstRange(rPolygon.SequenceZ);
    for( sal_Int32 nS = rPolygon.SequenceX.getLength(); nS--;)
    {
        auto xValuesRange = asNonConstRange(SequenceXRange[nS]);
        auto yValuesRange = asNonConstRange(SequenceYRange[nS]);
        auto zValuesRange = asNonConstRange(SequenceZRange[nS]);
        for( sal_Int32 nP = SequenceXRange[nS].getLength(); nP--; )
        {
            double& fX = xValuesRange[nP];
            double& fY = yValuesRange[nP];
            double& fZ = zValuesRange[nP];
            aScenePosition = transformScaledLogicToScene( fX,fY,fZ,true );
            fX = aScenePosition.PositionX;
            fY = aScenePosition.PositionY;
            fZ = aScenePosition.PositionZ;
        }
    }
}

void PlottingPositionHelper::transformScaledLogicToScene( std::vector<std::vector<css::drawing::Position3D>>& rPolygon ) const
{
    drawing::Position3D aScenePosition;
    for( sal_Int32 nS = static_cast<sal_Int32>(rPolygon.size()); nS--;)
    {
        auto valuesRange = rPolygon[nS].data();
        for( sal_Int32 nP = rPolygon[nS].size(); nP--; )
        {
            double& fX = valuesRange[nP].PositionX;
            double& fY = valuesRange[nP].PositionY;
            double& fZ = valuesRange[nP].PositionZ;
            aScenePosition = transformScaledLogicToScene( fX,fY,fZ,true );
            fX = aScenePosition.PositionX;
            fY = aScenePosition.PositionY;
            fZ = aScenePosition.PositionZ;
        }
    }
}

void PlottingPositionHelper::clipScaledLogicValues( double* pX, double* pY, double* pZ ) const
{
    //get logic clip values:
    double MinX = getLogicMinX();
    double MinY = getLogicMinY();
    double MinZ = getLogicMinZ();
    double MaxX = getLogicMaxX();
    double MaxY = getLogicMaxY();
    double MaxZ = getLogicMaxZ();

    //apply scaling
    doUnshiftedLogicScaling( &MinX, &MinY, &MinZ );
    doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ);

    if(pX)
    {
        if( *pX < MinX )
            *pX = MinX;
        else if( *pX > MaxX )
            *pX = MaxX;
    }
    if(pY)
    {
        if( *pY < MinY )
            *pY = MinY;
        else if( *pY > MaxY )
            *pY = MaxY;
    }
    if(pZ)
    {
        if( *pZ < MinZ )
            *pZ = MinZ;
        else if( *pZ > MaxZ )
            *pZ = MaxZ;
    }
}

basegfx::B2DRectangle PlottingPositionHelper::getScaledLogicClipDoubleRect() const
{
    //get logic clip values:
    double MinX = getLogicMinX();
    double MinY = getLogicMinY();
    double MinZ = getLogicMinZ();
    double MaxX = getLogicMaxX();
    double MaxY = getLogicMaxY();
    double MaxZ = getLogicMaxZ();

    //apply scaling
    doUnshiftedLogicScaling( &MinX, &MinY, &MinZ );
    doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ);

    basegfx::B2DRectangle aRet( MinX, MaxY, MaxX, MinY );
    return aRet;
}

drawing::Direction3D PlottingPositionHelper::getScaledLogicWidth() const
{
    drawing::Direction3D aRet;

    double MinX = getLogicMinX();
    double MinY = getLogicMinY();
    double MinZ = getLogicMinZ();
    double MaxX = getLogicMaxX();
    double MaxY = getLogicMaxY();
    double MaxZ = getLogicMaxZ();

    doLogicScaling( &MinX, &MinY, &MinZ );
    doLogicScaling( &MaxX, &MaxY, &MaxZ);

    aRet.DirectionX = MaxX - MinX;
    aRet.DirectionY = MaxY - MinY;
    aRet.DirectionZ = MaxZ - MinZ;
    return aRet;
}

PolarPlottingPositionHelper::PolarPlottingPositionHelper()
    : m_fRadiusOffset(0.0)
    , m_fAngleDegreeOffset(90.0)
{
    m_bMaySkipPointsInRegressionCalculation = false;
}

PolarPlottingPositionHelper::PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource )
    : PlottingPositionHelper(rSource)
    , m_fRadiusOffset( rSource.m_fRadiusOffset )
    , m_fAngleDegreeOffset( rSource.m_fAngleDegreeOffset )
    , m_aUnitCartesianToScene( rSource.m_aUnitCartesianToScene )
{
}

PolarPlottingPositionHelper::~PolarPlottingPositionHelper()
{
}

std::unique_ptr<PlottingPositionHelper> PolarPlottingPositionHelper::clone() const
{
    return std::make_unique<PolarPlottingPositionHelper>(*this);
}

void PolarPlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix)
{
    PlottingPositionHelper::setTransformationSceneToScreen( rMatrix);
    m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene );
}
void PolarPlottingPositionHelper::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis )
{
    PlottingPositionHelper::setScales( std::move(rScales), bSwapXAndYAxis );
    m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene );
}

::basegfx::B3DHomMatrix PolarPlottingPositionHelper::impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const
{
    ::basegfx::B3DHomMatrix aRet;

    if( m_aScales.empty() )
        return aRet;

    double fTranslate =1.0;
    double fScale     =FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0;

    double fTranslateLogicZ;
    double fScaleLogicZ;
    {
        double fScaleDirectionZ = m_aScales[2].Orientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0;
        double MinZ = getLogicMinZ();
        double MaxZ = getLogicMaxZ();
        doLogicScaling( nullptr, nullptr, &MinZ );
        doLogicScaling( nullptr, nullptr, &MaxZ );
        double fWidthZ = MaxZ - MinZ;

        if( m_aScales[2].Orientation==AxisOrientation_MATHEMATICAL )
            fTranslateLogicZ=MinZ;
        else
            fTranslateLogicZ=MaxZ;
        fScaleLogicZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ;
    }

    double fTranslateX = fTranslate;
    double fTranslateY = fTranslate;
    double fTranslateZ = fTranslateLogicZ;

    double fScaleX = fScale;
    double fScaleY = fScale;
    double fScaleZ = fScaleLogicZ;

    aRet.translate(fTranslateX, fTranslateY, fTranslateZ);//x first
    aRet.scale(fScaleX, fScaleY, fScaleZ);//x first

    aRet = rMatrixScreenToScene * aRet;
    return aRet;
}

::chart::XTransformation2* PolarPlottingPositionHelper::getTransformationScaledLogicToScene() const
{
    if( !m_xTransformationLogicToScene )
        m_xTransformationLogicToScene.reset(new VPolarTransformation(*this));
    return m_xTransformationLogicToScene.get();
}

double PolarPlottingPositionHelper::getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const
{
    const ExplicitScaleData& rAngleScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0];
    if( rAngleScale.Orientation != AxisOrientation_MATHEMATICAL )
        std::swap( fStartLogicValueOnAngleAxis, fEndLogicValueOnAngleAxis );

    double fStartAngleDegree = transformToAngleDegree( fStartLogicValueOnAngleAxis );
    double fEndAngleDegree   = transformToAngleDegree( fEndLogicValueOnAngleAxis );
    double fWidthAngleDegree = fEndAngleDegree - fStartAngleDegree;

    if( ::rtl::math::approxEqual( fStartAngleDegree, fEndAngleDegree )
        && !::rtl::math::approxEqual( fStartLogicValueOnAngleAxis, fEndLogicValueOnAngleAxis ) )
        fWidthAngleDegree = 360.0;

    // tdf#123504: both 0 and 360 are valid and different values here!
    while (fWidthAngleDegree < 0.0)
        fWidthAngleDegree += 360.0;
    while (fWidthAngleDegree > 360.0)
        fWidthAngleDegree -= 360.0;

    return fWidthAngleDegree;
}

//This method does a lot of computation for understanding which scale to
//utilize and if reverse orientation should be used. Indeed, for a pie or donut,
//the final result is as simple as multiplying by 360 and adding
//`m_fAngleDegreeOffset`.
double PolarPlottingPositionHelper::transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling ) const
{
    double fRet=0.0;

    double fAxisAngleScaleDirection = 1.0;
    {
        const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0];
        if(rScale.Orientation != AxisOrientation_MATHEMATICAL)
            fAxisAngleScaleDirection *= -1.0;
    }

    double MinAngleValue = 0.0;
    double MaxAngleValue = 0.0;
    {
        double MinX = getLogicMinX();
        double MinY = getLogicMinY();
        double MaxX = getLogicMaxX();
        double MaxY = getLogicMaxY();
        double MinZ = getLogicMinZ();
        double MaxZ = getLogicMaxZ();

        doLogicScaling( &MinX, &MinY, &MinZ );
        doLogicScaling( &MaxX, &MaxY, &MaxZ);

        MinAngleValue = m_bSwapXAndY ? MinY : MinX;
        MaxAngleValue = m_bSwapXAndY ? MaxY : MaxX;
    }

    double fScaledLogicAngleValue = 0.0;
    if(bDoScaling)
    {
        double fX = m_bSwapXAndY ? getLogicMaxX() : fLogicValueOnAngleAxis;
        double fY = m_bSwapXAndY ? fLogicValueOnAngleAxis : getLogicMaxY();
        double fZ = getLogicMaxZ();
        clipLogicValues( &fX, &fY, &fZ );
        doLogicScaling( &fX, &fY, &fZ );
        fScaledLogicAngleValue = m_bSwapXAndY ? fY : fX;
    }
    else
        fScaledLogicAngleValue = fLogicValueOnAngleAxis;

    fRet = m_fAngleDegreeOffset
                  + fAxisAngleScaleDirection*(fScaledLogicAngleValue-MinAngleValue)*360.0
                    /fabs(MaxAngleValue-MinAngleValue);
    // tdf#123504: both 0 and 360 are valid and different values here!
    while (fRet > 360.0)
        fRet -= 360.0;
    while (fRet < 0)
        fRet += 360.0;
    return fRet;
}

/**
 * Given a value in the radius axis scale range, it returns, in the simplest
 * case (that is when `m_fRadiusOffset` is zero), the normalized value; when
 * `m_fRadiusOffset` is not zero (e.g. as in the case of a donut), the interval
 * used for normalization is extended by `m_fRadiusOffset`: if the axis
 * orientation is not reversed the new interval becomes
 * [scale.Minimum - m_fRadiusOffset, scale.Maximum] else it becomes
 * [scale.Minimum, scale.Maximum + m_fRadiusOffset].
 * Pay attention here! For the latter case, since the axis orientation is
 * reversed, the normalization is reversed too. Indeed, we have
 * `transformToRadius(scale.Maximum + m_fRadiusOffset) = 0` and
 * `transformToRadius(scale.Minimum) = 1`.
 *
 * For a pie chart the radius axis scale range is initialized by the
 * `getMinimum` and `getMaximum` methods of the `PieChart` object (see notes
 * for `VCoordinateSystem::prepareAutomaticAxisScaling`).
 * So we have scale.Minimum = 0.5 (always constant!) and
 * scale.Maximum = 0.5 + number_of_rings + max_offset
 * (see notes for `PieChart::getMaxOffset`).
 * Hence we get the following general formulas for computing normalized inner
 * and outer radius:
 *
 *    1- transformToRadius(inner_radius) =
 *               (number_of_rings - (ring_index + 1) + m_fRadiusOffset)
 *                   / (number_of_rings + max_offset + m_fRadiusOffset)
 *
 *    2- transformToRadius(outer_radius) =
 *               (1 + number_of_rings - (ring_index + 1) + m_fRadiusOffset)
 *                   / (number_of_rings + max_offset + m_fRadiusOffset).
 *
 * Here you have to take into account that values for inner and outer radius
 * are swapped since the radius axis is reversed (See notes for
 * `PiePositionHelper::getInnerAndOuterRadius`). So indeed inner_radius is
 * the outer and outer_radius is the inner. Anyway still because of the reverse
 * orientation, the normalization performed by `transformToRadius` is reversed
 * too, as we have seen above. Hence `transformToRadius(inner_radius)` is
 * really the normalized inner radius and  `transformToRadius(outer_radius)` is
 * really the normalized outer radius.
 *
 * Some basic examples where we apply the above formulas:
 *    1- For a non-exploded pie chart we have:
 *         `transformToRadius(inner_radius) = 0`,
 *         `transformToRadius(outer_radius) = 1`.
 *    2- For a non-exploded donut with a single ring we have:
 *         `transformToRadius(inner_radius) =
 *                 m_fRadiusOffset/(1 + m_fRadiusOffset)`,
 *         `transformToRadius(outer_radius) =
 *                 (1 + m_fRadiusOffset)/(1 + m_fRadiusOffset) = 1`.
 *    3- For an exploded pie chart we have:
 *         `transformToRadius(inner_radius) = 0/(1 + max_offset) = 0`,
 *         `transformToRadius(outer_radius) = 1/(1 + max_offset)`.
 *
 *  The third example needs some remark. Both the logical inner and outer
 *  radius passed to `transformToRadius` are offset by `max_offset`.
 *  However the returned normalized values do not contain any (normalized)
 *  offset term at all, otherwise the returned values would be
 *  `max_offset/(1 + max_offset)` and `1`. Hence, for exploded pie/donut,
 *  `transformToRadius` returns the normalized value of radii without any
 *  offset term. These values are smaller than in the non-exploded case by an
 *  amount equals to the value of the normalized maximum offset
 *  (`max_offset/(1 + max_offset)` in the example above). That is due to the
 *  fact that the normalization keeps into account the space needed for the
 *  offset. This is the correct behavior, in fact the offset for the current
 *  slice could be different from the maximum offset.
 *  These remarks should clarify why the `PieChart::createDataPoint` and
 *  `PieChart::createTextLabelShape` methods add the normalized offset (for the
 *  current slice) to the normalized radii in order to achieve the correct
 *  placement of slice and text shapes.
 */

double PolarPlottingPositionHelper::transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling ) const
{
    double fNormalRadius = 0.0;
    {
        double fScaledLogicRadiusValue = 0.0;
        double fX = m_bSwapXAndY ? fLogicValueOnRadiusAxis: getLogicMaxX();
        double fY = m_bSwapXAndY ? getLogicMaxY() : fLogicValueOnRadiusAxis;
        if(bDoScaling)
            doLogicScaling( &fX, &fY, nullptr );

        fScaledLogicRadiusValue = m_bSwapXAndY ? fX : fY;

        bool bMinIsInnerRadius = true;
        const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1];
        if(rScale.Orientation != AxisOrientation_MATHEMATICAL)
            bMinIsInnerRadius = false;

        double fInnerScaledLogicRadius=0.0;
        double fOuterScaledLogicRadius=0.0;
        {
            double MinX = getLogicMinX();
            double MinY = getLogicMinY();
            doLogicScaling( &MinX, &MinY, nullptr );
            double MaxX = getLogicMaxX();
            double MaxY = getLogicMaxY();
            doLogicScaling( &MaxX, &MaxY, nullptr );

            double fMin = m_bSwapXAndY ? MinX : MinY;
            double fMax = m_bSwapXAndY ? MaxX : MaxY;

            fInnerScaledLogicRadius = bMinIsInnerRadius ? fMin : fMax;
            fOuterScaledLogicRadius = bMinIsInnerRadius ? fMax : fMin;
        }

        if( bMinIsInnerRadius )
            fInnerScaledLogicRadius -= fabs(m_fRadiusOffset);
        else
            fInnerScaledLogicRadius += fabs(m_fRadiusOffset);
        fNormalRadius = (fScaledLogicRadiusValue-fInnerScaledLogicRadius)/(fOuterScaledLogicRadius-fInnerScaledLogicRadius);
    }
    return fNormalRadius;
}

drawing::Position3D PolarPlottingPositionHelper::transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const
{
    if(bClip)
        clipLogicValues( &fX,&fY,&fZ );
    double fLogicValueOnAngleAxis  = m_bSwapXAndY ? fY : fX;
    double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY;
    return transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ );
}

drawing::Position3D PolarPlottingPositionHelper::transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const
{
    if(bClip)
        clipScaledLogicValues( &fX,&fY,&fZ );
    double fLogicValueOnAngleAxis  = m_bSwapXAndY ? fY : fX;
    double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY;
    return transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, false );
}
drawing::Position3D PolarPlottingPositionHelper::transformUnitCircleToScene(
        double fUnitAngleDegree, double fUnitRadius,
        double fLogicZ ,
        const ::basegfx::B3DVector& aOffset) const
{
    double fAnglePi = basegfx::deg2rad(fUnitAngleDegree);

    double fX=fUnitRadius*std::cos(fAnglePi);
    double fY=fUnitRadius*std::sin(fAnglePi);
    double fZ=fLogicZ;

    //!! applying matrix to vector does ignore translation, so it is important to use a B3DPoint here instead of B3DVector
    ::basegfx::B3DPoint aPoint(fX,fY,fZ);
    aPoint += aOffset;
    ::basegfx::B3DPoint aRet = m_aUnitCartesianToScene * aPoint;
    return B3DPointToPosition3D(aRet);
}

drawing::Position3D PolarPlottingPositionHelper::transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling ) const
{
    double fUnitAngleDegree = transformToAngleDegree(fLogicValueOnAngleAxis,bDoScaling);
    double fUnitRadius      = transformToRadius(fLogicValueOnRadiusAxis,bDoScaling);

    return transformUnitCircleToScene( fUnitAngleDegree, fUnitRadius, fLogicZ );
}

double PolarPlottingPositionHelper::getOuterLogicRadius() const
{
    const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1];
    if( rScale.Orientation==AxisOrientation_MATHEMATICAL )
        return rScale.Maximum;
    else
        return rScale.Minimum;
}

bool PlottingPositionHelper::isPercentY() const
{
    return m_aScales[1].AxisType==AxisType::PERCENT;
}

double PlottingPositionHelper::getBaseValueY() const
{
    return m_aScales[1].Origin;
}

void PlottingPositionHelper::setTimeResolution( tools::Long nTimeResolution, const Date& rNullDate )
{
    m_nTimeResolution = nTimeResolution;
    m_aNullDate = rNullDate;

    //adapt category width
    double fCategoryWidth = 1.0;
    if( !m_aScales.empty() )
    {
        if( m_aScales[0].AxisType == css::chart2::AxisType::DATE )
        {
            m_bDateAxis = true;
            if( nTimeResolution == css::chart::TimeUnit::YEAR )
            {
                const double fMonthCount = 12.0;//todo: this depends on the DateScaling and must be adjusted in case we use more generic calendars in future
                fCategoryWidth = fMonthCount;
            }
        }
    }
    setScaledCategoryWidth(fCategoryWidth);
}

void PlottingPositionHelper::setScaledCategoryWidth( double fScaledCategoryWidth )
{
    m_fScaledCategoryWidth = fScaledCategoryWidth;
}
void PlottingPositionHelper::AllowShiftXAxisPos( bool bAllowShift )
{
    m_bAllowShiftXAxisPos = bAllowShift;
}
void PlottingPositionHelper::AllowShiftZAxisPos( bool bAllowShift )
{
    m_bAllowShiftZAxisPos = bAllowShift;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.