Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdomeas.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <svx/dialmgr.hxx>
21
#include <svx/strings.hrc>
22
23
#include <basegfx/matrix/b2dhommatrix.hxx>
24
#include <basegfx/matrix/b2dhommatrixtools.hxx>
25
#include <basegfx/point/b2dpoint.hxx>
26
#include <basegfx/polygon/b2dpolygon.hxx>
27
#include <basegfx/polygon/b2dpolypolygon.hxx>
28
#include <editeng/editdata.hxx>
29
#include <editeng/editobj.hxx>
30
#include <editeng/eeitem.hxx>
31
#include <editeng/flditem.hxx>
32
#include <editeng/measfld.hxx>
33
#include <editeng/outlobj.hxx>
34
#include <math.h>
35
#include <svl/style.hxx>
36
37
#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
38
#include <sdr/properties/measureproperties.hxx>
39
#include <svx/svddrag.hxx>
40
#include <svx/svdhdl.hxx>
41
#include <svx/svdmodel.hxx>
42
#include <svx/svdogrp.hxx>
43
#include <svx/svdomeas.hxx>
44
#include <svx/svdopath.hxx>
45
#include <svx/svdoutl.hxx>
46
#include <svx/svdpage.hxx>
47
#include <svx/svdtrans.hxx>
48
#include <svx/svdview.hxx>
49
#include <svx/sxmbritm.hxx>
50
#include <svx/sxmlhitm.hxx>
51
#include <sxmsitm.hxx>
52
#include <sxmtaitm.hxx>
53
#include <svx/sxmtfitm.hxx>
54
#include <svx/sxmtpitm.hxx>
55
#include <svx/sxmtritm.hxx>
56
#include <svx/sxmuitm.hxx>
57
#include <svx/xlnedcit.hxx>
58
#include <svx/xlnedit.hxx>
59
#include <svx/xlnedwit.hxx>
60
#include <svx/xlnstcit.hxx>
61
#include <svx/xlnstit.hxx>
62
#include <svx/xlnstwit.hxx>
63
#include <svx/xlnwtit.hxx>
64
#include <svx/xpoly.hxx>
65
#include <unotools/syslocale.hxx>
66
#include <unotools/localedatawrapper.hxx>
67
#include <vcl/ptrstyle.hxx>
68
69
70
0
SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
71
0
SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
72
73
OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
74
0
{
75
0
    OUString aStr;
76
0
    double fMeasureScale = 1.0;
77
0
    bool bTextRota90(false);
78
0
    bool bShowUnit(false);
79
0
    FieldUnit eMeasureUnit(FieldUnit::NONE);
80
0
    FieldUnit eModUIUnit(FieldUnit::NONE);
81
82
0
    const SfxItemSet& rSet = GetMergedItemSet();
83
0
    bTextRota90 = rSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue();
84
0
    eMeasureUnit = rSet.Get(SDRATTR_MEASUREUNIT).GetValue();
85
0
    fMeasureScale = rSet.Get(SDRATTR_MEASURESCALE).GetValue();
86
0
    bShowUnit = rSet.Get(SDRATTR_MEASURESHOWUNIT).GetValue();
87
0
    sal_Int16 nNumDigits = rSet.Get(SDRATTR_MEASUREDECIMALPLACES).GetValue();
88
89
0
    switch(eMeasureFieldKind)
90
0
    {
91
0
        case SdrMeasureFieldKind::Value:
92
0
        {
93
0
            eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
94
95
0
            if(eMeasureUnit == FieldUnit::NONE)
96
0
                eMeasureUnit = eModUIUnit;
97
98
0
            sal_Int32 nLen(GetLen(m_aPt2 - m_aPt1));
99
0
            double fFact = 1.0;
100
101
0
            if(eMeasureUnit != eModUIUnit)
102
0
            {
103
                // for the unit conversion
104
0
                fFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
105
0
            }
106
107
0
            if(fMeasureScale != 1.0)
108
0
            {
109
0
                fFact *= fMeasureScale;
110
0
            }
111
112
0
            if(fFact != 1.0)
113
0
            {
114
0
                nLen = nLen * fFact;
115
0
            }
116
117
0
            aStr = getSdrModelFromSdrObject().GetMetricString(nLen, true, nNumDigits);
118
119
0
            SvtSysLocale aSysLocale;
120
0
            const LocaleDataWrapper& rLocaleDataWrapper = aSysLocale.GetLocaleData();
121
0
            sal_Unicode cDec(rLocaleDataWrapper.getNumDecimalSep()[0]);
122
0
            sal_Unicode cDecAlt(rLocaleDataWrapper.getNumDecimalSepAlt().toChar());
123
124
0
            if(aStr.indexOf(cDec) != -1 || (cDecAlt && aStr.indexOf(cDecAlt) != -1))
125
0
            {
126
0
                sal_Int32 nLen2(aStr.getLength() - 1);
127
128
0
                while(aStr[nLen2] == '0')
129
0
                {
130
0
                    aStr = aStr.copy(0, nLen2);
131
0
                    nLen2--;
132
0
                }
133
134
0
                if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
135
0
                {
136
0
                    aStr = aStr.copy(0, nLen2);
137
0
                    nLen2--;
138
0
                }
139
140
0
                if(aStr.isEmpty())
141
0
                    aStr += "0";
142
0
            }
143
144
0
            break;
145
0
        }
146
0
        case SdrMeasureFieldKind::Unit:
147
0
        {
148
0
            if(bShowUnit)
149
0
            {
150
0
                eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
151
152
0
                if(eMeasureUnit == FieldUnit::NONE)
153
0
                    eMeasureUnit = eModUIUnit;
154
155
0
                aStr = SdrModel::GetUnitString(eMeasureUnit);
156
0
            }
157
158
0
            break;
159
0
        }
160
0
        case SdrMeasureFieldKind::Rotate90Blanks:
161
0
        {
162
0
            if(bTextRota90)
163
0
            {
164
0
                aStr = " ";
165
0
            }
166
167
0
            break;
168
0
        }
169
0
    }
170
0
    return aStr;
171
0
}
172
173
174
// BaseProperties section
175
176
std::unique_ptr<sdr::properties::BaseProperties> SdrMeasureObj::CreateObjectSpecificProperties()
177
0
{
178
0
    return std::make_unique<sdr::properties::MeasureProperties>(*this);
179
0
}
180
181
182
// DrawContact section
183
184
std::unique_ptr<sdr::contact::ViewContact> SdrMeasureObj::CreateObjectSpecificViewContact()
185
0
{
186
0
    return std::make_unique<sdr::contact::ViewContactOfSdrMeasureObj>(*this);
187
0
}
188
189
190
SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel)
191
0
:   SdrTextObj(rSdrModel),
192
0
    m_bTextDirty(false)
193
0
{
194
    // #i25616#
195
0
    mbSupportTextIndentingOnLineWidthChange = false;
196
0
}
197
198
SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel, SdrMeasureObj const & rSource)
199
0
:   SdrTextObj(rSdrModel, rSource),
200
0
    m_bTextDirty(false)
201
0
{
202
    // #i25616#
203
0
    mbSupportTextIndentingOnLineWidthChange = false;
204
205
0
    m_aPt1 = rSource.m_aPt1;
206
0
    m_aPt2 = rSource.m_aPt2;
207
0
    m_bTextDirty = rSource.m_bTextDirty;
208
0
}
209
210
SdrMeasureObj::SdrMeasureObj(
211
    SdrModel& rSdrModel,
212
    const Point& rPt1,
213
    const Point& rPt2)
214
0
:   SdrTextObj(rSdrModel),
215
0
    m_aPt1(rPt1),
216
0
    m_aPt2(rPt2),
217
0
    m_bTextDirty(false)
218
0
{
219
    // #i25616#
220
0
    mbSupportTextIndentingOnLineWidthChange = false;
221
0
}
222
223
SdrMeasureObj::~SdrMeasureObj()
224
0
{
225
0
}
226
227
void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
228
0
{
229
0
    rInfo.bMoveAllowed      =true;
230
0
    rInfo.bResizeFreeAllowed=true;
231
0
    rInfo.bResizePropAllowed=true;
232
0
    rInfo.bRotateFreeAllowed=true;
233
0
    rInfo.bRotate90Allowed  =true;
234
0
    rInfo.bMirrorFreeAllowed=true;
235
0
    rInfo.bMirror45Allowed  =true;
236
0
    rInfo.bMirror90Allowed  =true;
237
0
    rInfo.bTransparenceAllowed = false;
238
0
    rInfo.bShearAllowed     =true;
239
0
    rInfo.bEdgeRadiusAllowed=false;
240
0
    rInfo.bNoOrthoDesired   =true;
241
0
    rInfo.bNoContortion     =false;
242
0
    rInfo.bCanConvToPath    =false;
243
0
    rInfo.bCanConvToPoly    =true;
244
0
    rInfo.bCanConvToPathLineToArea=false;
245
0
    rInfo.bCanConvToPolyLineToArea=false;
246
0
    rInfo.bCanConvToContour = LineGeometryUsageIsNecessary();
247
0
}
248
249
SdrObjKind SdrMeasureObj::GetObjIdentifier() const
250
0
{
251
0
    return SdrObjKind::Measure;
252
0
}
253
254
struct ImpMeasureRec : public SdrDragStatUserData
255
{
256
    Point                       aPt1;
257
    Point                       aPt2;
258
    css::drawing::MeasureTextHorzPos eWantTextHPos;
259
    css::drawing::MeasureTextVertPos eWantTextVPos;
260
    tools::Long                        nLineDist;
261
    tools::Long                        nHelplineOverhang;
262
    tools::Long                        nHelplineDist;
263
    tools::Long                        nHelpline1Len;
264
    tools::Long                        nHelpline2Len;
265
    bool                        bBelowRefEdge;
266
    bool                        bTextRota90;
267
    bool                        bTextUpsideDown;
268
    bool                        bTextAutoAngle;
269
    Degree100                   nTextAutoAngleView;
270
};
271
272
namespace {
273
274
struct ImpLineRec
275
{
276
    Point                       aP1;
277
    Point                       aP2;
278
};
279
280
}
281
282
struct ImpMeasurePoly
283
{
284
    ImpLineRec                  aMainline1; // those with the 1st arrowhead
285
    ImpLineRec                  aMainline2; // those with the 2nd arrowhead
286
    ImpLineRec                  aMainline3; // those in between
287
    ImpLineRec                  aHelpline1;
288
    ImpLineRec                  aHelpline2;
289
    Size                        aTextSize;
290
    tools::Long                        nLineLen;
291
    Degree100                   nLineAngle;
292
    Degree100                   nTextAngle;
293
    Degree100                   nHlpAngle;
294
    double                      nLineSin;
295
    double                      nLineCos;
296
    sal_uInt16                      nMainlineCnt;
297
    css::drawing::MeasureTextHorzPos eUsedTextHPos;
298
    css::drawing::MeasureTextVertPos eUsedTextVPos;
299
    tools::Long                        nLineWdt2;  // half the line width
300
    tools::Long                        nArrow1Len; // length of 1st arrowhead; for Center, use only half
301
    tools::Long                        nArrow2Len; // length of 2nd arrowhead; for Center, use only half
302
    tools::Long                        nArrow1Wdt; // width of 1st arrow
303
    tools::Long                        nArrow2Wdt; // width of 2nd arrow
304
    tools::Long                        nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
305
    bool                        bAutoUpsideDown; // UpsideDown via automation
306
    bool                        bBreakedLine;
307
};
308
309
void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
310
0
{
311
0
    rRec.aPt1 = m_aPt1;
312
0
    rRec.aPt2 = m_aPt2;
313
314
0
    const SfxItemSet& rSet = GetObjectItemSet();
315
0
    rRec.eWantTextHPos     =rSet.Get(SDRATTR_MEASURETEXTHPOS        ).GetValue();
316
0
    rRec.eWantTextVPos     =rSet.Get(SDRATTR_MEASURETEXTVPOS        ).GetValue();
317
0
    rRec.nLineDist         =rSet.Get(SDRATTR_MEASURELINEDIST        ).GetValue();
318
0
    rRec.nHelplineOverhang =rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue();
319
0
    rRec.nHelplineDist     =rSet.Get(SDRATTR_MEASUREHELPLINEDIST    ).GetValue();
320
0
    rRec.nHelpline1Len     =rSet.Get(SDRATTR_MEASUREHELPLINE1LEN    ).GetValue();
321
0
    rRec.nHelpline2Len     =rSet.Get(SDRATTR_MEASUREHELPLINE2LEN    ).GetValue();
322
0
    rRec.bBelowRefEdge     =rSet.Get(SDRATTR_MEASUREBELOWREFEDGE    ).GetValue();
323
0
    rRec.bTextRota90       =rSet.Get(SDRATTR_MEASURETEXTROTA90      ).GetValue();
324
0
    rRec.bTextUpsideDown   =static_cast<const SdrMeasureTextUpsideDownItem&   >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN  )).GetValue();
325
0
    rRec.bTextAutoAngle    =rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE    ).GetValue();
326
0
    rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
327
0
}
328
329
static tools::Long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, tools::Long nNewWidth, bool bCenter)
330
0
{
331
0
    const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
332
0
    const double fOldWidth(std::max(aPolygonRange.getWidth(), 1.0));
333
0
    const double fScale(static_cast<double>(nNewWidth) / fOldWidth);
334
0
    tools::Long nHeight(basegfx::fround<tools::Long>(aPolygonRange.getHeight() * fScale));
335
336
0
    if(bCenter)
337
0
    {
338
0
        nHeight /= 2;
339
0
    }
340
341
0
    return nHeight;
342
0
}
343
344
void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
345
0
{
346
0
    Point aP1(rRec.aPt1);
347
0
    Point aP2(rRec.aPt2);
348
0
    Point aDelt(aP2); aDelt-=aP1;
349
350
0
    rPol.aTextSize=GetTextSize();
351
0
    rPol.nLineLen=GetLen(aDelt);
352
353
0
    rPol.nLineWdt2=0;
354
0
    tools::Long nArrow1Len=0; bool bArrow1Center=false;
355
0
    tools::Long nArrow2Len=0; bool bArrow2Center=false;
356
0
    tools::Long nArrow1Wdt=0;
357
0
    tools::Long nArrow2Wdt=0;
358
0
    rPol.nArrow1Wdt=0;
359
0
    rPol.nArrow2Wdt=0;
360
0
    tools::Long nArrowNeed=0;
361
0
    tools::Long nShortLen=0;
362
0
    bool bPfeileAussen = false;
363
364
0
    const SfxItemSet& rSet = GetObjectItemSet();
365
0
    sal_Int32 nLineWdt = rSet.Get(XATTR_LINEWIDTH).GetValue(); // line width
366
0
    rPol.nLineWdt2 = (nLineWdt + 1) / 2;
367
368
0
    nArrow1Wdt = rSet.Get(XATTR_LINESTARTWIDTH).GetValue();
369
0
    if(nArrow1Wdt < 0)
370
0
        nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative
371
372
0
    nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
373
0
    if(nArrow2Wdt < 0)
374
0
        nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relative
375
376
0
    basegfx::B2DPolyPolygon aPol1(rSet.Get(XATTR_LINESTART).GetLineStartValue());
377
0
    basegfx::B2DPolyPolygon aPol2(rSet.Get(XATTR_LINEEND).GetLineEndValue());
378
0
    bArrow1Center = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
379
0
    bArrow2Center = rSet.Get(XATTR_LINEENDCENTER).GetValue();
380
0
    nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
381
0
    nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
382
383
    // nArrowLen is already halved at bCenter.
384
    // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
385
0
    nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
386
0
    if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
387
0
    nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
388
389
0
    rPol.eUsedTextHPos=rRec.eWantTextHPos;
390
0
    rPol.eUsedTextVPos=rRec.eWantTextVPos;
391
0
    if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
392
0
        rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST;
393
0
    bool bBrkLine=false;
394
0
    if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
395
0
    {
396
0
        OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
397
0
        if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
398
0
        {
399
0
            bBrkLine=true; // dashed line if there's only on paragraph.
400
0
        }
401
0
    }
402
0
    rPol.bBreakedLine=bBrkLine;
403
0
    if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside
404
0
        bool bOutside = false;
405
0
        tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
406
0
        if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
407
0
        if (bBrkLine) {
408
0
            if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
409
0
        } else {
410
0
            tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
411
0
            if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
412
0
        }
413
0
        rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
414
0
    }
415
0
    if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
416
0
    rPol.nArrow1Wdt=nArrow1Wdt;
417
0
    rPol.nArrow2Wdt=nArrow2Wdt;
418
0
    rPol.nShortLineLen=nShortLen;
419
0
    rPol.nArrow1Len=nArrow1Len;
420
0
    rPol.nArrow2Len=nArrow2Len;
421
422
0
    rPol.nLineAngle=GetAngle(aDelt);
423
0
    double a = toRadians(rPol.nLineAngle);
424
0
    double nLineSin=sin(a);
425
0
    double nLineCos=cos(a);
426
0
    rPol.nLineSin=nLineSin;
427
0
    rPol.nLineCos=nLineCos;
428
429
0
    rPol.nTextAngle=rPol.nLineAngle;
430
0
    if (rRec.bTextRota90) rPol.nTextAngle+=9000_deg100;
431
432
0
    rPol.bAutoUpsideDown=false;
433
0
    if (rRec.bTextAutoAngle) {
434
0
        Degree100 nTmpAngle=NormAngle36000(rPol.nTextAngle-rRec.nTextAutoAngleView);
435
0
        if (nTmpAngle>=18000_deg100) {
436
0
            rPol.nTextAngle+=18000_deg100;
437
0
            rPol.bAutoUpsideDown=true;
438
0
        }
439
0
    }
440
441
0
    if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000_deg100;
442
0
    rPol.nTextAngle=NormAngle36000(rPol.nTextAngle);
443
0
    rPol.nHlpAngle=rPol.nLineAngle+9000_deg100;
444
0
    if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000_deg100;
445
0
    rPol.nHlpAngle=NormAngle36000(rPol.nHlpAngle);
446
0
    double nHlpSin=nLineCos;
447
0
    double nHlpCos=-nLineSin;
448
0
    if (rRec.bBelowRefEdge) {
449
0
        nHlpSin=-nHlpSin;
450
0
        nHlpCos=-nHlpCos;
451
0
    }
452
453
0
    tools::Long nLineDist=rRec.nLineDist;
454
0
    tools::Long nOverhang=rRec.nHelplineOverhang;
455
0
    tools::Long nHelplineDist=rRec.nHelplineDist;
456
457
0
    tools::Long dx = basegfx::fround<tools::Long>(nLineDist * nHlpCos);
458
0
    tools::Long dy = basegfx::fround<tools::Long>(nLineDist * -nHlpSin);
459
0
    tools::Long dxh1a = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline1Len) * nHlpCos);
460
0
    tools::Long dyh1a = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline1Len) * -nHlpSin);
461
0
    tools::Long dxh1b = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline2Len) * nHlpCos);
462
0
    tools::Long dyh1b = basegfx::fround<tools::Long>((nHelplineDist - rRec.nHelpline2Len) * -nHlpSin);
463
0
    tools::Long dxh2 = basegfx::fround<tools::Long>((nLineDist + nOverhang) * nHlpCos);
464
0
    tools::Long dyh2 = basegfx::fround<tools::Long>((nLineDist + nOverhang) * -nHlpSin);
465
466
    // extension line 1
467
0
    rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
468
0
    rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
469
470
    // extension line 2
471
0
    rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
472
0
    rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
473
474
    // dimension line
475
0
    Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
476
0
    Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
477
0
    if (!bPfeileAussen) {
478
0
        rPol.aMainline1.aP1=aMainlinePt1;
479
0
        rPol.aMainline1.aP2=aMainlinePt2;
480
0
        rPol.aMainline2=rPol.aMainline1;
481
0
        rPol.aMainline3=rPol.aMainline1;
482
0
        rPol.nMainlineCnt=1;
483
0
        if (bBrkLine) {
484
0
            tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
485
0
            tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
486
0
            rPol.nMainlineCnt=2;
487
0
            rPol.aMainline1.aP2=aMainlinePt1;
488
0
            rPol.aMainline1.aP2.AdjustX(nHalfLen );
489
0
            RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
490
0
            rPol.aMainline2.aP1=aMainlinePt2;
491
0
            rPol.aMainline2.aP1.AdjustX( -nHalfLen );
492
0
            RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
493
0
        }
494
0
    } else {
495
0
        tools::Long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
496
0
        tools::Long nLen2=nShortLen;
497
0
        tools::Long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
498
0
        if (!bBrkLine) {
499
0
            if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
500
0
            if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
501
0
        }
502
0
        rPol.aMainline1.aP1=aMainlinePt1;
503
0
        rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.AdjustX( -nLen1 ); RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
504
0
        rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.AdjustX(nLen2 ); RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
505
0
        rPol.aMainline2.aP2=aMainlinePt2;
506
0
        rPol.aMainline3.aP1=aMainlinePt1;
507
0
        rPol.aMainline3.aP2=aMainlinePt2;
508
0
        rPol.nMainlineCnt=3;
509
0
        if (bBrkLine && rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_INSIDE) rPol.nMainlineCnt=2;
510
0
    }
511
0
}
512
513
basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
514
0
{
515
0
    basegfx::B2DPolyPolygon aRetval;
516
0
    basegfx::B2DPolygon aPartPolyA;
517
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
518
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
519
0
    aRetval.append(aPartPolyA);
520
521
0
    if(rPol.nMainlineCnt > 1)
522
0
    {
523
0
        aPartPolyA.clear();
524
0
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
525
0
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
526
0
        aRetval.append(aPartPolyA);
527
0
    }
528
529
0
    if(rPol.nMainlineCnt > 2)
530
0
    {
531
0
        aPartPolyA.clear();
532
0
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
533
0
        aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
534
0
        aRetval.append(aPartPolyA);
535
0
    }
536
537
0
    aPartPolyA.clear();
538
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
539
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
540
0
    aRetval.append(aPartPolyA);
541
542
0
    aPartPolyA.clear();
543
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
544
0
    aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
545
0
    aRetval.append(aPartPolyA);
546
547
0
    return aRetval;
548
0
}
549
550
bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
551
    bool bEdit,
552
    std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, std::optional<FontLineStyle>& rpFldLineStyle, OUString& rRet) const
553
0
{
554
0
    const SvxFieldData* pField=rField.GetField();
555
0
    const SdrMeasureField* pMeasureField=dynamic_cast<const SdrMeasureField*>( pField );
556
0
    if (pMeasureField!=nullptr) {
557
0
        rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
558
0
        if (rpFldColor && !bEdit)
559
0
        {
560
0
            rpFldColor.reset();
561
0
        }
562
0
        return true;
563
0
    } else {
564
0
        return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rpFldLineStyle,rRet);
565
0
    }
566
0
}
567
568
void SdrMeasureObj::UndirtyText() const
569
0
{
570
0
    if (!m_bTextDirty)
571
0
        return;
572
573
0
    SdrOutliner& rOutliner=ImpGetDrawOutliner();
574
0
    OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
575
0
    if(pOutlinerParaObject==nullptr)
576
0
    {
577
0
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD), ESelection(0,0));
578
0
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value), EE_FEATURE_FIELD),ESelection(0,1));
579
0
        rOutliner.QuickInsertText(u" "_ustr, ESelection(0,2));
580
0
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit), EE_FEATURE_FIELD),ESelection(0,3));
581
0
        rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD),ESelection(0,4));
582
583
0
        if(GetStyleSheet())
584
0
            rOutliner.SetStyleSheet(0, GetStyleSheet());
585
586
0
        rOutliner.SetParaAttribs(0, GetObjectItemSet());
587
588
        // cast to nonconst
589
0
        const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
590
0
    }
591
0
    else
592
0
    {
593
0
        rOutliner.SetText(*pOutlinerParaObject);
594
0
    }
595
596
0
    rOutliner.SetUpdateLayout(true);
597
0
    rOutliner.UpdateFields();
598
0
    Size aSiz(rOutliner.CalcTextSize());
599
0
    rOutliner.Clear();
600
    // cast to nonconst three times
601
0
    const_cast<SdrMeasureObj*>(this)->maTextSize = aSiz;
602
0
    const_cast<SdrMeasureObj*>(this)->mbTextSizeDirty = false;
603
0
    const_cast<SdrMeasureObj*>(this)->m_bTextDirty = false;
604
0
}
605
606
void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
607
0
{
608
0
    if (m_bTextDirty) UndirtyText();
609
0
    ImpMeasureRec aRec;
610
0
    ImpMeasurePoly aMPol;
611
0
    ImpTakeAttr(aRec);
612
0
    ImpCalcGeometrics(aRec,aMPol);
613
614
    // determine TextSize including text frame margins
615
0
    Size aTextSize2(aMPol.aTextSize);
616
0
    if (aTextSize2.Width()<1) aTextSize2.setWidth(1 );
617
0
    if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
618
0
    aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
619
0
    aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
620
621
0
    Point aPt1b(aMPol.aMainline1.aP1);
622
0
    tools::Long nLen=aMPol.nLineLen;
623
0
    tools::Long nLWdt=aMPol.nLineWdt2;
624
0
    tools::Long nArr1Len=aMPol.nArrow1Len;
625
0
    tools::Long nArr2Len=aMPol.nArrow2Len;
626
0
    if (aMPol.bBreakedLine) {
627
        // In the case of a dashed line and Outside, the text should be
628
        // placed next to the line at the arrowhead instead of directly
629
        // at the arrowhead.
630
0
        nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
631
0
        nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
632
0
    }
633
634
0
    Point aTextPos;
635
0
    bool bRota90=aRec.bTextRota90;
636
0
    bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
637
0
    bool bBelowRefEdge=aRec.bBelowRefEdge;
638
0
    css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
639
0
    css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos;
640
0
    if (!bRota90) {
641
0
        switch (eMH) {
642
0
            case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break;
643
0
            case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break;
644
0
            default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
645
0
        }
646
0
        switch (eMV) {
647
0
            case css::drawing::MeasureTextVertPos_CENTERED:
648
0
                aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break;
649
0
            case css::drawing::MeasureTextVertPos_WEST: {
650
0
                if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt );
651
0
                else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
652
0
            } break;
653
0
            default: {
654
0
                if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
655
0
                else aTextPos.setY(aPt1b.Y()+nLWdt );
656
0
            }
657
0
        }
658
0
        if (bUpsideDown) {
659
0
            aTextPos.AdjustX(aTextSize2.Width() );
660
0
            aTextPos.AdjustY(aTextSize2.Height() );
661
0
        }
662
0
    } else { // also if bTextRota90==TRUE
663
0
        switch (eMH) {
664
0
            case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break;
665
0
            case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break;
666
0
            default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
667
0
        }
668
0
        switch (eMV) {
669
0
            case css::drawing::MeasureTextVertPos_CENTERED:
670
0
                aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break;
671
0
            case css::drawing::MeasureTextVertPos_WEST: {
672
0
                if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
673
0
                else aTextPos.setY(aPt1b.Y()-nLWdt );
674
0
            } break;
675
0
            default: {
676
0
                if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
677
0
                else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
678
0
            }
679
0
        }
680
0
        if (bUpsideDown) {
681
0
            aTextPos.AdjustX(aTextSize2.Height() );
682
0
            aTextPos.AdjustY( -(aTextSize2.Width()) );
683
0
        }
684
0
    }
685
0
    if (aMPol.nTextAngle != maGeo.m_nRotationAngle) {
686
0
        const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle;
687
0
        const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
688
0
    }
689
0
    RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
690
0
    aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
691
0
    rRect=tools::Rectangle(aTextPos,aTextSize2);
692
0
    rRect.Normalize();
693
0
    const_cast<SdrMeasureObj*>(this)->setRectangle(rRect);
694
695
0
    if (aMPol.nTextAngle != maGeo.m_nRotationAngle) {
696
0
        const_cast<SdrMeasureObj*>(this)->maGeo.m_nRotationAngle=aMPol.nTextAngle;
697
0
        const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
698
0
    }
699
0
}
700
701
rtl::Reference<SdrObject> SdrMeasureObj::CloneSdrObject(SdrModel& rTargetModel) const
702
0
{
703
0
    return new SdrMeasureObj(rTargetModel, *this);
704
0
}
705
706
OUString SdrMeasureObj::TakeObjNameSingul() const
707
0
{
708
0
    OUString sName(SvxResId(STR_ObjNameSingulMEASURE));
709
710
0
    OUString aName( GetName() );
711
0
    if (!aName.isEmpty())
712
0
        sName += " '" + aName + "'";
713
714
0
    return sName;
715
0
}
716
717
OUString SdrMeasureObj::TakeObjNamePlural() const
718
0
{
719
0
    return SvxResId(STR_ObjNamePluralMEASURE);
720
0
}
721
722
basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
723
0
{
724
0
    ImpMeasureRec aRec;
725
0
    ImpMeasurePoly aMPol;
726
0
    ImpTakeAttr(aRec);
727
0
    ImpCalcGeometrics(aRec,aMPol);
728
0
    return ImpCalcXPoly(aMPol);
729
0
}
730
731
sal_uInt32 SdrMeasureObj::GetHdlCount() const
732
0
{
733
0
    return 6;
734
0
}
735
736
void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
737
0
{
738
0
    ImpMeasureRec aRec;
739
0
    ImpMeasurePoly aMPol;
740
0
    ImpTakeAttr(aRec);
741
0
    aRec.nHelplineDist=0;
742
0
    ImpCalcGeometrics(aRec,aMPol);
743
744
0
    for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
745
0
    {
746
0
        Point aPt;
747
0
        switch (nHdlNum) {
748
0
            case 0: aPt=aMPol.aHelpline1.aP1; break;
749
0
            case 1: aPt=aMPol.aHelpline2.aP1; break;
750
0
            case 2: aPt=m_aPt1;       break;
751
0
            case 3: aPt=m_aPt2;       break;
752
0
            case 4: aPt=aMPol.aHelpline1.aP2; break;
753
0
            case 5: aPt=aMPol.aHelpline2.aP2; break;
754
0
        } // switch
755
0
        std::unique_ptr<SdrHdl> pHdl(new ImpMeasureHdl(aPt,SdrHdlKind::User));
756
0
        pHdl->SetObjHdlNum(nHdlNum);
757
0
        pHdl->SetRotationAngle(aMPol.nLineAngle);
758
0
        rHdlList.AddHdl(std::move(pHdl));
759
0
    }
760
0
}
761
762
763
bool SdrMeasureObj::hasSpecialDrag() const
764
0
{
765
0
    return true;
766
0
}
767
768
bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
769
0
{
770
0
    const SdrHdl* pHdl = rDrag.GetHdl();
771
772
0
    if(pHdl)
773
0
    {
774
0
        const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
775
776
0
        if(nHdlNum != 2 && nHdlNum != 3)
777
0
        {
778
0
            rDrag.SetEndDragChangesAttributes(true);
779
0
        }
780
781
0
        return true;
782
0
    }
783
784
0
    return false;
785
0
}
786
787
bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
788
0
{
789
0
    ImpMeasureRec aMeasureRec;
790
0
    const SdrHdl* pHdl = rDrag.GetHdl();
791
0
    const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
792
793
0
    ImpTakeAttr(aMeasureRec);
794
0
    ImpEvalDrag(aMeasureRec, rDrag);
795
796
0
    switch (nHdlNum)
797
0
    {
798
0
        case 2:
799
0
        {
800
0
            m_aPt1 = aMeasureRec.aPt1;
801
0
            SetTextDirty();
802
0
            break;
803
0
        }
804
0
        case 3:
805
0
        {
806
0
            m_aPt2 = aMeasureRec.aPt2;
807
0
            SetTextDirty();
808
0
            break;
809
0
        }
810
0
        default:
811
0
        {
812
0
            switch(nHdlNum)
813
0
            {
814
0
                case 0:
815
0
                case 1:
816
0
                {
817
0
                    ImpMeasureRec aOrigMeasureRec;
818
0
                    ImpTakeAttr(aOrigMeasureRec);
819
820
0
                    if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
821
0
                    {
822
0
                        SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
823
0
                    }
824
825
0
                    if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
826
0
                    {
827
0
                        SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
828
0
                    }
829
830
0
                    break;
831
0
                }
832
833
0
                case 4:
834
0
                case 5:
835
0
                {
836
0
                    ImpMeasureRec aOrigMeasureRec;
837
0
                    ImpTakeAttr(aOrigMeasureRec);
838
839
0
                    if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
840
0
                    {
841
0
                        SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
842
0
                    }
843
844
0
                    if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
845
0
                    {
846
0
                        SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
847
0
                    }
848
0
                }
849
0
            }
850
0
        }
851
0
    } // switch
852
853
0
    SetBoundAndSnapRectsDirty();
854
0
    SetChanged();
855
856
0
    return true;
857
0
}
858
859
OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
860
0
{
861
0
    return OUString();
862
0
}
863
864
void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
865
0
{
866
0
    Degree100 nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
867
0
    double a = toRadians(nLineAngle);
868
0
    double nSin=sin(a);
869
0
    double nCos=cos(a);
870
871
0
    const SdrHdl* pHdl=rDrag.GetHdl();
872
0
    sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
873
0
    bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
874
0
    bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
875
0
    bool bBelow=rRec.bBelowRefEdge;
876
0
    Point aPt(rDrag.GetNow());
877
878
0
    switch (nHdlNum) {
879
0
        case 0: {
880
0
            RotatePoint(aPt,m_aPt1,nSin,-nCos);
881
0
            rRec.nHelpline1Len=m_aPt1.Y()-aPt.Y();
882
0
            if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
883
0
            if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
884
0
        } break;
885
0
        case 1: {
886
0
            RotatePoint(aPt,m_aPt2,nSin,-nCos);
887
0
            rRec.nHelpline2Len=m_aPt2.Y()-aPt.Y();
888
0
            if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
889
0
            if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
890
0
        } break;
891
0
        case 2: case 3: {
892
0
            bool bAnf=nHdlNum==2;
893
0
            Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
894
0
            Point aMov(rMov);
895
0
            Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
896
0
            if (bOrtho) {
897
0
                tools::Long ndx0=aMov.X()-aFix.X();
898
0
                tools::Long ndy0=aMov.Y()-aFix.Y();
899
0
                bool bHLin=ndy0==0;
900
0
                bool bVLin=ndx0==0;
901
0
                if (!bHLin || !bVLin) { // else aPt1==aPt2
902
0
                    tools::Long ndx=aPt.X()-aFix.X();
903
0
                    tools::Long ndy=aPt.Y()-aFix.Y();
904
0
                    double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
905
0
                    double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
906
0
                    bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
907
0
                    bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
908
0
                    if (bHor) ndy=tools::Long(ndy0*nXFact);
909
0
                    if (bVer) ndx=tools::Long(ndx0*nYFact);
910
0
                    aPt=aFix;
911
0
                    aPt.AdjustX(ndx );
912
0
                    aPt.AdjustY(ndy );
913
0
                } // else Ortho8
914
0
            }
915
0
            rMov=aPt;
916
0
        } break;
917
0
        case 4: case 5: {
918
0
            tools::Long nVal0=rRec.nLineDist;
919
0
            RotatePoint(aPt,(nHdlNum==4 ? m_aPt1 : m_aPt2),nSin,-nCos);
920
0
            rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? m_aPt1.Y() : m_aPt2.Y());
921
0
            if (bBelow) rRec.nLineDist=-rRec.nLineDist;
922
0
            if (rRec.nLineDist<0) {
923
0
                rRec.nLineDist=-rRec.nLineDist;
924
0
                rRec.bBelowRefEdge=!bBelow;
925
0
            }
926
0
            rRec.nLineDist-=rRec.nHelplineOverhang;
927
0
            if (bOrtho) rRec.nLineDist=nVal0;
928
0
        } break;
929
0
    } // switch
930
0
}
931
932
933
bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
934
0
{
935
0
    rStat.SetOrtho8Possible();
936
0
    m_aPt1=rStat.GetStart();
937
0
    m_aPt2=rStat.GetNow();
938
0
    SetTextDirty();
939
0
    return true;
940
0
}
941
942
bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
943
0
{
944
0
    SdrView* pView=rStat.GetView();
945
0
    m_aPt1=rStat.GetStart();
946
0
    m_aPt2=rStat.GetNow();
947
0
    if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
948
0
        m_aPt1+=m_aPt1;
949
0
        m_aPt1-=rStat.GetNow();
950
0
    }
951
0
    SetTextDirty();
952
0
    SetBoundRectDirty();
953
0
    m_bSnapRectDirty=true;
954
0
    return true;
955
0
}
956
957
bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
958
0
{
959
0
    SetTextDirty();
960
0
    SetBoundAndSnapRectsDirty();
961
0
    return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
962
0
}
963
964
bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
965
0
{
966
0
    return false;
967
0
}
968
969
void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
970
0
{
971
0
}
972
973
basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
974
0
{
975
0
    ImpMeasureRec aRec;
976
0
    ImpMeasurePoly aMPol;
977
978
0
    ImpTakeAttr(aRec);
979
0
    ImpCalcGeometrics(aRec, aMPol);
980
981
0
    return ImpCalcXPoly(aMPol);
982
0
}
983
984
PointerStyle SdrMeasureObj::GetCreatePointer() const
985
0
{
986
0
    return PointerStyle::Cross;
987
0
}
988
989
void SdrMeasureObj::NbcMove(const Size& rSiz)
990
0
{
991
0
    SdrTextObj::NbcMove(rSiz);
992
0
    m_aPt1.Move(rSiz);
993
0
    m_aPt2.Move(rSiz);
994
0
}
995
996
void SdrMeasureObj::NbcResize(const Point& rRef, double xFact, double yFact)
997
0
{
998
0
    SdrTextObj::NbcResize(rRef,xFact,yFact);
999
0
    ResizePoint(m_aPt1,rRef,xFact,yFact);
1000
0
    ResizePoint(m_aPt2,rRef,xFact,yFact);
1001
0
    SetTextDirty();
1002
0
}
1003
1004
void SdrMeasureObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
1005
0
{
1006
0
    SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
1007
0
    tools::Long nLen0=GetLen(m_aPt2-m_aPt1);
1008
0
    RotatePoint(m_aPt1,rRef,sn,cs);
1009
0
    RotatePoint(m_aPt2,rRef,sn,cs);
1010
0
    tools::Long nLen1=GetLen(m_aPt2-m_aPt1);
1011
0
    if (nLen1!=nLen0) { // rounding error!
1012
0
        tools::Long dx=m_aPt2.X()-m_aPt1.X();
1013
0
        tools::Long dy=m_aPt2.Y()-m_aPt1.Y();
1014
0
        dx=BigMulDiv(dx,nLen0,nLen1);
1015
0
        dy=BigMulDiv(dy,nLen0,nLen1);
1016
0
        if (rRef==m_aPt2) {
1017
0
            m_aPt1.setX(m_aPt2.X()-dx );
1018
0
            m_aPt1.setY(m_aPt2.Y()-dy );
1019
0
        } else {
1020
0
            m_aPt2.setX(m_aPt1.X()+dx );
1021
0
            m_aPt2.setY(m_aPt1.Y()+dy );
1022
0
        }
1023
0
    }
1024
0
    SetBoundAndSnapRectsDirty();
1025
0
}
1026
1027
void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1028
0
{
1029
0
    SdrTextObj::NbcMirror(rRef1,rRef2);
1030
0
    MirrorPoint(m_aPt1,rRef1,rRef2);
1031
0
    MirrorPoint(m_aPt2,rRef1,rRef2);
1032
0
    SetBoundAndSnapRectsDirty();
1033
0
}
1034
1035
void SdrMeasureObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
1036
0
{
1037
0
    SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
1038
0
    ShearPoint(m_aPt1,rRef,tn,bVShear);
1039
0
    ShearPoint(m_aPt2,rRef,tn,bVShear);
1040
0
    SetBoundAndSnapRectsDirty();
1041
0
    SetTextDirty();
1042
0
}
1043
1044
Degree100 SdrMeasureObj::GetRotateAngle() const
1045
0
{
1046
0
    return GetAngle(m_aPt2-m_aPt1);
1047
0
}
1048
1049
void SdrMeasureObj::RecalcSnapRect()
1050
0
{
1051
0
    ImpMeasureRec aRec;
1052
0
    ImpMeasurePoly aMPol;
1053
0
    XPolyPolygon aXPP;
1054
1055
0
    ImpTakeAttr(aRec);
1056
0
    ImpCalcGeometrics(aRec, aMPol);
1057
0
    aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1058
0
    maSnapRect = aXPP.GetBoundRect();
1059
0
}
1060
1061
sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1062
0
{
1063
0
    return 2;
1064
0
}
1065
1066
Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1067
0
{
1068
0
    if (i==0) return m_aPt1;
1069
0
    else return m_aPt2;
1070
0
}
1071
1072
bool SdrMeasureObj::IsPolyObj() const
1073
0
{
1074
0
    return true;
1075
0
}
1076
1077
sal_uInt32 SdrMeasureObj::GetPointCount() const
1078
0
{
1079
0
    return 2;
1080
0
}
1081
1082
Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1083
0
{
1084
0
     return (0 == i) ? m_aPt1 : m_aPt2;
1085
0
}
1086
1087
void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1088
0
{
1089
0
    if (0 == i)
1090
0
        m_aPt1=rPnt;
1091
0
    if (1 == i)
1092
0
        m_aPt2=rPnt;
1093
0
    SetBoundAndSnapRectsDirty();
1094
0
    SetTextDirty();
1095
0
}
1096
1097
std::unique_ptr<SdrObjGeoData> SdrMeasureObj::NewGeoData() const
1098
0
{
1099
0
    return std::make_unique<SdrMeasureObjGeoData>();
1100
0
}
1101
1102
void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1103
0
{
1104
0
    SdrTextObj::SaveGeoData(rGeo);
1105
0
    SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
1106
0
    rMGeo.aPt1=m_aPt1;
1107
0
    rMGeo.aPt2=m_aPt2;
1108
0
}
1109
1110
void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData& rGeo)
1111
0
{
1112
0
    SdrTextObj::RestoreGeoData(rGeo);
1113
0
    const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
1114
0
    m_aPt1=rMGeo.aPt1;
1115
0
    m_aPt2=rMGeo.aPt2;
1116
0
    SetTextDirty();
1117
0
}
1118
1119
rtl::Reference<SdrObject> SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
1120
0
{
1121
    // get XOR Poly as base
1122
0
    XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1123
1124
    // get local ItemSet and StyleSheet
1125
0
    SfxItemSet aSet(GetObjectItemSet());
1126
0
    SfxStyleSheet* pStyleSheet = GetStyleSheet();
1127
1128
    // prepare group
1129
0
    rtl::Reference<SdrObjGroup> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
1130
1131
    // prepare parameters
1132
0
    basegfx::B2DPolyPolygon aPolyPoly;
1133
0
    rtl::Reference<SdrPathObj> pPath;
1134
0
    sal_uInt16 nCount(aTmpPolyPolygon.Count());
1135
0
    sal_uInt16 nLoopStart(0);
1136
1137
0
    if(nCount == 3)
1138
0
    {
1139
        // three lines, first one is the middle one
1140
0
        aPolyPoly.clear();
1141
0
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1142
1143
0
        pPath = new SdrPathObj(
1144
0
            getSdrModelFromSdrObject(),
1145
0
            SdrObjKind::PathLine,
1146
0
            aPolyPoly);
1147
1148
0
        pPath->SetMergedItemSet(aSet);
1149
0
        pPath->SetStyleSheet(pStyleSheet, true);
1150
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1151
0
        aSet.Put(XLineStartWidthItem(0));
1152
0
        aSet.Put(XLineEndWidthItem(0));
1153
0
        nLoopStart = 1;
1154
0
    }
1155
0
    else if(nCount == 4)
1156
0
    {
1157
        // four lines, middle line with gap, so there are two lines used
1158
        // which have one arrow each
1159
0
        sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
1160
0
        aSet.Put(XLineEndWidthItem(0));
1161
1162
0
        aPolyPoly.clear();
1163
0
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1164
0
        pPath = new SdrPathObj(
1165
0
            getSdrModelFromSdrObject(),
1166
0
            SdrObjKind::PathLine,
1167
0
            aPolyPoly);
1168
1169
0
        pPath->SetMergedItemSet(aSet);
1170
0
        pPath->SetStyleSheet(pStyleSheet, true);
1171
1172
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1173
1174
0
        aSet.Put(XLineEndWidthItem(nEndWidth));
1175
0
        aSet.Put(XLineStartWidthItem(0));
1176
1177
0
        aPolyPoly.clear();
1178
0
        aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1179
0
        pPath = new SdrPathObj(
1180
0
            getSdrModelFromSdrObject(),
1181
0
            SdrObjKind::PathLine,
1182
0
            aPolyPoly);
1183
1184
0
        pPath->SetMergedItemSet(aSet);
1185
0
        pPath->SetStyleSheet(pStyleSheet, true);
1186
1187
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1188
1189
0
        aSet.Put(XLineEndWidthItem(0));
1190
0
        nLoopStart = 2;
1191
0
    }
1192
0
    else if(nCount == 5)
1193
0
    {
1194
        // five lines, first two are the outer ones
1195
0
        sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
1196
1197
0
        aSet.Put(XLineEndWidthItem(0));
1198
1199
0
        aPolyPoly.clear();
1200
0
        aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1201
0
        pPath = new SdrPathObj(
1202
0
            getSdrModelFromSdrObject(),
1203
0
            SdrObjKind::PathLine,
1204
0
            aPolyPoly);
1205
1206
0
        pPath->SetMergedItemSet(aSet);
1207
0
        pPath->SetStyleSheet(pStyleSheet, true);
1208
1209
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1210
1211
0
        aSet.Put(XLineEndWidthItem(nEndWidth));
1212
0
        aSet.Put(XLineStartWidthItem(0));
1213
1214
0
        aPolyPoly.clear();
1215
0
        aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1216
0
        pPath = new SdrPathObj(
1217
0
            getSdrModelFromSdrObject(),
1218
0
            SdrObjKind::PathLine,
1219
0
            aPolyPoly);
1220
1221
0
        pPath->SetMergedItemSet(aSet);
1222
0
        pPath->SetStyleSheet(pStyleSheet, true);
1223
1224
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1225
1226
0
        aSet.Put(XLineEndWidthItem(0));
1227
0
        nLoopStart = 2;
1228
0
    }
1229
1230
0
    for(;nLoopStart<nCount;nLoopStart++)
1231
0
    {
1232
0
        aPolyPoly.clear();
1233
0
        aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1234
0
        pPath = new SdrPathObj(
1235
0
            getSdrModelFromSdrObject(),
1236
0
            SdrObjKind::PathLine,
1237
0
            aPolyPoly);
1238
1239
0
        pPath->SetMergedItemSet(aSet);
1240
0
        pPath->SetStyleSheet(pStyleSheet, true);
1241
1242
0
        pGroup->GetSubList()->NbcInsertObject(pPath.get());
1243
0
    }
1244
1245
0
    if(bAddText)
1246
0
    {
1247
0
        return ImpConvertAddText(std::move(pGroup), bBezier);
1248
0
    }
1249
0
    else
1250
0
    {
1251
0
        return pGroup;
1252
0
    }
1253
0
}
1254
1255
bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1256
0
{
1257
0
    UndirtyText();
1258
0
    return SdrTextObj::BegTextEdit(rOutl);
1259
0
}
1260
1261
const Size& SdrMeasureObj::GetTextSize() const
1262
0
{
1263
0
    if (m_bTextDirty) UndirtyText();
1264
0
    return SdrTextObj::GetTextSize();
1265
0
}
1266
1267
OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1268
0
{
1269
0
    if(m_bTextDirty)
1270
0
        UndirtyText();
1271
0
    return SdrTextObj::GetOutlinerParaObject();
1272
0
}
1273
1274
void SdrMeasureObj::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject, bool bAdjustTextFrameWidthAndHeight)
1275
0
{
1276
0
    SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject), bAdjustTextFrameWidthAndHeight);
1277
0
    if(SdrTextObj::GetOutlinerParaObject())
1278
0
        SetTextDirty(); // recalculate text
1279
0
}
1280
1281
void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
1282
    tools::Rectangle* pAnchorRect, bool bLineWidth ) const
1283
0
{
1284
0
    if (m_bTextDirty) UndirtyText();
1285
0
    SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1286
0
}
1287
1288
void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
1289
0
{
1290
0
    if (m_bTextDirty) UndirtyText();
1291
0
    SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1292
0
}
1293
1294
void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
1295
0
{
1296
0
    if (m_bTextDirty) UndirtyText();
1297
0
    SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1298
0
}
1299
1300
EEAnchorMode SdrMeasureObj::GetOutlinerViewAnchorMode() const
1301
0
{
1302
0
    if (m_bTextDirty) UndirtyText();
1303
0
    ImpMeasureRec aRec;
1304
0
    ImpMeasurePoly aMPol;
1305
0
    ImpTakeAttr(aRec);
1306
0
    ImpCalcGeometrics(aRec,aMPol);
1307
1308
0
    SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1309
0
    SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1310
0
    css::drawing::MeasureTextHorzPos eMH = aMPol.eUsedTextHPos;
1311
0
    css::drawing::MeasureTextVertPos eMV = aMPol.eUsedTextVPos;
1312
0
    bool bTextRota90=aRec.bTextRota90;
1313
0
    bool bBelowRefEdge=aRec.bBelowRefEdge;
1314
1315
    // TODO: bTextUpsideDown should be interpreted here!
1316
0
    if (!bTextRota90) {
1317
0
        if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1318
0
        if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1319
        // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
1320
0
        if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM;
1321
0
        if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP;
1322
0
        if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
1323
0
    } else {
1324
0
        if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1325
0
        if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
1326
        // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
1327
0
        if (!bBelowRefEdge) {
1328
0
            if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT;
1329
0
            if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
1330
0
        } else {
1331
0
            if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT;
1332
0
            if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
1333
0
        }
1334
0
        if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1335
0
    }
1336
1337
0
    EEAnchorMode eRet=EEAnchorMode::BottomHCenter;
1338
0
    if (eTH==SDRTEXTHORZADJUST_LEFT) {
1339
0
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft;
1340
0
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft;
1341
0
        else eRet=EEAnchorMode::VCenterLeft;
1342
0
    } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
1343
0
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight;
1344
0
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight;
1345
0
        else eRet=EEAnchorMode::VCenterRight;
1346
0
    } else {
1347
0
        if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
1348
0
        else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
1349
0
        else eRet=EEAnchorMode::VCenterHCenter;
1350
0
    }
1351
0
    return eRet;
1352
0
}
1353
1354
1355
// #i97878#
1356
// TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1357
// same as line geometry in SdrPathObj. Thus needs to be overridden and
1358
// implemented since currently it is derived from SdrTextObj which uses
1359
// a functionality based on SnapRect which is not useful here
1360
1361
bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1362
0
{
1363
    // handle the same as a simple line since the definition is based on two points
1364
0
    const basegfx::B2DRange aRange(m_aPt1.X(), m_aPt1.Y(), m_aPt2.X(), m_aPt2.Y());
1365
0
    basegfx::B2DTuple aScale(aRange.getRange());
1366
0
    basegfx::B2DTuple aTranslate(aRange.getMinimum());
1367
1368
    // position maybe relative to anchor position, convert
1369
0
    if( getSdrModelFromSdrObject().IsWriter() )
1370
0
    {
1371
0
        if(GetAnchorPos().X() || GetAnchorPos().Y())
1372
0
        {
1373
0
            aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1374
0
        }
1375
0
    }
1376
1377
    // build return value matrix
1378
0
    rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1379
1380
0
    return true;
1381
0
}
1382
1383
void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1384
0
{
1385
    // use given transformation to derive the two defining points from unit line
1386
0
    basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1387
0
    basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1388
1389
0
    if( getSdrModelFromSdrObject().IsWriter() )
1390
0
    {
1391
        // if anchor is used, make position relative to it
1392
0
        if(GetAnchorPos().X() || GetAnchorPos().Y())
1393
0
        {
1394
0
            const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1395
1396
0
            aPosA += aAnchorOffset;
1397
0
            aPosB += aAnchorOffset;
1398
0
        }
1399
0
    }
1400
1401
    // derive new model data
1402
0
    const Point aNewPt1(basegfx::fround<tools::Long>(aPosA.getX()), basegfx::fround<tools::Long>(aPosA.getY()));
1403
0
    const Point aNewPt2(basegfx::fround<tools::Long>(aPosB.getX()), basegfx::fround<tools::Long>(aPosB.getY()));
1404
1405
0
    if(aNewPt1 == m_aPt1 && aNewPt2 == m_aPt2)
1406
0
        return;
1407
1408
    // set model values and broadcast
1409
0
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1410
1411
0
    m_aPt1 = aNewPt1;
1412
0
    m_aPt2 = aNewPt2;
1413
1414
0
    SetTextDirty();
1415
0
    ActionChanged();
1416
0
    SetChanged();
1417
0
    BroadcastObjectChange();
1418
0
    SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1419
0
}
1420
1421
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */