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/svdtrans.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
21
#include <svx/svdtrans.hxx>
22
#include <math.h>
23
#include <svx/xpoly.hxx>
24
#include <rtl/ustrbuf.hxx>
25
26
#include <vcl/virdev.hxx>
27
#include <tools/bigint.hxx>
28
#include <tools/UnitConversion.hxx>
29
#include <unotools/syslocale.hxx>
30
#include <unotools/localedatawrapper.hxx>
31
#include <sal/log.hxx>
32
33
void MoveXPoly(XPolygon& rPoly, const Size& S)
34
2.84k
{
35
2.84k
    rPoly.Move(S.Width(),S.Height());
36
2.84k
}
37
38
void ResizeRect(tools::Rectangle& rRect, const Point& rRef, double aXFact, double aYFact)
39
6.20k
{
40
6.20k
    rRect.SetLeft( rRef.X() + basegfx::fround<tools::Long>( (rRect.Left()  - rRef.X()) * aXFact ) );
41
6.20k
    rRect.SetRight( rRef.X() + basegfx::fround<tools::Long>( (rRect.Right() - rRef.X()) * aXFact ) );
42
43
6.20k
    rRect.SetTop( rRef.Y() + basegfx::fround<tools::Long>( (rRect.Top()    - rRef.Y()) * aYFact ) );
44
6.20k
    rRect.SetBottom( rRef.Y() + basegfx::fround<tools::Long>( (rRect.Bottom() - rRef.Y()) * aYFact ) );
45
46
6.20k
    rRect.Normalize();
47
6.20k
}
48
49
void ResizePoly(tools::Polygon& rPoly, const Point& rRef, double xFact, double yFact)
50
0
{
51
0
    sal_uInt16 nCount=rPoly.GetSize();
52
0
    for (sal_uInt16 i=0; i<nCount; i++) {
53
0
        ResizePoint(rPoly[i],rRef,xFact,yFact);
54
0
    }
55
0
}
56
57
void ResizeXPoly(XPolygon& rPoly, const Point& rRef, double xFact, double yFact)
58
4.43k
{
59
4.43k
    sal_uInt16 nCount=rPoly.GetPointCount();
60
915k
    for (sal_uInt16 i=0; i<nCount; i++) {
61
910k
        ResizePoint(rPoly[i],rRef,xFact,yFact);
62
910k
    }
63
4.43k
}
64
65
void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs)
66
71.9k
{
67
71.9k
    sal_uInt16 nCount=rPoly.GetSize();
68
431k
    for (sal_uInt16 i=0; i<nCount; i++) {
69
359k
        RotatePoint(rPoly[i],rRef,sn,cs);
70
359k
    }
71
71.9k
}
72
73
void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
74
282
{
75
282
    sal_uInt16 nCount=rPoly.GetPointCount();
76
886
    for (sal_uInt16 i=0; i<nCount; i++) {
77
604
        RotatePoint(rPoly[i],rRef,sn,cs);
78
604
    }
79
282
}
80
81
void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
82
0
{
83
0
    sal_uInt16 nCount=rPoly.Count();
84
0
    for (sal_uInt16 i=0; i<nCount; i++) {
85
0
        RotateXPoly(rPoly[i],rRef,sn,cs);
86
0
    }
87
0
}
88
89
void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
90
477k
{
91
477k
    tools::Long mx=rRef2.X()-rRef1.X();
92
477k
    tools::Long my=rRef2.Y()-rRef1.Y();
93
477k
    if (mx==0) { // vertical axis
94
232k
        tools::Long dx=rRef1.X()-rPnt.X();
95
232k
        rPnt.AdjustX(2*dx );
96
245k
    } else if (my==0) { // horizontal axis
97
245k
        tools::Long dy=rRef1.Y()-rPnt.Y();
98
245k
        rPnt.AdjustY(2*dy );
99
245k
    } else if (mx==my) { // diagonal axis '\'
100
0
        tools::Long dx1=rPnt.X()-rRef1.X();
101
0
        tools::Long dy1=rPnt.Y()-rRef1.Y();
102
0
        rPnt.setX(rRef1.X()+dy1 );
103
0
        rPnt.setY(rRef1.Y()+dx1 );
104
0
    } else if (mx==-my) { // diagonal axis '/'
105
0
        tools::Long dx1=rPnt.X()-rRef1.X();
106
0
        tools::Long dy1=rPnt.Y()-rRef1.Y();
107
0
        rPnt.setX(rRef1.X()-dy1 );
108
0
        rPnt.setY(rRef1.Y()-dx1 );
109
0
    } else { // arbitrary axis
110
        // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
111
0
        Degree100 nRefAngle=GetAngle(rRef2-rRef1);
112
0
        rPnt-=rRef1;
113
0
        Degree100 nPntAngle=GetAngle(rPnt);
114
0
        Degree100 nAngle=2_deg100*(nRefAngle-nPntAngle);
115
0
        double a = toRadians(nAngle);
116
0
        double nSin=sin(a);
117
0
        double nCos=cos(a);
118
0
        RotatePoint(rPnt,Point(),nSin,nCos);
119
0
        rPnt+=rRef1;
120
0
    }
121
477k
}
122
123
void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
124
763
{
125
763
    sal_uInt16 nCount=rPoly.GetPointCount();
126
2.69k
    for (sal_uInt16 i=0; i<nCount; i++) {
127
1.93k
        MirrorPoint(rPoly[i],rRef1,rRef2);
128
1.93k
    }
129
763
}
130
131
void ShearPoly(tools::Polygon& rPoly, const Point& rRef, double tn)
132
54
{
133
54
    sal_uInt16 nCount=rPoly.GetSize();
134
324
    for (sal_uInt16 i=0; i<nCount; i++) {
135
270
        ShearPoint(rPoly[i],rRef,tn);
136
270
    }
137
54
}
138
139
void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
140
0
{
141
0
    sal_uInt16 nCount=rPoly.GetPointCount();
142
0
    for (sal_uInt16 i=0; i<nCount; i++) {
143
0
        ShearPoint(rPoly[i],rRef,tn,bVShear);
144
0
    }
145
0
}
146
147
double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
148
                         const Point& rRad, double& rSin, double& rCos, bool bVert)
149
0
{
150
0
    bool bC1=pC1!=nullptr;
151
0
    bool bC2=pC2!=nullptr;
152
0
    tools::Long x0=rPnt.X();
153
0
    tools::Long y0=rPnt.Y();
154
0
    tools::Long cx=rCenter.X();
155
0
    tools::Long cy=rCenter.Y();
156
0
    double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
157
0
    double sn=sin(nAngle);
158
0
    double cs=cos(nAngle);
159
0
    RotatePoint(rPnt,rCenter,sn,cs);
160
0
    if (bC1) {
161
0
        if (bVert) {
162
            // move into the direction of the center, as a basic position for the rotation
163
0
            pC1->AdjustY( -y0 );
164
            // resize, account for the distance from the center
165
0
            pC1->setY(basegfx::fround<tools::Long>(static_cast<double>(pC1->Y()) /rRad.X()*(cx-pC1->X())) );
166
0
            pC1->AdjustY(cy );
167
0
        } else {
168
            // move into the direction of the center, as a basic position for the rotation
169
0
            pC1->AdjustX( -x0 );
170
            // resize, account for the distance from the center
171
0
            tools::Long nPntRad=cy-pC1->Y();
172
0
            double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y());
173
0
            pC1->setX(basegfx::fround<tools::Long>(static_cast<double>(pC1->X()) * nFact));
174
0
            pC1->AdjustX(cx );
175
0
        }
176
0
        RotatePoint(*pC1,rCenter,sn,cs);
177
0
    }
178
0
    if (bC2) {
179
0
        if (bVert) {
180
            // move into the direction of the center, as a basic position for the rotation
181
0
            pC2->AdjustY( -y0 );
182
            // resize, account for the distance from the center
183
0
            pC2->setY(basegfx::fround<tools::Long>(static_cast<double>(pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X())) );
184
0
            pC2->AdjustY(cy );
185
0
        } else {
186
            // move into the direction of the center, as a basic position for the rotation
187
0
            pC2->AdjustX( -x0 );
188
            // resize, account for the distance from the center
189
0
            tools::Long nPntRad=rCenter.Y()-pC2->Y();
190
0
            double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y());
191
0
            pC2->setX(basegfx::fround<tools::Long>(static_cast<double>(pC2->X()) * nFact));
192
0
            pC2->AdjustX(cx );
193
0
        }
194
0
        RotatePoint(*pC2,rCenter,sn,cs);
195
0
    }
196
0
    rSin=sn;
197
0
    rCos=cs;
198
0
    return nAngle;
199
0
}
200
201
double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
202
                        const Point& rRad, double& rSin, double& rCos, bool bVert)
203
0
{
204
0
    bool bC1=pC1!=nullptr;
205
0
    bool bC2=pC2!=nullptr;
206
0
    tools::Long x0=rPnt.X();
207
0
    tools::Long y0=rPnt.Y();
208
0
    tools::Long dx1=0,dy1=0;
209
0
    tools::Long dxC1=0,dyC1=0;
210
0
    tools::Long dxC2=0,dyC2=0;
211
0
    if (bVert) {
212
0
        tools::Long nStart=rCenter.X()-rRad.X();
213
0
        dx1=rPnt.X()-nStart;
214
0
        rPnt.setX(nStart );
215
0
        if (bC1) {
216
0
            dxC1=pC1->X()-nStart;
217
0
            pC1->setX(nStart );
218
0
        }
219
0
        if (bC2) {
220
0
            dxC2=pC2->X()-nStart;
221
0
            pC2->setX(nStart );
222
0
        }
223
0
    } else {
224
0
        tools::Long nStart=rCenter.Y()-rRad.Y();
225
0
        dy1=rPnt.Y()-nStart;
226
0
        rPnt.setY(nStart );
227
0
        if (bC1) {
228
0
            dyC1=pC1->Y()-nStart;
229
0
            pC1->setY(nStart );
230
0
        }
231
0
        if (bC2) {
232
0
            dyC2=pC2->Y()-nStart;
233
0
            pC2->setY(nStart );
234
0
        }
235
0
    }
236
0
    double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
237
0
    double sn=sin(nAngle);
238
0
    double cs=cos(nAngle);
239
0
    RotatePoint(rPnt,rCenter,sn,cs);
240
0
    if (bC1) { if (bVert) pC1->AdjustY( -(y0-rCenter.Y()) ); else pC1->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC1,rCenter,sn,cs); }
241
0
    if (bC2) { if (bVert) pC2->AdjustY( -(y0-rCenter.Y()) ); else pC2->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC2,rCenter,sn,cs); }
242
0
    if (bVert) {
243
0
        rPnt.AdjustX(dx1 );
244
0
        if (bC1) pC1->AdjustX(dxC1 );
245
0
        if (bC2) pC2->AdjustX(dxC2 );
246
0
    } else {
247
0
        rPnt.AdjustY(dy1 );
248
0
        if (bC1) pC1->AdjustY(dyC1 );
249
0
        if (bC2) pC2->AdjustY(dyC2 );
250
0
    }
251
0
    rSin=sn;
252
0
    rCos=cs;
253
0
    return nAngle;
254
0
}
255
256
double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
257
                          const Point& rRad, double& rSin, double& rCos, bool bVert,
258
                          const tools::Rectangle& rRefRect)
259
0
{
260
0
    tools::Long y0=rPnt.Y();
261
0
    CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
262
0
    if (bVert) {
263
0
    } else {
264
0
        tools::Long nTop=rRefRect.Top();
265
0
        tools::Long nBtm=rRefRect.Bottom();
266
0
        tools::Long nHgt=nBtm-nTop;
267
0
        tools::Long dy=rPnt.Y()-y0;
268
0
        double a=static_cast<double>(y0-nTop)/nHgt;
269
0
        a*=dy;
270
0
        rPnt.setY(y0 + basegfx::fround<tools::Long>(a));
271
0
    }
272
0
    return 0.0;
273
0
}
274
275
276
void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
277
0
{
278
0
    double nSin,nCos;
279
0
    sal_uInt16 nPointCnt=rPoly.GetPointCount();
280
0
    sal_uInt16 i=0;
281
0
    while (i<nPointCnt) {
282
0
        Point* pPnt=&rPoly[i];
283
0
        Point* pC1=nullptr;
284
0
        Point* pC2=nullptr;
285
0
        if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
286
0
            pC1=pPnt;
287
0
            i++;
288
0
            pPnt=&rPoly[i];
289
0
        }
290
0
        i++;
291
0
        if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
292
0
            pC2=&rPoly[i];
293
0
            i++;
294
0
        }
295
0
        CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
296
0
    }
297
0
}
298
299
void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
300
0
{
301
0
    double nSin,nCos;
302
0
    sal_uInt16 nPointCnt=rPoly.GetPointCount();
303
0
    sal_uInt16 i=0;
304
0
    while (i<nPointCnt) {
305
0
        Point* pPnt=&rPoly[i];
306
0
        Point* pC1=nullptr;
307
0
        Point* pC2=nullptr;
308
0
        if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
309
0
            pC1=pPnt;
310
0
            i++;
311
0
            pPnt=&rPoly[i];
312
0
        }
313
0
        i++;
314
0
        if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
315
0
            pC2=&rPoly[i];
316
0
            i++;
317
0
        }
318
0
        CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
319
0
    }
320
0
}
321
322
void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
323
0
{
324
0
    double nSin,nCos;
325
0
    sal_uInt16 nPointCnt=rPoly.GetPointCount();
326
0
    sal_uInt16 i=0;
327
0
    while (i<nPointCnt) {
328
0
        Point* pPnt=&rPoly[i];
329
0
        Point* pC1=nullptr;
330
0
        Point* pC2=nullptr;
331
0
        if (i+1<nPointCnt && rPoly.IsControl(i)) { //  control point to the left
332
0
            pC1=pPnt;
333
0
            i++;
334
0
            pPnt=&rPoly[i];
335
0
        }
336
0
        i++;
337
0
        if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
338
0
            pC2=&rPoly[i];
339
0
            i++;
340
0
        }
341
0
        CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
342
0
    }
343
0
}
344
345
346
void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
347
0
{
348
0
    sal_uInt16 nPolyCount=rPoly.Count();
349
0
    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
350
0
        CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
351
0
    }
352
0
}
353
354
void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
355
0
{
356
0
    sal_uInt16 nPolyCount=rPoly.Count();
357
0
    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
358
0
        CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
359
0
    }
360
0
}
361
362
void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
363
0
{
364
0
    sal_uInt16 nPolyCount=rPoly.Count();
365
0
    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
366
0
        CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
367
0
    }
368
0
}
369
370
371
Degree100 GetAngle(const Point& rPnt)
372
256k
{
373
256k
    Degree100 a;
374
256k
    if (rPnt.Y()==0) {
375
117k
        if (rPnt.X()<0) a=-18000_deg100;
376
138k
    } else if (rPnt.X()==0) {
377
69.8k
        if (rPnt.Y()>0) a=-9000_deg100;
378
6.47k
        else a=9000_deg100;
379
69.8k
    } else {
380
69.0k
        a = Degree100(basegfx::fround(basegfx::rad2deg<100>(atan2(-static_cast<double>(rPnt.Y()), static_cast<double>(rPnt.X())))));
381
69.0k
    }
382
256k
    return a;
383
256k
}
384
385
Degree100 NormAngle18000(Degree100 a)
386
78.1k
{
387
78.1k
    while (a<-18000_deg100) a+=36000_deg100;
388
156k
    while (a>=18000_deg100) a-=36000_deg100;
389
78.1k
    return a;
390
78.1k
}
391
392
Degree100 NormAngle36000(Degree100 a)
393
562k
{
394
562k
    a %= 36000_deg100;
395
562k
    if (a < 0_deg100)
396
157k
        a += 36000_deg100;
397
562k
    return a;
398
562k
}
399
400
0
sal_uInt16 GetAngleSector(Degree100 nAngle) { return (NormAngle36000(nAngle) / 9000_deg100).get(); }
401
402
tools::Long GetLen(const Point& rPnt)
403
0
{
404
0
    tools::Long x=std::abs(rPnt.X());
405
0
    tools::Long y=std::abs(rPnt.Y());
406
0
    if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
407
0
        x*=x;
408
0
        y*=y;
409
0
        x+=y;
410
0
        x = basegfx::fround<tools::Long>(sqrt(x));
411
0
        return x;
412
0
    } else {
413
0
        double nx=x;
414
0
        double ny=y;
415
0
        nx*=nx;
416
0
        ny*=ny;
417
0
        nx+=ny;
418
0
        nx=sqrt(nx);
419
0
        if (nx>0x7FFFFFFF) {
420
0
            return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
421
0
        } else {
422
0
            return basegfx::fround<tools::Long>(nx);
423
0
        }
424
0
    }
425
0
}
426
427
428
void GeoStat::RecalcSinCos()
429
280k
{
430
280k
    if (m_nRotationAngle==0_deg100) {
431
162k
        mfSinRotationAngle=0.0;
432
162k
        mfCosRotationAngle=1.0;
433
162k
    } else {
434
118k
        double a = toRadians(m_nRotationAngle);
435
118k
        mfSinRotationAngle=sin(a);
436
118k
        mfCosRotationAngle=cos(a);
437
118k
    }
438
280k
}
439
440
void GeoStat::RecalcTan()
441
276k
{
442
276k
    if (m_nShearAngle==0_deg100) {
443
254k
        mfTanShearAngle=0.0;
444
254k
    } else {
445
21.9k
        double a = toRadians(m_nShearAngle);
446
21.9k
        mfTanShearAngle=tan(a);
447
21.9k
    }
448
276k
}
449
450
451
tools::Polygon Rect2Poly(const tools::Rectangle& rRect, const GeoStat& rGeo)
452
117k
{
453
117k
    tools::Polygon aPol(5);
454
117k
    aPol[0]=rRect.TopLeft();
455
117k
    aPol[1]=rRect.TopRight();
456
117k
    aPol[2]=rRect.BottomRight();
457
117k
    aPol[3]=rRect.BottomLeft();
458
117k
    aPol[4]=rRect.TopLeft();
459
117k
    if (rGeo.m_nShearAngle) ShearPoly(aPol,rRect.TopLeft(),rGeo.mfTanShearAngle);
460
117k
    if (rGeo.m_nRotationAngle) RotatePoly(aPol,rRect.TopLeft(),rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle);
461
117k
    return aPol;
462
117k
}
463
464
namespace svx
465
{
466
tools::Rectangle polygonToRectangle(const tools::Polygon& rPolygon, GeoStat& rGeo)
467
78.1k
{
468
78.1k
    rGeo.m_nRotationAngle = GetAngle(rPolygon[1] - rPolygon[0]);
469
78.1k
    rGeo.m_nRotationAngle = NormAngle36000(rGeo.m_nRotationAngle);
470
471
    // rotation successful
472
78.1k
    rGeo.RecalcSinCos();
473
474
78.1k
    Point aPoint1(rPolygon[1] - rPolygon[0]);
475
78.1k
    if (rGeo.m_nRotationAngle)
476
51.5k
        RotatePoint(aPoint1, Point(0,0), -rGeo.mfSinRotationAngle, rGeo.mfCosRotationAngle); // -Sin to reverse rotation
477
78.1k
    tools::Long nWidth = aPoint1.X();
478
479
78.1k
    Point aPoint0(rPolygon[0]);
480
78.1k
    Point aPoint3(rPolygon[3] - rPolygon[0]);
481
78.1k
    if (rGeo.m_nRotationAngle)
482
51.5k
        RotatePoint(aPoint3, Point(0,0), -rGeo.mfSinRotationAngle, rGeo.mfCosRotationAngle); // -Sin to reverse rotation
483
78.1k
    tools::Long nHeight = aPoint3.Y();
484
485
78.1k
    Degree100 nShearAngle = GetAngle(aPoint3);
486
78.1k
    nShearAngle -= 27000_deg100; // ShearWink is measured against a vertical line
487
78.1k
    nShearAngle = -nShearAngle;  // negating, because '+' is shearing clock-wise
488
489
78.1k
    bool bMirror = aPoint3.Y() < 0;
490
78.1k
    if (bMirror)
491
1.40k
    {   // "exchange of points" when mirroring
492
1.40k
        nHeight = -nHeight;
493
1.40k
        nShearAngle += 18000_deg100;
494
1.40k
        aPoint0 = rPolygon[3];
495
1.40k
    }
496
497
78.1k
    nShearAngle = NormAngle18000(nShearAngle);
498
78.1k
    if (nShearAngle < -9000_deg100 || nShearAngle > 9000_deg100)
499
0
    {
500
0
        nShearAngle = NormAngle18000(nShearAngle + 18000_deg100);
501
0
    }
502
503
78.1k
    if (nShearAngle < -SDRMAXSHEAR)
504
17.2k
        nShearAngle = -SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
505
506
78.1k
    if (nShearAngle > SDRMAXSHEAR)
507
740
        nShearAngle = SDRMAXSHEAR;
508
509
78.1k
    rGeo.m_nShearAngle = nShearAngle;
510
78.1k
    rGeo.RecalcTan();
511
512
78.1k
    Point aRU(aPoint0);
513
78.1k
    aRU.AdjustX(nWidth);
514
78.1k
    aRU.AdjustY(nHeight);
515
516
78.1k
    return tools::Rectangle(aPoint0, aRU);
517
78.1k
}
518
519
} // end svx
520
521
void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
522
0
{
523
0
    tools::Long dx=rPt.X()-rPt0.X();
524
0
    tools::Long dy=rPt.Y()-rPt0.Y();
525
0
    tools::Long dxa=std::abs(dx);
526
0
    tools::Long dya=std::abs(dy);
527
0
    if (dx==0 || dy==0 || dxa==dya) return;
528
0
    if (dxa>=dya*2) { rPt.setY(rPt0.Y() ); return; }
529
0
    if (dya>=dxa*2) { rPt.setX(rPt0.X() ); return; }
530
0
    if ((dxa<dya) != bBigOrtho) {
531
0
        rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
532
0
    } else {
533
0
        rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
534
0
    }
535
0
}
536
537
void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
538
0
{
539
0
    tools::Long dx=rPt.X()-rPt0.X();
540
0
    tools::Long dy=rPt.Y()-rPt0.Y();
541
0
    tools::Long dxa=std::abs(dx);
542
0
    tools::Long dya=std::abs(dy);
543
0
    if ((dxa<dya) != bBigOrtho) {
544
0
        rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
545
0
    } else {
546
0
        rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
547
0
    }
548
0
}
549
550
551
tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
552
287k
{
553
287k
    if (!nDiv)
554
0
        return 0x7fffffff;
555
287k
    return BigInt::Scale(nVal, nMul, nDiv);
556
287k
}
557
558
static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo)
559
87.7k
{
560
87.7k
    const auto [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
561
87.7k
    return FrPair(nNum, nDen, nNum, nDen);
562
87.7k
}
563
564
// How many eU units fit into a mm, respectively an inch?
565
// Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
566
567
static FrPair GetInchOrMM(MapUnit eU)
568
0
{
569
0
    switch (eU) {
570
0
        case MapUnit::Map1000thInch: return toPair(o3tl::Length::in, o3tl::Length::in1000);
571
0
        case MapUnit::Map100thInch : return toPair(o3tl::Length::in, o3tl::Length::in100);
572
0
        case MapUnit::Map10thInch  : return toPair(o3tl::Length::in, o3tl::Length::in10);
573
0
        case MapUnit::MapInch       : return toPair(o3tl::Length::in, o3tl::Length::in);
574
0
        case MapUnit::MapPoint      : return toPair(o3tl::Length::in, o3tl::Length::pt);
575
0
        case MapUnit::MapTwip       : return toPair(o3tl::Length::in, o3tl::Length::twip);
576
0
        case MapUnit::Map100thMM   : return toPair(o3tl::Length::mm, o3tl::Length::mm100);
577
0
        case MapUnit::Map10thMM    : return toPair(o3tl::Length::mm, o3tl::Length::mm10);
578
0
        case MapUnit::MapMM         : return toPair(o3tl::Length::mm, o3tl::Length::mm);
579
0
        case MapUnit::MapCM         : return toPair(o3tl::Length::mm, o3tl::Length::cm);
580
0
        case MapUnit::MapPixel      : {
581
0
            ScopedVclPtrInstance< VirtualDevice > pVD;
582
0
            pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
583
0
            Point aP(pVD->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
584
0
            return FrPair(6400,aP.X(),6400,aP.Y());
585
0
        }
586
0
        case MapUnit::MapAppFont: case MapUnit::MapSysFont: {
587
0
            ScopedVclPtrInstance< VirtualDevice > pVD;
588
0
            pVD->SetMapMode(MapMode(eU));
589
0
            Point aP(pVD->LogicToPixel(Point(32,32))); // 32 units for more accuracy
590
0
            pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
591
0
            aP=pVD->PixelToLogic(aP);
592
0
            return FrPair(3200,aP.X(),3200,aP.Y());
593
0
        }
594
0
        default: break;
595
0
    }
596
0
    return 1.0;
597
0
}
598
599
// Calculate the factor that we need to convert units from eS to eD.
600
// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
601
602
FrPair GetMapFactor(MapUnit eS, MapUnit eD)
603
103k
{
604
103k
    if (eS==eD) return FrPair(1,1,1,1);
605
87.7k
    const auto eFrom = MapToO3tlLength(eS, o3tl::Length::invalid);
606
87.7k
    const auto eTo = MapToO3tlLength(eD, o3tl::Length::invalid);
607
87.7k
    if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
608
87.7k
        return toPair(eFrom, eTo);
609
0
    FrPair aS(GetInchOrMM(eS));
610
0
    FrPair aD(GetInchOrMM(eD));
611
0
    bool bSInch=IsInch(eS);
612
0
    bool bDInch=IsInch(eD);
613
0
    FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
614
0
    if (bSInch && !bDInch) { aRet.X() *= 127.0/5; aRet.Y() *= 127.0/5; }
615
0
    if (!bSInch && bDInch) { aRet.X() *= 5.0/127; aRet.Y() *= 5.0/127; }
616
0
    return aRet;
617
87.7k
};
618
619
FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
620
0
{
621
0
    if (eS==eD) return FrPair(1,1,1,1);
622
0
    auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD);
623
0
    if (eFrom == o3tl::Length::invalid)
624
0
    {
625
0
        if (eTo == o3tl::Length::invalid)
626
0
            return FrPair(1,1,1,1);
627
0
        eFrom = IsInch(eD) ? o3tl::Length::in : o3tl::Length::mm;
628
0
    }
629
0
    else if (eTo == o3tl::Length::invalid)
630
0
        eTo = IsInch(eS) ? o3tl::Length::in : o3tl::Length::mm;
631
0
    return toPair(eFrom, eTo);
632
0
};
633
634
void SdrFormatter::Undirty()
635
0
{
636
0
    const o3tl::Length eFrom = MapToO3tlLength(m_eSrcMU, o3tl::Length::invalid);
637
0
    const o3tl::Length eTo = MapToO3tlLength(m_eDstMU, o3tl::Length::invalid);
638
0
    if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
639
0
    {
640
0
        const auto [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
641
0
        sal_Int64 nMul = mul;
642
0
        sal_Int64 nDiv = div;
643
0
        short nComma = 0;
644
645
        // shorten trailing zeros for dividend
646
0
        while (0 == (nMul % 10))
647
0
        {
648
0
            nComma--;
649
0
            nMul /= 10;
650
0
        }
651
652
        // shorten trailing zeros for divisor
653
0
        while (0 == (nDiv % 10))
654
0
        {
655
0
            nComma++;
656
0
            nDiv /= 10;
657
0
        }
658
0
        m_nMul = nMul;
659
0
        m_nDiv = nDiv;
660
0
        m_nComma = nComma;
661
0
    }
662
0
    else
663
0
    {
664
0
        m_nMul = m_nDiv = 1;
665
0
        m_nComma = 0;
666
0
    }
667
0
    m_bDirty=false;
668
0
}
669
670
671
OUString SdrFormatter::GetStr(tools::Long nVal) const
672
0
{
673
0
    static constexpr OUString aNullCode(u"0"_ustr);
674
675
0
    if(!nVal)
676
0
    {
677
0
        return aNullCode;
678
0
    }
679
680
    // we may lose some decimal places here, because of MulDiv instead of Real
681
0
    bool bNeg(nVal < 0);
682
0
    SvtSysLocale aSysLoc;
683
0
    const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
684
685
0
    if (m_bDirty)
686
0
        const_cast<SdrFormatter*>(this)->Undirty();
687
688
0
    sal_Int16 nC(m_nComma);
689
690
0
    if(bNeg)
691
0
        nVal = -nVal;
692
693
0
    while(nC <= -3)
694
0
    {
695
0
        nVal *= 1000;
696
0
        nC += 3;
697
0
    }
698
699
0
    while(nC <= -1)
700
0
    {
701
0
        nVal *= 10;
702
0
        nC++;
703
0
    }
704
705
0
    if(m_nMul != m_nDiv)
706
0
        nVal = BigMulDiv(nVal, m_nMul, m_nDiv);
707
708
0
    OUStringBuffer aStr = OUString::number(nVal);
709
710
0
    if(nC > 0 && aStr.getLength() <= nC )
711
0
    {
712
        // decimal separator necessary
713
0
        sal_Int32 nCount(nC - aStr.getLength());
714
715
0
        if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
716
0
            nCount++;
717
718
0
        for(sal_Int32  i=0; i<nCount; i++)
719
0
            aStr.insert(0, aNullCode);
720
721
        // remove superfluous decimal points
722
0
        sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits());
723
0
        sal_Int32 nWeg(nC - nNumDigits);
724
725
0
        if(nWeg > 0)
726
0
        {
727
            // TODO: we should round here
728
0
            aStr.remove(aStr.getLength() - nWeg, nWeg);
729
0
            nC = nNumDigits;
730
0
        }
731
0
    }
732
733
    // remember everything before the decimal separator for later
734
0
    sal_Int32 nForComma(aStr.getLength() - nC);
735
736
0
    if(nC > 0)
737
0
    {
738
        // insert comma char (decimal separator)
739
        // remove trailing zeros
740
0
        while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode.getStr()[0])
741
0
        {
742
0
            aStr.remove(aStr.getLength() - 1, 1);
743
0
            nC--;
744
0
        }
745
746
0
        if(nC > 0)
747
0
        {
748
            // do we still have decimal places?
749
0
            sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
750
0
            aStr.insert(nForComma, cDec);
751
0
        }
752
0
    }
753
754
    // add in thousands separator (if necessary)
755
0
    if( nForComma > 3 )
756
0
    {
757
0
        const OUString& aThoSep( rLoc.getNumThousandSep() );
758
0
        if ( aThoSep.getLength() > 0 )
759
0
        {
760
0
            sal_Unicode cTho( aThoSep[0] );
761
0
            sal_Int32 i(nForComma - 3);
762
763
0
            while(i > 0)
764
0
            {
765
0
                aStr.insert(i, cTho);
766
0
                i -= 3;
767
0
            }
768
0
        }
769
0
    }
770
771
0
    if(aStr.isEmpty())
772
0
        aStr.append(aNullCode);
773
774
0
    if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode.getStr()[0]))
775
0
    {
776
0
        aStr.insert(0, "-");
777
0
    }
778
779
0
    return aStr.makeStringAndClear();
780
0
}
781
782
OUString SdrFormatter::GetUnitStr(MapUnit eUnit)
783
0
{
784
0
    switch(eUnit)
785
0
    {
786
        // metrically
787
0
        case MapUnit::Map100thMM   :
788
0
            return u"/100mm"_ustr;
789
0
        case MapUnit::Map10thMM    :
790
0
            return u"/10mm"_ustr;
791
0
        case MapUnit::MapMM         :
792
0
            return u"mm"_ustr;
793
0
        case MapUnit::MapCM         :
794
0
            return u"cm"_ustr;
795
796
        // Inch
797
0
        case MapUnit::Map1000thInch:
798
0
            return u"/1000\""_ustr;
799
0
        case MapUnit::Map100thInch :
800
0
            return u"/100\""_ustr;
801
0
        case MapUnit::Map10thInch  :
802
0
            return u"/10\""_ustr;
803
0
        case MapUnit::MapInch       :
804
0
            return u"\""_ustr;
805
0
        case MapUnit::MapPoint      :
806
0
            return u"pt"_ustr;
807
0
        case MapUnit::MapTwip       :
808
0
            return u"twip"_ustr;
809
810
        // others
811
0
        case MapUnit::MapPixel      :
812
0
            return u"pixel"_ustr;
813
0
        case MapUnit::MapSysFont    :
814
0
            return u"sysfont"_ustr;
815
0
        case MapUnit::MapAppFont    :
816
0
            return u"appfont"_ustr;
817
0
        case MapUnit::MapRelative   :
818
0
            return u"%"_ustr;
819
0
        default:
820
0
            return OUString();
821
0
    }
822
0
}
823
824
OUString SdrFormatter::GetUnitStr(FieldUnit eUnit)
825
0
{
826
0
    switch(eUnit)
827
0
    {
828
0
        default             :
829
0
        case FieldUnit::NONE     :
830
0
        case FieldUnit::CUSTOM   :
831
0
            return OUString();
832
833
        // metrically
834
0
        case FieldUnit::MM_100TH:
835
0
            return u"/100mm"_ustr;
836
0
        case FieldUnit::MM     :
837
0
            return u"mm"_ustr;
838
0
        case FieldUnit::CM     :
839
0
            return u"cm"_ustr;
840
0
        case FieldUnit::M      :
841
0
            return u"m"_ustr;
842
0
        case FieldUnit::KM     :
843
0
            return u"km"_ustr;
844
845
        // Inch
846
0
        case FieldUnit::TWIP   :
847
0
            return u"twip"_ustr;
848
0
        case FieldUnit::POINT  :
849
0
            return u"pt"_ustr;
850
0
        case FieldUnit::PICA   :
851
0
            return u"pica"_ustr;
852
0
        case FieldUnit::INCH   :
853
0
            return u"\""_ustr;
854
0
        case FieldUnit::FOOT   :
855
0
            return u"ft"_ustr;
856
0
        case FieldUnit::MILE   :
857
0
            return u"mile(s)"_ustr;
858
859
        // others
860
0
        case FieldUnit::PERCENT:
861
0
            return u"%"_ustr;
862
0
    }
863
0
}
864
865
866
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */