1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <svx/svdtrans.hxx>
23 #include <svx/xpoly.hxx>
24 #include <rtl/ustrbuf.hxx>
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>
33 void MoveXPoly(XPolygon
& rPoly
, const Size
& S
)
35 rPoly
.Move(S
.Width(),S
.Height());
38 void ResizeRect(tools::Rectangle
& rRect
, const Point
& rRef
, const Fraction
& rxFact
, const Fraction
& ryFact
)
40 Fraction
aXFact(rxFact
);
41 Fraction
aYFact(ryFact
);
43 if (!aXFact
.IsValid()) {
44 SAL_WARN( "svx.svdraw", "invalid fraction xFract, using Fraction(1,1)" );
45 aXFact
= Fraction(1,1);
46 tools::Long nWdt
= rRect
.Right() - rRect
.Left();
47 if (nWdt
== 0) rRect
.AdjustRight( 1 );
49 rRect
.SetLeft( rRef
.X() + FRound( (rRect
.Left() - rRef
.X()) * double(aXFact
) ) );
50 rRect
.SetRight( rRef
.X() + FRound( (rRect
.Right() - rRef
.X()) * double(aXFact
) ) );
52 if (!aYFact
.IsValid()) {
53 SAL_WARN( "svx.svdraw", "invalid fraction yFract, using Fraction(1,1)" );
54 aYFact
= Fraction(1,1);
55 tools::Long nHgt
= rRect
.Bottom() - rRect
.Top();
56 if (nHgt
== 0) rRect
.AdjustBottom( 1 );
58 rRect
.SetTop( rRef
.Y() + FRound( (rRect
.Top() - rRef
.Y()) * double(aYFact
) ) );
59 rRect
.SetBottom( rRef
.Y() + FRound( (rRect
.Bottom() - rRef
.Y()) * double(aYFact
) ) );
65 void ResizePoly(tools::Polygon
& rPoly
, const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
67 sal_uInt16 nCount
=rPoly
.GetSize();
68 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
69 ResizePoint(rPoly
[i
],rRef
,xFact
,yFact
);
73 void ResizeXPoly(XPolygon
& rPoly
, const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
75 sal_uInt16 nCount
=rPoly
.GetPointCount();
76 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
77 ResizePoint(rPoly
[i
],rRef
,xFact
,yFact
);
81 void RotatePoly(tools::Polygon
& rPoly
, const Point
& rRef
, double sn
, double cs
)
83 sal_uInt16 nCount
=rPoly
.GetSize();
84 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
85 RotatePoint(rPoly
[i
],rRef
,sn
,cs
);
89 void RotateXPoly(XPolygon
& rPoly
, const Point
& rRef
, double sn
, double cs
)
91 sal_uInt16 nCount
=rPoly
.GetPointCount();
92 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
93 RotatePoint(rPoly
[i
],rRef
,sn
,cs
);
97 void RotateXPoly(XPolyPolygon
& rPoly
, const Point
& rRef
, double sn
, double cs
)
99 sal_uInt16 nCount
=rPoly
.Count();
100 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
101 RotateXPoly(rPoly
[i
],rRef
,sn
,cs
);
105 void MirrorPoint(Point
& rPnt
, const Point
& rRef1
, const Point
& rRef2
)
107 tools::Long mx
=rRef2
.X()-rRef1
.X();
108 tools::Long my
=rRef2
.Y()-rRef1
.Y();
109 if (mx
==0) { // vertical axis
110 tools::Long dx
=rRef1
.X()-rPnt
.X();
112 } else if (my
==0) { // horizontal axis
113 tools::Long dy
=rRef1
.Y()-rPnt
.Y();
115 } else if (mx
==my
) { // diagonal axis '\'
116 tools::Long dx1
=rPnt
.X()-rRef1
.X();
117 tools::Long dy1
=rPnt
.Y()-rRef1
.Y();
118 rPnt
.setX(rRef1
.X()+dy1
);
119 rPnt
.setY(rRef1
.Y()+dx1
);
120 } else if (mx
==-my
) { // diagonal axis '/'
121 tools::Long dx1
=rPnt
.X()-rRef1
.X();
122 tools::Long dy1
=rPnt
.Y()-rRef1
.Y();
123 rPnt
.setX(rRef1
.X()-dy1
);
124 rPnt
.setY(rRef1
.Y()-dx1
);
125 } else { // arbitrary axis
126 // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
127 Degree100 nRefAngle
=GetAngle(rRef2
-rRef1
);
129 Degree100 nPntAngle
=GetAngle(rPnt
);
130 Degree100 nAngle
=2_deg100
*(nRefAngle
-nPntAngle
);
131 double a
= toRadians(nAngle
);
134 RotatePoint(rPnt
,Point(),nSin
,nCos
);
139 void MirrorXPoly(XPolygon
& rPoly
, const Point
& rRef1
, const Point
& rRef2
)
141 sal_uInt16 nCount
=rPoly
.GetPointCount();
142 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
143 MirrorPoint(rPoly
[i
],rRef1
,rRef2
);
147 void ShearPoly(tools::Polygon
& rPoly
, const Point
& rRef
, double tn
)
149 sal_uInt16 nCount
=rPoly
.GetSize();
150 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
151 ShearPoint(rPoly
[i
],rRef
,tn
);
155 void ShearXPoly(XPolygon
& rPoly
, const Point
& rRef
, double tn
, bool bVShear
)
157 sal_uInt16 nCount
=rPoly
.GetPointCount();
158 for (sal_uInt16 i
=0; i
<nCount
; i
++) {
159 ShearPoint(rPoly
[i
],rRef
,tn
,bVShear
);
163 double CrookRotateXPoint(Point
& rPnt
, Point
* pC1
, Point
* pC2
, const Point
& rCenter
,
164 const Point
& rRad
, double& rSin
, double& rCos
, bool bVert
)
166 bool bC1
=pC1
!=nullptr;
167 bool bC2
=pC2
!=nullptr;
168 tools::Long x0
=rPnt
.X();
169 tools::Long y0
=rPnt
.Y();
170 tools::Long cx
=rCenter
.X();
171 tools::Long cy
=rCenter
.Y();
172 double nAngle
=GetCrookAngle(rPnt
,rCenter
,rRad
,bVert
);
173 double sn
=sin(nAngle
);
174 double cs
=cos(nAngle
);
175 RotatePoint(rPnt
,rCenter
,sn
,cs
);
178 // move into the direction of the center, as a basic position for the rotation
180 // resize, account for the distance from the center
181 pC1
->setY(FRound(static_cast<double>(pC1
->Y()) /rRad
.X()*(cx
-pC1
->X())) );
184 // move into the direction of the center, as a basic position for the rotation
186 // resize, account for the distance from the center
187 tools::Long nPntRad
=cy
-pC1
->Y();
188 double nFact
=static_cast<double>(nPntRad
)/static_cast<double>(rRad
.Y());
189 pC1
->setX(FRound(static_cast<double>(pC1
->X())*nFact
) );
192 RotatePoint(*pC1
,rCenter
,sn
,cs
);
196 // move into the direction of the center, as a basic position for the rotation
198 // resize, account for the distance from the center
199 pC2
->setY(FRound(static_cast<double>(pC2
->Y()) /rRad
.X()*(rCenter
.X()-pC2
->X())) );
202 // move into the direction of the center, as a basic position for the rotation
204 // resize, account for the distance from the center
205 tools::Long nPntRad
=rCenter
.Y()-pC2
->Y();
206 double nFact
=static_cast<double>(nPntRad
)/static_cast<double>(rRad
.Y());
207 pC2
->setX(FRound(static_cast<double>(pC2
->X())*nFact
) );
210 RotatePoint(*pC2
,rCenter
,sn
,cs
);
217 double CrookSlantXPoint(Point
& rPnt
, Point
* pC1
, Point
* pC2
, const Point
& rCenter
,
218 const Point
& rRad
, double& rSin
, double& rCos
, bool bVert
)
220 bool bC1
=pC1
!=nullptr;
221 bool bC2
=pC2
!=nullptr;
222 tools::Long x0
=rPnt
.X();
223 tools::Long y0
=rPnt
.Y();
224 tools::Long dx1
=0,dy1
=0;
225 tools::Long dxC1
=0,dyC1
=0;
226 tools::Long dxC2
=0,dyC2
=0;
228 tools::Long nStart
=rCenter
.X()-rRad
.X();
232 dxC1
=pC1
->X()-nStart
;
236 dxC2
=pC2
->X()-nStart
;
240 tools::Long nStart
=rCenter
.Y()-rRad
.Y();
244 dyC1
=pC1
->Y()-nStart
;
248 dyC2
=pC2
->Y()-nStart
;
252 double nAngle
=GetCrookAngle(rPnt
,rCenter
,rRad
,bVert
);
253 double sn
=sin(nAngle
);
254 double cs
=cos(nAngle
);
255 RotatePoint(rPnt
,rCenter
,sn
,cs
);
256 if (bC1
) { if (bVert
) pC1
->AdjustY( -(y0
-rCenter
.Y()) ); else pC1
->AdjustX( -(x0
-rCenter
.X()) ); RotatePoint(*pC1
,rCenter
,sn
,cs
); }
257 if (bC2
) { if (bVert
) pC2
->AdjustY( -(y0
-rCenter
.Y()) ); else pC2
->AdjustX( -(x0
-rCenter
.X()) ); RotatePoint(*pC2
,rCenter
,sn
,cs
); }
260 if (bC1
) pC1
->AdjustX(dxC1
);
261 if (bC2
) pC2
->AdjustX(dxC2
);
264 if (bC1
) pC1
->AdjustY(dyC1
);
265 if (bC2
) pC2
->AdjustY(dyC2
);
272 double CrookStretchXPoint(Point
& rPnt
, Point
* pC1
, Point
* pC2
, const Point
& rCenter
,
273 const Point
& rRad
, double& rSin
, double& rCos
, bool bVert
,
274 const tools::Rectangle
& rRefRect
)
276 tools::Long y0
=rPnt
.Y();
277 CrookSlantXPoint(rPnt
,pC1
,pC2
,rCenter
,rRad
,rSin
,rCos
,bVert
);
280 tools::Long nTop
=rRefRect
.Top();
281 tools::Long nBtm
=rRefRect
.Bottom();
282 tools::Long nHgt
=nBtm
-nTop
;
283 tools::Long dy
=rPnt
.Y()-y0
;
284 double a
=static_cast<double>(y0
-nTop
)/nHgt
;
286 rPnt
.setY(y0
+FRound(a
) );
292 void CrookRotatePoly(XPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
)
295 sal_uInt16 nPointCnt
=rPoly
.GetPointCount();
297 while (i
<nPointCnt
) {
298 Point
* pPnt
=&rPoly
[i
];
301 if (i
+1<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the left
307 if (i
<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the right
311 CrookRotateXPoint(*pPnt
,pC1
,pC2
,rCenter
,rRad
,nSin
,nCos
,bVert
);
315 void CrookSlantPoly(XPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
)
318 sal_uInt16 nPointCnt
=rPoly
.GetPointCount();
320 while (i
<nPointCnt
) {
321 Point
* pPnt
=&rPoly
[i
];
324 if (i
+1<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the left
330 if (i
<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the right
334 CrookSlantXPoint(*pPnt
,pC1
,pC2
,rCenter
,rRad
,nSin
,nCos
,bVert
);
338 void CrookStretchPoly(XPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
, const tools::Rectangle
& rRefRect
)
341 sal_uInt16 nPointCnt
=rPoly
.GetPointCount();
343 while (i
<nPointCnt
) {
344 Point
* pPnt
=&rPoly
[i
];
347 if (i
+1<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the left
353 if (i
<nPointCnt
&& rPoly
.IsControl(i
)) { // control point to the right
357 CrookStretchXPoint(*pPnt
,pC1
,pC2
,rCenter
,rRad
,nSin
,nCos
,bVert
,rRefRect
);
362 void CrookRotatePoly(XPolyPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
)
364 sal_uInt16 nPolyCount
=rPoly
.Count();
365 for (sal_uInt16 nPolyNum
=0; nPolyNum
<nPolyCount
; nPolyNum
++) {
366 CrookRotatePoly(rPoly
[nPolyNum
],rCenter
,rRad
,bVert
);
370 void CrookSlantPoly(XPolyPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
)
372 sal_uInt16 nPolyCount
=rPoly
.Count();
373 for (sal_uInt16 nPolyNum
=0; nPolyNum
<nPolyCount
; nPolyNum
++) {
374 CrookSlantPoly(rPoly
[nPolyNum
],rCenter
,rRad
,bVert
);
378 void CrookStretchPoly(XPolyPolygon
& rPoly
, const Point
& rCenter
, const Point
& rRad
, bool bVert
, const tools::Rectangle
& rRefRect
)
380 sal_uInt16 nPolyCount
=rPoly
.Count();
381 for (sal_uInt16 nPolyNum
=0; nPolyNum
<nPolyCount
; nPolyNum
++) {
382 CrookStretchPoly(rPoly
[nPolyNum
],rCenter
,rRad
,bVert
,rRefRect
);
387 Degree100
GetAngle(const Point
& rPnt
)
391 if (rPnt
.X()<0) a
=-18000_deg100
;
392 } else if (rPnt
.X()==0) {
393 if (rPnt
.Y()>0) a
=-9000_deg100
;
396 a
= Degree100(FRound(basegfx::rad2deg
<100>(atan2(static_cast<double>(-rPnt
.Y()), static_cast<double>(rPnt
.X())))));
401 Degree100
NormAngle18000(Degree100 a
)
403 while (a
<-18000_deg100
) a
+=36000_deg100
;
404 while (a
>=18000_deg100
) a
-=36000_deg100
;
408 Degree100
NormAngle36000(Degree100 a
)
416 sal_uInt16
GetAngleSector(Degree100 nAngle
) { return (NormAngle36000(nAngle
) / 9000_deg100
).get(); }
418 tools::Long
GetLen(const Point
& rPnt
)
420 tools::Long x
=std::abs(rPnt
.X());
421 tools::Long y
=std::abs(rPnt
.Y());
422 if (x
+y
<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
426 x
=FRound(sqrt(static_cast<double>(x
)));
436 return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
444 void GeoStat::RecalcSinCos()
446 if (nRotationAngle
==0_deg100
) {
447 mfSinRotationAngle
=0.0;
448 mfCosRotationAngle
=1.0;
450 double a
= toRadians(nRotationAngle
);
451 mfSinRotationAngle
=sin(a
);
452 mfCosRotationAngle
=cos(a
);
456 void GeoStat::RecalcTan()
458 if (nShearAngle
==0_deg100
) {
461 double a
= toRadians(nShearAngle
);
462 mfTanShearAngle
=tan(a
);
467 tools::Polygon
Rect2Poly(const tools::Rectangle
& rRect
, const GeoStat
& rGeo
)
469 tools::Polygon
aPol(5);
470 aPol
[0]=rRect
.TopLeft();
471 aPol
[1]=rRect
.TopRight();
472 aPol
[2]=rRect
.BottomRight();
473 aPol
[3]=rRect
.BottomLeft();
474 aPol
[4]=rRect
.TopLeft();
475 if (rGeo
.nShearAngle
) ShearPoly(aPol
,rRect
.TopLeft(),rGeo
.mfTanShearAngle
);
476 if (rGeo
.nRotationAngle
) RotatePoly(aPol
,rRect
.TopLeft(),rGeo
.mfSinRotationAngle
,rGeo
.mfCosRotationAngle
);
482 tools::Rectangle
polygonToRectangle(const tools::Polygon
& rPolygon
, GeoStat
& rGeo
)
484 rGeo
.nRotationAngle
= GetAngle(rPolygon
[1] - rPolygon
[0]);
485 rGeo
.nRotationAngle
= NormAngle36000(rGeo
.nRotationAngle
);
487 // rotation successful
490 Point
aPoint1(rPolygon
[1] - rPolygon
[0]);
491 if (rGeo
.nRotationAngle
)
492 RotatePoint(aPoint1
, Point(0,0), -rGeo
.mfSinRotationAngle
, rGeo
.mfCosRotationAngle
); // -Sin to reverse rotation
493 tools::Long nWidth
= aPoint1
.X();
495 Point
aPoint0(rPolygon
[0]);
496 Point
aPoint3(rPolygon
[3] - rPolygon
[0]);
497 if (rGeo
.nRotationAngle
)
498 RotatePoint(aPoint3
, Point(0,0), -rGeo
.mfSinRotationAngle
, rGeo
.mfCosRotationAngle
); // -Sin to reverse rotation
499 tools::Long nHeight
= aPoint3
.Y();
501 Degree100 nShearAngle
= GetAngle(aPoint3
);
502 nShearAngle
-= 27000_deg100
; // ShearWink is measured against a vertical line
503 nShearAngle
= -nShearAngle
; // negating, because '+' is shearing clock-wise
505 bool bMirror
= aPoint3
.Y() < 0;
507 { // "exchange of points" when mirroring
509 nShearAngle
+= 18000_deg100
;
510 aPoint0
= rPolygon
[3];
513 nShearAngle
= NormAngle18000(nShearAngle
);
514 if (nShearAngle
< -9000_deg100
|| nShearAngle
> 9000_deg100
)
516 nShearAngle
= NormAngle18000(nShearAngle
+ 18000_deg100
);
519 if (nShearAngle
< -SDRMAXSHEAR
)
520 nShearAngle
= -SDRMAXSHEAR
; // limit ShearWinkel (shear angle) to +/- 89.00 deg
522 if (nShearAngle
> SDRMAXSHEAR
)
523 nShearAngle
= SDRMAXSHEAR
;
525 rGeo
.nShearAngle
= nShearAngle
;
530 aRU
.AdjustY(nHeight
);
532 return tools::Rectangle(aPoint0
, aRU
);
537 void OrthoDistance8(const Point
& rPt0
, Point
& rPt
, bool bBigOrtho
)
539 tools::Long dx
=rPt
.X()-rPt0
.X();
540 tools::Long dy
=rPt
.Y()-rPt0
.Y();
541 tools::Long dxa
=std::abs(dx
);
542 tools::Long dya
=std::abs(dy
);
543 if (dx
==0 || dy
==0 || dxa
==dya
) return;
544 if (dxa
>=dya
*2) { rPt
.setY(rPt0
.Y() ); return; }
545 if (dya
>=dxa
*2) { rPt
.setX(rPt0
.X() ); return; }
546 if ((dxa
<dya
) != bBigOrtho
) {
547 rPt
.setY(rPt0
.Y()+(dxa
* (dy
>=0 ? 1 : -1) ) );
549 rPt
.setX(rPt0
.X()+(dya
* (dx
>=0 ? 1 : -1) ) );
553 void OrthoDistance4(const Point
& rPt0
, Point
& rPt
, bool bBigOrtho
)
555 tools::Long dx
=rPt
.X()-rPt0
.X();
556 tools::Long dy
=rPt
.Y()-rPt0
.Y();
557 tools::Long dxa
=std::abs(dx
);
558 tools::Long dya
=std::abs(dy
);
559 if ((dxa
<dya
) != bBigOrtho
) {
560 rPt
.setY(rPt0
.Y()+(dxa
* (dy
>=0 ? 1 : -1) ) );
562 rPt
.setX(rPt0
.X()+(dya
* (dx
>=0 ? 1 : -1) ) );
567 tools::Long
BigMulDiv(tools::Long nVal
, tools::Long nMul
, tools::Long nDiv
)
571 return BigInt::Scale(nVal
, nMul
, nDiv
);
574 static FrPair
toPair(o3tl::Length eFrom
, o3tl::Length eTo
)
576 const auto& [nNum
, nDen
] = o3tl::getConversionMulDiv(eFrom
, eTo
);
577 return FrPair(nNum
, nDen
);
580 // How many eU units fit into a mm, respectively an inch?
581 // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
583 static FrPair
GetInchOrMM(MapUnit eU
)
586 case MapUnit::Map1000thInch
: return toPair(o3tl::Length::in
, o3tl::Length::in1000
);
587 case MapUnit::Map100thInch
: return toPair(o3tl::Length::in
, o3tl::Length::in100
);
588 case MapUnit::Map10thInch
: return toPair(o3tl::Length::in
, o3tl::Length::in10
);
589 case MapUnit::MapInch
: return toPair(o3tl::Length::in
, o3tl::Length::in
);
590 case MapUnit::MapPoint
: return toPair(o3tl::Length::in
, o3tl::Length::pt
);
591 case MapUnit::MapTwip
: return toPair(o3tl::Length::in
, o3tl::Length::twip
);
592 case MapUnit::Map100thMM
: return toPair(o3tl::Length::mm
, o3tl::Length::mm100
);
593 case MapUnit::Map10thMM
: return toPair(o3tl::Length::mm
, o3tl::Length::mm10
);
594 case MapUnit::MapMM
: return toPair(o3tl::Length::mm
, o3tl::Length::mm
);
595 case MapUnit::MapCM
: return toPair(o3tl::Length::mm
, o3tl::Length::cm
);
596 case MapUnit::MapPixel
: {
597 ScopedVclPtrInstance
< VirtualDevice
> pVD
;
598 pVD
->SetMapMode(MapMode(MapUnit::Map100thMM
));
599 Point
aP(pVD
->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
600 return FrPair(6400,aP
.X(),6400,aP
.Y());
602 case MapUnit::MapAppFont
: case MapUnit::MapSysFont
: {
603 ScopedVclPtrInstance
< VirtualDevice
> pVD
;
604 pVD
->SetMapMode(MapMode(eU
));
605 Point
aP(pVD
->LogicToPixel(Point(32,32))); // 32 units for more accuracy
606 pVD
->SetMapMode(MapMode(MapUnit::Map100thMM
));
607 aP
=pVD
->PixelToLogic(aP
);
608 return FrPair(3200,aP
.X(),3200,aP
.Y());
612 return Fraction(1,1);
615 // Calculate the factor that we need to convert units from eS to eD.
616 // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
618 FrPair
GetMapFactor(MapUnit eS
, MapUnit eD
)
620 if (eS
==eD
) return FrPair(1,1,1,1);
621 const auto eFrom
= MapToO3tlLength(eS
, o3tl::Length::invalid
);
622 const auto eTo
= MapToO3tlLength(eD
, o3tl::Length::invalid
);
623 if (eFrom
!= o3tl::Length::invalid
&& eTo
!= o3tl::Length::invalid
)
624 return toPair(eFrom
, eTo
);
625 FrPair
aS(GetInchOrMM(eS
));
626 FrPair
aD(GetInchOrMM(eD
));
627 bool bSInch
=IsInch(eS
);
628 bool bDInch
=IsInch(eD
);
629 FrPair
aRet(aD
.X()/aS
.X(),aD
.Y()/aS
.Y());
630 if (bSInch
&& !bDInch
) { aRet
.X()*=Fraction(127,5); aRet
.Y()*=Fraction(127,5); }
631 if (!bSInch
&& bDInch
) { aRet
.X()*=Fraction(5,127); aRet
.Y()*=Fraction(5,127); }
635 FrPair
GetMapFactor(FieldUnit eS
, FieldUnit eD
)
637 if (eS
==eD
) return FrPair(1,1,1,1);
638 auto eFrom
= FieldToO3tlLength(eS
), eTo
= FieldToO3tlLength(eD
);
639 if (eFrom
== o3tl::Length::invalid
)
641 if (eTo
== o3tl::Length::invalid
)
642 return FrPair(1,1,1,1);
643 eFrom
= IsInch(eD
) ? o3tl::Length::in
: o3tl::Length::mm
;
645 else if (eTo
== o3tl::Length::invalid
)
646 eTo
= IsInch(eS
) ? o3tl::Length::in
: o3tl::Length::mm
;
647 return toPair(eFrom
, eTo
);
650 void SdrFormatter::Undirty()
652 const o3tl::Length eFrom
= MapToO3tlLength(eSrcMU
, o3tl::Length::invalid
);
653 const o3tl::Length eTo
= MapToO3tlLength(eDstMU
, o3tl::Length::invalid
);
654 if (eFrom
!= o3tl::Length::invalid
&& eTo
!= o3tl::Length::invalid
)
656 const auto& [mul
, div
] = o3tl::getConversionMulDiv(eFrom
, eTo
);
657 sal_Int64 nMul
= mul
;
658 sal_Int64 nDiv
= div
;
661 // shorten trailing zeros for dividend
662 while (0 == (nMul
% 10))
668 // shorten trailing zeros for divisor
669 while (0 == (nDiv
% 10))
687 OUString
SdrFormatter::GetStr(tools::Long nVal
) const
689 const OUString
aNullCode("0");
696 // we may lose some decimal places here, because of MulDiv instead of Real
698 SvtSysLocale aSysLoc
;
699 const LocaleDataWrapper
& rLoc
= aSysLoc
.GetLocaleData();
702 const_cast<SdrFormatter
*>(this)->Undirty();
704 sal_Int16
nC(nComma_
);
722 nVal
= BigMulDiv(nVal
, nMul_
, nDiv_
);
724 OUStringBuffer aStr
= OUString::number(nVal
);
726 if(nC
> 0 && aStr
.getLength() <= nC
)
728 // decimal separator necessary
729 sal_Int32
nCount(nC
- aStr
.getLength());
731 if(nCount
>= 0 && LocaleDataWrapper::isNumLeadingZero())
734 for(sal_Int32 i
=0; i
<nCount
; i
++)
735 aStr
.insert(0, aNullCode
);
737 // remove superfluous decimal points
738 sal_Int32
nNumDigits(LocaleDataWrapper::getNumDigits());
739 sal_Int32
nWeg(nC
- nNumDigits
);
743 // TODO: we should round here
744 aStr
.remove(aStr
.getLength() - nWeg
, nWeg
);
749 // remember everything before the decimal separator for later
750 sal_Int32
nForComma(aStr
.getLength() - nC
);
754 // insert comma char (decimal separator)
755 // remove trailing zeros
756 while(nC
> 0 && aStr
[aStr
.getLength() - 1] == aNullCode
[0])
758 aStr
.remove(aStr
.getLength() - 1, 1);
764 // do we still have decimal places?
765 sal_Unicode
cDec(rLoc
.getNumDecimalSep()[0]);
766 aStr
.insert(nForComma
, cDec
);
770 // add in thousands separator (if necessary)
773 const OUString
& aThoSep( rLoc
.getNumThousandSep() );
774 if ( aThoSep
.getLength() > 0 )
776 sal_Unicode
cTho( aThoSep
[0] );
777 sal_Int32
i(nForComma
- 3);
781 aStr
.insert(i
, cTho
);
788 aStr
.append(aNullCode
);
790 if(bNeg
&& (aStr
.getLength() > 1 || aStr
[0] != aNullCode
[0]))
795 return aStr
.makeStringAndClear();
798 OUString
SdrFormatter::GetUnitStr(MapUnit eUnit
)
803 case MapUnit::Map100thMM
:
805 case MapUnit::Map10thMM
:
807 case MapUnit::MapMM
:
809 case MapUnit::MapCM
:
813 case MapUnit::Map1000thInch
:
815 case MapUnit::Map100thInch
:
817 case MapUnit::Map10thInch
:
819 case MapUnit::MapInch
:
821 case MapUnit::MapPoint
:
823 case MapUnit::MapTwip
:
827 case MapUnit::MapPixel
:
829 case MapUnit::MapSysFont
:
831 case MapUnit::MapAppFont
:
833 case MapUnit::MapRelative
:
840 OUString
SdrFormatter::GetUnitStr(FieldUnit eUnit
)
845 case FieldUnit::NONE
:
846 case FieldUnit::CUSTOM
:
850 case FieldUnit::MM_100TH
:
862 case FieldUnit::TWIP
:
864 case FieldUnit::POINT
:
866 case FieldUnit::PICA
:
868 case FieldUnit::INCH
:
870 case FieldUnit::FOOT
:
872 case FieldUnit::MILE
:
876 case FieldUnit::PERCENT
:
882 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */