Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/svx/source/svdraw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 48 kB image not shown  

Quelle  svdomeas.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 <svx/dialmgr.hxx>
#include <svx/strings.hrc>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <editeng/editdata.hxx>
#include <editeng/editobj.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/flditem.hxx>
#include <editeng/measfld.hxx>
#include <editeng/outlobj.hxx>
#include <math.h>
#include <svl/style.hxx>

#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
#include <sdr/properties/measureproperties.hxx>
#include <svx/svddrag.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdomeas.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdoutl.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdview.hxx>
#include <svx/sxmbritm.hxx>
#include <svx/sxmlhitm.hxx>
#include <sxmsitm.hxx>
#include <sxmtaitm.hxx>
#include <svx/sxmtfitm.hxx>
#include <svx/sxmtpitm.hxx>
#include <svx/sxmtritm.hxx>
#include <svx/sxmuitm.hxx>
#include <svx/xlnedcit.hxx>
#include <svx/xlnedit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstcit.hxx>
#include <svx/xlnstit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xpoly.hxx>
#include <unotools/syslocale.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/ptrstyle.hxx>


SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}

OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
{
    OUString aStr;
    Fraction aMeasureScale(1, 1);
    bool bTextRota90(false);
    bool bShowUnit(false);
    FieldUnit eMeasureUnit(FieldUnit::NONE);
    FieldUnit eModUIUnit(FieldUnit::NONE);

    const SfxItemSet& rSet = GetMergedItemSet();
    bTextRota90 = rSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue();
    eMeasureUnit = rSet.Get(SDRATTR_MEASUREUNIT).GetValue();
    aMeasureScale = rSet.Get(SDRATTR_MEASURESCALE).GetValue();
    bShowUnit = rSet.Get(SDRATTR_MEASURESHOWUNIT).GetValue();
    sal_Int16 nNumDigits = rSet.Get(SDRATTR_MEASUREDECIMALPLACES).GetValue();

    switch(eMeasureFieldKind)
    {
        case SdrMeasureFieldKind::Value:
        {
            eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();

            if(eMeasureUnit == FieldUnit::NONE)
                eMeasureUnit = eModUIUnit;

            sal_Int32 nLen(GetLen(m_aPt2 - m_aPt1));
            Fraction aFact(1,1);

            if(eMeasureUnit != eModUIUnit)
            {
                // for the unit conversion
                aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
            }

            if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
            {
                aFact *= aMeasureScale;
            }

            if(aFact.GetNumerator() != aFact.GetDenominator())
            {
                // scale via BigInt, to avoid overruns
                nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
            }

            if(!aFact.IsValid())
            {
                aStr = "?";
            }
            else
            {
                aStr = getSdrModelFromSdrObject().GetMetricString(nLen, true, nNumDigits);
            }

            SvtSysLocale aSysLocale;
            const LocaleDataWrapper& rLocaleDataWrapper = aSysLocale.GetLocaleData();
            sal_Unicode cDec(rLocaleDataWrapper.getNumDecimalSep()[0]);
            sal_Unicode cDecAlt(rLocaleDataWrapper.getNumDecimalSepAlt().toChar());

            if(aStr.indexOf(cDec) != -1 || (cDecAlt && aStr.indexOf(cDecAlt) != -1))
            {
                sal_Int32 nLen2(aStr.getLength() - 1);

                while(aStr[nLen2] == '0')
                {
                    aStr = aStr.copy(0, nLen2);
                    nLen2--;
                }

                if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
                {
                    aStr = aStr.copy(0, nLen2);
                    nLen2--;
                }

                if(aStr.isEmpty())
                    aStr += "0";
            }

            break;
        }
        case SdrMeasureFieldKind::Unit:
        {
            if(bShowUnit)
            {
                eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();

                if(eMeasureUnit == FieldUnit::NONE)
                    eMeasureUnit = eModUIUnit;

                aStr = SdrModel::GetUnitString(eMeasureUnit);
            }

            break;
        }
        case SdrMeasureFieldKind::Rotate90Blanks:
        {
            if(bTextRota90)
            {
                aStr = " ";
            }

            break;
        }
    }
    return aStr;
}


// BaseProperties section

std::unique_ptr<sdr::properties::BaseProperties> SdrMeasureObj::CreateObjectSpecificProperties()
{
    return std::make_unique<sdr::properties::MeasureProperties>(*this);
}


// DrawContact section

std::unique_ptr<sdr::contact::ViewContact> SdrMeasureObj::CreateObjectSpecificViewContact()
{
    return std::make_unique<sdr::contact::ViewContactOfSdrMeasureObj>(*this);
}


SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel)
:   SdrTextObj(rSdrModel),
    m_bTextDirty(false)
{
    // #i25616#
    mbSupportTextIndentingOnLineWidthChange = false;
}

SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel, SdrMeasureObj const & rSource)
:   SdrTextObj(rSdrModel, rSource),
    m_bTextDirty(false)
{
    // #i25616#
    mbSupportTextIndentingOnLineWidthChange = false;

    m_aPt1 = rSource.m_aPt1;
    m_aPt2 = rSource.m_aPt2;
    m_bTextDirty = rSource.m_bTextDirty;
}

SdrMeasureObj::SdrMeasureObj(
    SdrModel& rSdrModel,
    const Point& rPt1,
    const Point& rPt2)
:   SdrTextObj(rSdrModel),
    m_aPt1(rPt1),
    m_aPt2(rPt2),
    m_bTextDirty(false)
{
    // #i25616#
    mbSupportTextIndentingOnLineWidthChange = false;
}

SdrMeasureObj::~SdrMeasureObj()
{
}

void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
    rInfo.bMoveAllowed      =true;
    rInfo.bResizeFreeAllowed=true;
    rInfo.bResizePropAllowed=true;
    rInfo.bRotateFreeAllowed=true;
    rInfo.bRotate90Allowed  =true;
    rInfo.bMirrorFreeAllowed=true;
    rInfo.bMirror45Allowed  =true;
    rInfo.bMirror90Allowed  =true;
    rInfo.bTransparenceAllowed = false;
    rInfo.bShearAllowed     =true;
    rInfo.bEdgeRadiusAllowed=false;
    rInfo.bNoOrthoDesired   =true;
    rInfo.bNoContortion     =false;
    rInfo.bCanConvToPath    =false;
    rInfo.bCanConvToPoly    =true;
    rInfo.bCanConvToPathLineToArea=false;
    rInfo.bCanConvToPolyLineToArea=false;
    rInfo.bCanConvToContour = LineGeometryUsageIsNecessary();
}

SdrObjKind SdrMeasureObj::GetObjIdentifier() const
{
    return SdrObjKind::Measure;
}

struct ImpMeasureRec : public SdrDragStatUserData
{
    Point                       aPt1;
    Point                       aPt2;
    css::drawing::MeasureTextHorzPos eWantTextHPos;
    css::drawing::MeasureTextVertPos eWantTextVPos;
    tools::Long                        nLineDist;
    tools::Long                        nHelplineOverhang;
    tools::Long                        nHelplineDist;
    tools::Long                        nHelpline1Len;
    tools::Long                        nHelpline2Len;
    bool                        bBelowRefEdge;
    bool                        bTextRota90;
    bool                        bTextUpsideDown;
    bool                        bTextAutoAngle;
    Degree100                   nTextAutoAngleView;
};

namespace {

struct ImpLineRec
{
    Point                       aP1;
    Point                       aP2;
};

}

struct ImpMeasurePoly
{
    ImpLineRec                  aMainline1; // those with the 1st arrowhead
    ImpLineRec                  aMainline2; // those with the 2nd arrowhead
    ImpLineRec                  aMainline3; // those in between
    ImpLineRec                  aHelpline1;
    ImpLineRec                  aHelpline2;
    Size                        aTextSize;
    tools::Long                        nLineLen;
    Degree100                   nLineAngle;
    Degree100                   nTextAngle;
    Degree100                   nHlpAngle;
    double                      nLineSin;
    double                      nLineCos;
    sal_uInt16                      nMainlineCnt;
    css::drawing::MeasureTextHorzPos eUsedTextHPos;
    css::drawing::MeasureTextVertPos eUsedTextVPos;
    tools::Long                        nLineWdt2;  // half the line width
    tools::Long                        nArrow1Len; // length of 1st arrowhead; for Center, use only half
    tools::Long                        nArrow2Len; // length of 2nd arrowhead; for Center, use only half
    tools::Long                        nArrow1Wdt; // width of 1st arrow
    tools::Long                        nArrow2Wdt; // width of 2nd arrow
    tools::Long                        nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
    bool                        bAutoUpsideDown; // UpsideDown via automation
    bool                        bBreakedLine;
};

void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
{
    rRec.aPt1 = m_aPt1;
    rRec.aPt2 = m_aPt2;

    const SfxItemSet& rSet = GetObjectItemSet();
    rRec.eWantTextHPos     =rSet.Get(SDRATTR_MEASURETEXTHPOS        ).GetValue();
    rRec.eWantTextVPos     =rSet.Get(SDRATTR_MEASURETEXTVPOS        ).GetValue();
    rRec.nLineDist         =rSet.Get(SDRATTR_MEASURELINEDIST        ).GetValue();
    rRec.nHelplineOverhang =rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue();
    rRec.nHelplineDist     =rSet.Get(SDRATTR_MEASUREHELPLINEDIST    ).GetValue();
    rRec.nHelpline1Len     =rSet.Get(SDRATTR_MEASUREHELPLINE1LEN    ).GetValue();
    rRec.nHelpline2Len     =rSet.Get(SDRATTR_MEASUREHELPLINE2LEN    ).GetValue();
    rRec.bBelowRefEdge     =rSet.Get(SDRATTR_MEASUREBELOWREFEDGE    ).GetValue();
    rRec.bTextRota90       =rSet.Get(SDRATTR_MEASURETEXTROTA90      ).GetValue();
    rRec.bTextUpsideDown   =static_cast<const SdrMeasureTextUpsideDownItem&   >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN  )).GetValue();
    rRec.bTextAutoAngle    =rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE    ).GetValue();
    rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
}

static tools::Long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, tools::Long nNewWidth, bool bCenter)
{
    const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
    const double fOldWidth(std::max(aPolygonRange.getWidth(), 1.0));
    const double fScale(static_cast<double>(nNewWidth) / fOldWidth);
    tools::Long nHeight(basegfx::fround<tools::Long>(aPolygonRange.getHeight() * fScale));

    if(bCenter)
    {
        nHeight /= 2;
    }

    return nHeight;
}

void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly&&nbsp;rPol) const
{
    Point aP1(rRec.aPt1);
    Point aP2(rRec.aPt2);
    Point aDelt(aP2); aDelt-=aP1;

    rPol.aTextSize=GetTextSize();
    rPol.nLineLen=GetLen(aDelt);

    rPol.nLineWdt2=0;
    tools::Long nArrow1Len=0; bool bArrow1Center=false;
    tools::Long nArrow2Len=0; bool bArrow2Center=false;
    tools::Long nArrow1Wdt=0;
    tools::Long nArrow2Wdt=0;
    rPol.nArrow1Wdt=0;
    rPol.nArrow2Wdt=0;
    tools::Long nArrowNeed=0;
    tools::Long nShortLen=0;
    bool bPfeileAussen = false;

    const SfxItemSet& rSet = GetObjectItemSet();
    sal_Int32 nLineWdt = rSet.Get(XATTR_LINEWIDTH).GetValue(); // line width
    rPol.nLineWdt2 = (nLineWdt + 1) / 2;

    nArrow1Wdt = rSet.Get(XATTR_LINESTARTWIDTH).GetValue();
    if(nArrow1Wdt < 0)
        nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative

    nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
    if(nArrow2Wdt < 0)
        nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relative

    basegfx::B2DPolyPolygon aPol1(rSet.Get(XATTR_LINESTART).GetLineStartValue());
    basegfx::B2DPolyPolygon aPol2(rSet.Get(XATTR_LINEEND).GetLineEndValue());
    bArrow1Center = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
    bArrow2Center = rSet.Get(XATTR_LINEENDCENTER).GetValue();
    nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
    nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;

    // nArrowLen is already halved at bCenter.
    // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
    nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
    if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
    nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;

    rPol.eUsedTextHPos=rRec.eWantTextHPos;
    rPol.eUsedTextVPos=rRec.eWantTextVPos;
    if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
        rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST;
    bool bBrkLine=false;
    if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
    {
        OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
        if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
        {
            bBrkLine=true// dashed line if there's only on paragraph.
        }
    }
    rPol.bBreakedLine=bBrkLine;
    if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside
        bool bOutside = false;
        tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
        if (nNeedSiz>rPol.nLineLen) bOutside = true// text doesn't fit in between
        if (bBrkLine) {
            if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true// text fits in between, if arrowheads are on the outside
        } else {
            tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
            if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true// text fits in between, if arrowheads are on the outside
        }
        rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
    }
    if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
    rPol.nArrow1Wdt=nArrow1Wdt;
    rPol.nArrow2Wdt=nArrow2Wdt;
    rPol.nShortLineLen=nShortLen;
    rPol.nArrow1Len=nArrow1Len;
    rPol.nArrow2Len=nArrow2Len;

    rPol.nLineAngle=GetAngle(aDelt);
    double a = toRadians(rPol.nLineAngle);
    double nLineSin=sin(a);
    double nLineCos=cos(a);
    rPol.nLineSin=nLineSin;
    rPol.nLineCos=nLineCos;

    rPol.nTextAngle=rPol.nLineAngle;
    if (rRec.bTextRota90) rPol.nTextAngle+=9000_deg100;

    rPol.bAutoUpsideDown=false;
    if (rRec.bTextAutoAngle) {
        Degree100 nTmpAngle=NormAngle36000(rPol.nTextAngle-rRec.nTextAutoAngleView);
        if (nTmpAngle>=18000_deg100) {
            rPol.nTextAngle+=18000_deg100;
            rPol.bAutoUpsideDown=true;
        }
    }

    if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000_deg100;
    rPol.nTextAngle=NormAngle36000(rPol.nTextAngle);
    rPol.nHlpAngle=rPol.nLineAngle+9000_deg100;
    if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000_deg100;
    rPol.nHlpAngle=NormAngle36000(rPol.nHlpAngle);
    double nHlpSin=nLineCos;
    double nHlpCos=-nLineSin;
    if (rRec.bBelowRefEdge) {
        nHlpSin=-nHlpSin;
        nHlpCos=-nHlpCos;
    }

    tools::Long nLineDist=rRec.nLineDist;
    tools::Long nOverhang=rRec.nHelplineOverhang;
    tools::Long nHelplineDist=rRec.nHelplineDist;

    tools::Long dx = basegfx::fround<tools::Long>(nLineDist * nHlpCos);
    tools::Long dy = basegfx::fround<tools::Long>(nLineDist * -nHlpSin);
    tools::Long dxh1a = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline1Len) * nHlpCos);
    tools::Long dyh1a = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline1Len) * -nHlpSin);
    tools::Long dxh1b = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline2Len) * nHlpCos);
    tools::Long dyh1b = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline2Len) * -nHlpSin);
    tools::Long dxh2 = basegfx::fround<tools::Long>((nLineDist + nOverhang) * nHlpCos);
    tools::Long dyh2 = basegfx::fround<tools::Long>((nLineDist + nOverhang) * -nHlpSin);

    // extension line 1
    rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
    rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);

    // extension line 2
    rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
    rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);

    // dimension line
    Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
    Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
    if (!bPfeileAussen) {
        rPol.aMainline1.aP1=aMainlinePt1;
        rPol.aMainline1.aP2=aMainlinePt2;
        rPol.aMainline2=rPol.aMainline1;
        rPol.aMainline3=rPol.aMainline1;
        rPol.nMainlineCnt=1;
        if (bBrkLine) {
            tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
            tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
            rPol.nMainlineCnt=2;
            rPol.aMainline1.aP2=aMainlinePt1;
            rPol.aMainline1.aP2.AdjustX(nHalfLen );
            RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
            rPol.aMainline2.aP1=aMainlinePt2;
            rPol.aMainline2.aP1.AdjustX( -nHalfLen );
            RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
        }
    } else {
        tools::Long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
        tools::Long nLen2=nShortLen;
        tools::Long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
        if (!bBrkLine) {
            if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
            if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
        }
        rPol.aMainline1.aP1=aMainlinePt1;
        rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.AdjustX( -nLen1 ); RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
        rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.AdjustX(nLen2 ); RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
        rPol.aMainline2.aP2=aMainlinePt2;
        rPol.aMainline3.aP1=aMainlinePt1;
        rPol.aMainline3.aP2=aMainlinePt2;
        rPol.nMainlineCnt=3;
        if (bBrkLine && rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_INSIDE) rPol.nMainlineCnt=2;
    }
}

basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
{
    basegfx::B2DPolyPolygon aRetval;
    basegfx::B2DPolygon aPartPolyA;
    aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
    aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
    aRetval.append(aPartPolyA);

    if(rPol.nMainlineCnt > 1)
    {
        aPartPolyA.clear();
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
        aRetval.append(aPartPolyA);
    }

    if(rPol.nMainlineCnt > 2)
    {
        aPartPolyA.clear();
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
        aRetval.append(aPartPolyA);
    }

    aPartPolyA.clear();
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
    aRetval.append(aPartPolyA);

    aPartPolyA.clear();
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
    aRetval.append(aPartPolyA);

    return aRetval;
}

bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
    bool bEdit,
    std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, std::optional<FontLineStyle>& rpFldLineStyle, OUString& rRet) const
{
    const SvxFieldData* pField=rField.GetField();
    const SdrMeasureField* pMeasureField=dynamic_cast<const SdrMeasureField*>( pField );
    if (pMeasureField!=nullptr) {
        rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
        if (rpFldColor && !bEdit)
        {
            rpFldColor.reset();
        }
        return true;
    } else {
        return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rpFldLineStyle,rRet);
    }
}

void SdrMeasureObj::UndirtyText() const
{
    if (!m_bTextDirty)
        return;

    SdrOutliner& rOutliner=ImpGetDrawOutliner();
    OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
    if(pOutlinerParaObject==nullptr)
    {
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD), ESelection(0,0));
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value), EE_FEATURE_FIELD),ESelection(0,1));
        rOutliner.QuickInsertText(u" "_ustr, ESelection(0,2));
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit), EE_FEATURE_FIELD),ESelection(0,3));
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD),ESelection(0,4));

        if(GetStyleSheet())
            rOutliner.SetStyleSheet(0, GetStyleSheet());

        rOutliner.SetParaAttribs(0, GetObjectItemSet());

        // cast to nonconst
        const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
    }
    else
    {
        rOutliner.SetText(*pOutlinerParaObject);
    }

    rOutliner.SetUpdateLayout(true);
    rOutliner.UpdateFields();
    Size aSiz(rOutliner.CalcTextSize());
    rOutliner.Clear();
    // cast to nonconst three times
    const_cast<SdrMeasureObj*>(this)->maTextSize = aSiz;
    const_cast<SdrMeasureObj*>(this)->mbTextSizeDirty = false;
    const_cast<SdrMeasureObj*>(this)->m_bTextDirty = false;
}

void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
{
    if (m_bTextDirty) UndirtyText();
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;
    ImpTakeAttr(aRec);
    ImpCalcGeometrics(aRec,aMPol);

    // determine TextSize including text frame margins
    Size aTextSize2(aMPol.aTextSize);
    if (aTextSize2.Width()<1) aTextSize2.setWidth(1 );
    if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
    aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
    aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );

    Point aPt1b(aMPol.aMainline1.aP1);
    tools::Long nLen=aMPol.nLineLen;
    tools::Long nLWdt=aMPol.nLineWdt2;
    tools::Long nArr1Len=aMPol.nArrow1Len;
    tools::Long nArr2Len=aMPol.nArrow2Len;
    if (aMPol.bBreakedLine) {
        // In the case of a dashed line and Outside, the text should be
        // placed next to the line at the arrowhead instead of directly
        // at the arrowhead.
        nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
        nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
    }

    Point aTextPos;
    bool bRota90=aRec.bTextRota90;
    bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
    bool bBelowRefEdge=aRec.bBelowRefEdge;
    css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
    css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos;
    if (!bRota90) {
        switch (eMH) {
            case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break;
            case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break;
            default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
        }
        switch (eMV) {
            case css::drawing::MeasureTextVertPos_CENTERED:
                aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break;
            case css::drawing::MeasureTextVertPos_WEST: {
                if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt );
                else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
            } break;
            default: {
                if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
                else aTextPos.setY(aPt1b.Y()+nLWdt );
            }
        }
        if (bUpsideDown) {
            aTextPos.AdjustX(aTextSize2.Width() );
            aTextPos.AdjustY(aTextSize2.Height() );
        }
    } else { // also if bTextRota90==TRUE
        switch (eMH) {
            case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break;
            case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break;
            default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
        }
        switch (eMV) {
            case css::drawing::MeasureTextVertPos_CENTERED:
                aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break;
            case css::drawing::MeasureTextVertPos_WEST: {
                if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
                else aTextPos.setY(aPt1b.Y()-nLWdt );
            } break;
            default: {
                if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
                else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
            }
        }
        if (bUpsideDown) {
            aTextPos.AdjustX(aTextSize2.Height() );
            aTextPos.AdjustY( -(aTextSize2.Width()) );
        }
    }
    if (aMPol.nTextAngle != maGeo.m_nRotationAngle) {
        const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle;
        const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
    }
    RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
    aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
    rRect=tools::Rectangle(aTextPos,aTextSize2);
    rRect.Normalize();
    const_cast<SdrMeasureObj*>(this)->setRectangle(rRect);

    if (aMPol.nTextAngle != maGeo.m_nRotationAngle) {
        const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle;
        const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
    }
}

rtl::Reference<SdrObject> SdrMeasureObj::CloneSdrObject(SdrModel& rTargetModel) const
{
    return new SdrMeasureObj(rTargetModel, *this);
}

OUString SdrMeasureObj::TakeObjNameSingul() const
{
    OUString sName(SvxResId(STR_ObjNameSingulMEASURE));

    OUString aName( GetName() );
    if (!aName.isEmpty())
        sName += " '" + aName + "'";

    return sName;
}

OUString SdrMeasureObj::TakeObjNamePlural() const
{
    return SvxResId(STR_ObjNamePluralMEASURE);
}

basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
{
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;
    ImpTakeAttr(aRec);
    ImpCalcGeometrics(aRec,aMPol);
    return ImpCalcXPoly(aMPol);
}

sal_uInt32 SdrMeasureObj::GetHdlCount() const
{
    return 6;
}

void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
{
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;
    ImpTakeAttr(aRec);
    aRec.nHelplineDist=0;
    ImpCalcGeometrics(aRec,aMPol);

    for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
    {
        Point aPt;
        switch (nHdlNum) {
            case 0: aPt=aMPol.aHelpline1.aP1; break;
            case 1: aPt=aMPol.aHelpline2.aP1; break;
            case 2: aPt=m_aPt1;       break;
            case 3: aPt=m_aPt2;       break;
            case 4: aPt=aMPol.aHelpline1.aP2; break;
            case 5: aPt=aMPol.aHelpline2.aP2; break;
        } // switch
        std::unique_ptr<SdrHdl> pHdl(new ImpMeasureHdl(aPt,SdrHdlKind::User));
        pHdl->SetObjHdlNum(nHdlNum);
        pHdl->SetRotationAngle(aMPol.nLineAngle);
        rHdlList.AddHdl(std::move(pHdl));
    }
}


bool SdrMeasureObj::hasSpecialDrag() const
{
    return true;
}

bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
{
    const SdrHdl* pHdl = rDrag.GetHdl();

    if(pHdl)
    {
        const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());

        if(nHdlNum != 2 && nHdlNum != 3)
        {
            rDrag.SetEndDragChangesAttributes(true);
        }

        return true;
    }

    return false;
}

bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
{
    ImpMeasureRec aMeasureRec;
    const SdrHdl* pHdl = rDrag.GetHdl();
    const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());

    ImpTakeAttr(aMeasureRec);
    ImpEvalDrag(aMeasureRec, rDrag);

    switch (nHdlNum)
    {
        case 2:
        {
            m_aPt1 = aMeasureRec.aPt1;
            SetTextDirty();
            break;
        }
        case 3:
        {
            m_aPt2 = aMeasureRec.aPt2;
            SetTextDirty();
            break;
        }
        default:
        {
            switch(nHdlNum)
            {
                case 0:
                case 1:
                {
                    ImpMeasureRec aOrigMeasureRec;
                    ImpTakeAttr(aOrigMeasureRec);

                    if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
                    {
                        SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
                    }

                    if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
                    {
                        SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
                    }

                    break;
                }

                case 4:
                case 5:
                {
                    ImpMeasureRec aOrigMeasureRec;
                    ImpTakeAttr(aOrigMeasureRec);

                    if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
                    {
                        SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
                    }

                    if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
                    {
                        SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
                    }
                }
            }
        }
    } // switch

    SetBoundAndSnapRectsDirty();
    SetChanged();

    return true;
}

OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
{
    return OUString();
}

void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDragconst
{
    Degree100 nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
    double a = toRadians(nLineAngle);
    double nSin=sin(a);
    double nCos=cos(a);

    const SdrHdl* pHdl=rDrag.GetHdl();
    sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
    bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
    bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
    bool bBelow=rRec.bBelowRefEdge;
    Point aPt(rDrag.GetNow());

    switch (nHdlNum) {
        case 0: {
            RotatePoint(aPt,m_aPt1,nSin,-nCos);
            rRec.nHelpline1Len=m_aPt1.Y()-aPt.Y();
            if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
            if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
        } break;
        case 1: {
            RotatePoint(aPt,m_aPt2,nSin,-nCos);
            rRec.nHelpline2Len=m_aPt2.Y()-aPt.Y();
            if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
            if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
        } break;
        case 2: case 3: {
            bool bAnf=nHdlNum==2;
            Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
            Point aMov(rMov);
            Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
            if (bOrtho) {
                tools::Long ndx0=aMov.X()-aFix.X();
                tools::Long ndy0=aMov.Y()-aFix.Y();
                bool bHLin=ndy0==0;
                bool bVLin=ndx0==0;
                if (!bHLin || !bVLin) { // else aPt1==aPt2
                    tools::Long ndx=aPt.X()-aFix.X();
                    tools::Long ndy=aPt.Y()-aFix.Y();
                    double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
                    double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
                    bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
                    bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
                    if (bHor) ndy=tools::Long(ndy0*nXFact);
                    if (bVer) ndx=tools::Long(ndx0*nYFact);
                    aPt=aFix;
                    aPt.AdjustX(ndx );
                    aPt.AdjustY(ndy );
                } // else Ortho8
            }
            rMov=aPt;
        } break;
        case 4: case 5: {
            tools::Long nVal0=rRec.nLineDist;
            RotatePoint(aPt,(nHdlNum==4 ? m_aPt1 : m_aPt2),nSin,-nCos);
            rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? m_aPt1.Y() : m_aPt2.Y());
            if (bBelow) rRec.nLineDist=-rRec.nLineDist;
            if (rRec.nLineDist<0) {
                rRec.nLineDist=-rRec.nLineDist;
                rRec.bBelowRefEdge=!bBelow;
            }
            rRec.nLineDist-=rRec.nHelplineOverhang;
            if (bOrtho) rRec.nLineDist=nVal0;
        } break;
    } // switch
}


bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
{
    rStat.SetOrtho8Possible();
    m_aPt1=rStat.GetStart();
    m_aPt2=rStat.GetNow();
    SetTextDirty();
    return true;
}

bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
{
    SdrView* pView=rStat.GetView();
    m_aPt1=rStat.GetStart();
    m_aPt2=rStat.GetNow();
    if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
        m_aPt1+=m_aPt1;
        m_aPt1-=rStat.GetNow();
    }
    SetTextDirty();
    SetBoundRectDirty();
    m_bSnapRectDirty=true;
    return true;
}

bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
    SetTextDirty();
    SetBoundAndSnapRectsDirty();
    return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
}

bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
{
    return false;
}

void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
{
}

basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
{
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;

    ImpTakeAttr(aRec);
    ImpCalcGeometrics(aRec, aMPol);

    return ImpCalcXPoly(aMPol);
}

PointerStyle SdrMeasureObj::GetCreatePointer() const
{
    return PointerStyle::Cross;
}

void SdrMeasureObj::NbcMove(const Size& rSiz)
{
    SdrTextObj::NbcMove(rSiz);
    m_aPt1.Move(rSiz);
    m_aPt2.Move(rSiz);
}

void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
    SdrTextObj::NbcResize(rRef,xFact,yFact);
    ResizePoint(m_aPt1,rRef,xFact,yFact);
    ResizePoint(m_aPt2,rRef,xFact,yFact);
    SetTextDirty();
}

void SdrMeasureObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
    SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
    tools::Long nLen0=GetLen(m_aPt2-m_aPt1);
    RotatePoint(m_aPt1,rRef,sn,cs);
    RotatePoint(m_aPt2,rRef,sn,cs);
    tools::Long nLen1=GetLen(m_aPt2-m_aPt1);
    if (nLen1!=nLen0) { // rounding error!
        tools::Long dx=m_aPt2.X()-m_aPt1.X();
        tools::Long dy=m_aPt2.Y()-m_aPt1.Y();
        dx=BigMulDiv(dx,nLen0,nLen1);
        dy=BigMulDiv(dy,nLen0,nLen1);
        if (rRef==m_aPt2) {
            m_aPt1.setX(m_aPt2.X()-dx );
            m_aPt1.setY(m_aPt2.Y()-dy );
        } else {
            m_aPt2.setX(m_aPt1.X()+dx );
            m_aPt2.setY(m_aPt1.Y()+dy );
        }
    }
    SetBoundAndSnapRectsDirty();
}

void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
{
    SdrTextObj::NbcMirror(rRef1,rRef2);
    MirrorPoint(m_aPt1,rRef1,rRef2);
    MirrorPoint(m_aPt2,rRef1,rRef2);
    SetBoundAndSnapRectsDirty();
}

void SdrMeasureObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
{
    SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
    ShearPoint(m_aPt1,rRef,tn,bVShear);
    ShearPoint(m_aPt2,rRef,tn,bVShear);
    SetBoundAndSnapRectsDirty();
    SetTextDirty();
}

Degree100 SdrMeasureObj::GetRotateAngle() const
{
    return GetAngle(m_aPt2-m_aPt1);
}

void SdrMeasureObj::RecalcSnapRect()
{
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;
    XPolyPolygon aXPP;

    ImpTakeAttr(aRec);
    ImpCalcGeometrics(aRec, aMPol);
    aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
    maSnapRect = aXPP.GetBoundRect();
}

sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
{
    return 2;
}

Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
{
    if (i==0) return m_aPt1;
    else return m_aPt2;
}

bool SdrMeasureObj::IsPolyObj() const
{
    return true;
}

sal_uInt32 SdrMeasureObj::GetPointCount() const
{
    return 2;
}

Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
{
     return (0 == i) ? m_aPt1 : m_aPt2;
}

void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
{
    if (0 == i)
        m_aPt1=rPnt;
    if (1 == i)
        m_aPt2=rPnt;
    SetBoundAndSnapRectsDirty();
    SetTextDirty();
}

std::unique_ptr<SdrObjGeoData> SdrMeasureObj::NewGeoData() const
{
    return std::make_unique<SdrMeasureObjGeoData>();
}

void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
{
    SdrTextObj::SaveGeoData(rGeo);
    SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
    rMGeo.aPt1=m_aPt1;
    rMGeo.aPt2=m_aPt2;
}

void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData& rGeo)
{
    SdrTextObj::RestoreGeoData(rGeo);
    const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
    m_aPt1=rMGeo.aPt1;
    m_aPt2=rMGeo.aPt2;
    SetTextDirty();
}

rtl::Reference<SdrObject> SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
{
    // get XOR Poly as base
    XPolyPolygon aTmpPolyPolygon(TakeXorPoly());

    // get local ItemSet and StyleSheet
    SfxItemSet aSet(GetObjectItemSet());
    SfxStyleSheet* pStyleSheet = GetStyleSheet();

    // prepare group
    rtl::Reference<SdrObjGroup> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));

    // prepare parameters
    basegfx::B2DPolyPolygon aPolyPoly;
    rtl::Reference<SdrPathObj> pPath;
    sal_uInt16 nCount(aTmpPolyPolygon.Count());
    sal_uInt16 nLoopStart(0);

    if(nCount == 3)
    {
        // three lines, first one is the middle one
        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());

        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
        aSet.Put(XLineStartWidthItem(0));
        aSet.Put(XLineEndWidthItem(0));
        nLoopStart = 1;
    }
    else if(nCount == 4)
    {
        // four lines, middle line with gap, so there are two lines used
        // which have one arrow each
        sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
        aSet.Put(XLineEndWidthItem(0));

        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);

        pGroup->GetSubList()->NbcInsertObject(pPath.get());

        aSet.Put(XLineEndWidthItem(nEndWidth));
        aSet.Put(XLineStartWidthItem(0));

        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);

        pGroup->GetSubList()->NbcInsertObject(pPath.get());

        aSet.Put(XLineEndWidthItem(0));
        nLoopStart = 2;
    }
    else if(nCount == 5)
    {
        // five lines, first two are the outer ones
        sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();

        aSet.Put(XLineEndWidthItem(0));

        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);

        pGroup->GetSubList()->NbcInsertObject(pPath.get());

        aSet.Put(XLineEndWidthItem(nEndWidth));
        aSet.Put(XLineStartWidthItem(0));

        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);

        pGroup->GetSubList()->NbcInsertObject(pPath.get());

        aSet.Put(XLineEndWidthItem(0));
        nLoopStart = 2;
    }

    for(;nLoopStart<nCount;nLoopStart++)
    {
        aPolyPoly.clear();
        aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
        pPath = new SdrPathObj(
            getSdrModelFromSdrObject(),
            SdrObjKind::PathLine,
            aPolyPoly);

        pPath->SetMergedItemSet(aSet);
        pPath->SetStyleSheet(pStyleSheet, true);

        pGroup->GetSubList()->NbcInsertObject(pPath.get());
    }

    if(bAddText)
    {
        return ImpConvertAddText(std::move(pGroup), bBezier);
    }
    else
    {
        return pGroup;
    }
}

bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
{
    UndirtyText();
    return SdrTextObj::BegTextEdit(rOutl);
}

const Size& SdrMeasureObj::GetTextSize() const
{
    if (m_bTextDirty) UndirtyText();
    return SdrTextObj::GetTextSize();
}

OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
{
    if(m_bTextDirty)
        UndirtyText();
    return SdrTextObj::GetOutlinerParaObject();
}

void SdrMeasureObj::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject, bool bAdjustTextFrameWidthAndHeight)
{
    SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject), bAdjustTextFrameWidthAndHeight);
    if(SdrTextObj::GetOutlinerParaObject())
        SetTextDirty(); // recalculate text
}

void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
    tools::Rectangle* pAnchorRect, bool bLineWidth ) const
{
    if (m_bTextDirty) UndirtyText();
    SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
}

void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
{
    if (m_bTextDirty) UndirtyText();
    SdrTextObj::TakeTextAnchorRect(rAnchorRect);
}

void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
{
    if (m_bTextDirty) UndirtyText();
    SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
}

EEAnchorMode SdrMeasureObj::GetOutlinerViewAnchorMode() const
{
    if (m_bTextDirty) UndirtyText();
    ImpMeasureRec aRec;
    ImpMeasurePoly aMPol;
    ImpTakeAttr(aRec);
    ImpCalcGeometrics(aRec,aMPol);

    SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
    SdrTextVertAdjust eTV=GetTextVerticalAdjust();
    css::drawing::MeasureTextHorzPos eMH = aMPol.eUsedTextHPos;
    css::drawing::MeasureTextVertPos eMV = aMPol.eUsedTextVPos;
    bool bTextRota90=aRec.bTextRota90;
    bool bBelowRefEdge=aRec.bBelowRefEdge;

    // TODO: bTextUpsideDown should be interpreted here!
    if (!bTextRota90) {
        if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
        if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
        // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
        if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM;
        if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP;
        if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
    } else {
        if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
        if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
        // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
        if (!bBelowRefEdge) {
            if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT;
            if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
        } else {
            if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT;
            if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
        }
        if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
    }

    EEAnchorMode eRet=EEAnchorMode::BottomHCenter;
    if (eTH==SDRTEXTHORZADJUST_LEFT) {
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft;
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft;
        else eRet=EEAnchorMode::VCenterLeft;
    } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight;
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight;
        else eRet=EEAnchorMode::VCenterRight;
    } else {
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
        else eRet=EEAnchorMode::VCenterHCenter;
    }
    return eRet;
}


// #i97878#
// TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
// same as line geometry in SdrPathObj. Thus needs to be overridden and
// implemented since currently it is derived from SdrTextObj which uses
// a functionality based on SnapRect which is not useful here

bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
{
    // handle the same as a simple line since the definition is based on two points
    const basegfx::B2DRange aRange(m_aPt1.X(), m_aPt1.Y(), m_aPt2.X(), m_aPt2.Y());
    basegfx::B2DTuple aScale(aRange.getRange());
    basegfx::B2DTuple aTranslate(aRange.getMinimum());

    // position maybe relative to anchor position, convert
    if( getSdrModelFromSdrObject().IsWriter() )
    {
        if(GetAnchorPos().X() || GetAnchorPos().Y())
        {
            aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
        }
    }

    // build return value matrix
    rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);

    return true;
}

void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{
    // use given transformation to derive the two defining points from unit line
    basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
    basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));

    if( getSdrModelFromSdrObject().IsWriter() )
    {
        // if anchor is used, make position relative to it
        if(GetAnchorPos().X() || GetAnchorPos().Y())
        {
            const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());

            aPosA += aAnchorOffset;
            aPosB += aAnchorOffset;
        }
    }

    // derive new model data
    const Point aNewPt1(basegfx::fround<tools::Long>(aPosA.getX()), basegfx::fround<tools::Long>(aPosA.getY()));
    const Point aNewPt2(basegfx::fround<tools::Long>(aPosB.getX()), basegfx::fround<tools::Long>(aPosB.getY()));

    if(aNewPt1 == m_aPt1 && aNewPt2 == m_aPt2)
        return;

    // set model values and broadcast
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();

    m_aPt1 = aNewPt1;
    m_aPt2 = aNewPt2;

    SetTextDirty();
    ActionChanged();
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
}

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

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

¤ Dauer der Verarbeitung: 0.6 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.