LibreOffice Module svx (master) 1
svdtrans.cxx
Go to the documentation of this file.
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>
31#include <sal/log.hxx>
32
33void MoveXPoly(XPolygon& rPoly, const Size& S)
34{
35 rPoly.Move(S.Width(),S.Height());
36}
37
38void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact)
39{
40 Fraction aXFact(rxFact);
41 Fraction aYFact(ryFact);
42
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 );
48 }
49 rRect.SetLeft( rRef.X() + FRound( (rRect.Left() - rRef.X()) * double(aXFact) ) );
50 rRect.SetRight( rRef.X() + FRound( (rRect.Right() - rRef.X()) * double(aXFact) ) );
51
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 );
57 }
58 rRect.SetTop( rRef.Y() + FRound( (rRect.Top() - rRef.Y()) * double(aYFact) ) );
59 rRect.SetBottom( rRef.Y() + FRound( (rRect.Bottom() - rRef.Y()) * double(aYFact) ) );
60
61 rRect.Normalize();
62}
63
64
65void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
66{
67 sal_uInt16 nCount=rPoly.GetSize();
68 for (sal_uInt16 i=0; i<nCount; i++) {
69 ResizePoint(rPoly[i],rRef,xFact,yFact);
70 }
71}
72
73void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
74{
75 sal_uInt16 nCount=rPoly.GetPointCount();
76 for (sal_uInt16 i=0; i<nCount; i++) {
77 ResizePoint(rPoly[i],rRef,xFact,yFact);
78 }
79}
80
81void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs)
82{
83 sal_uInt16 nCount=rPoly.GetSize();
84 for (sal_uInt16 i=0; i<nCount; i++) {
85 RotatePoint(rPoly[i],rRef,sn,cs);
86 }
87}
88
89void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
90{
91 sal_uInt16 nCount=rPoly.GetPointCount();
92 for (sal_uInt16 i=0; i<nCount; i++) {
93 RotatePoint(rPoly[i],rRef,sn,cs);
94 }
95}
96
97void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
98{
99 sal_uInt16 nCount=rPoly.Count();
100 for (sal_uInt16 i=0; i<nCount; i++) {
101 RotateXPoly(rPoly[i],rRef,sn,cs);
102 }
103}
104
105void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
106{
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();
111 rPnt.AdjustX(2*dx );
112 } else if (my==0) { // horizontal axis
113 tools::Long dy=rRef1.Y()-rPnt.Y();
114 rPnt.AdjustY(2*dy );
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);
128 rPnt-=rRef1;
129 Degree100 nPntAngle=GetAngle(rPnt);
130 Degree100 nAngle=2_deg100*(nRefAngle-nPntAngle);
131 double a = toRadians(nAngle);
132 double nSin=sin(a);
133 double nCos=cos(a);
134 RotatePoint(rPnt,Point(),nSin,nCos);
135 rPnt+=rRef1;
136 }
137}
138
139void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
140{
141 sal_uInt16 nCount=rPoly.GetPointCount();
142 for (sal_uInt16 i=0; i<nCount; i++) {
143 MirrorPoint(rPoly[i],rRef1,rRef2);
144 }
145}
146
147void ShearPoly(tools::Polygon& rPoly, const Point& rRef, double tn)
148{
149 sal_uInt16 nCount=rPoly.GetSize();
150 for (sal_uInt16 i=0; i<nCount; i++) {
151 ShearPoint(rPoly[i],rRef,tn);
152 }
153}
154
155void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
156{
157 sal_uInt16 nCount=rPoly.GetPointCount();
158 for (sal_uInt16 i=0; i<nCount; i++) {
159 ShearPoint(rPoly[i],rRef,tn,bVShear);
160 }
161}
162
163double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
164 const Point& rRad, double& rSin, double& rCos, bool bVert)
165{
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);
176 if (bC1) {
177 if (bVert) {
178 // move into the direction of the center, as a basic position for the rotation
179 pC1->AdjustY( -y0 );
180 // resize, account for the distance from the center
181 pC1->setY(FRound(static_cast<double>(pC1->Y()) /rRad.X()*(cx-pC1->X())) );
182 pC1->AdjustY(cy );
183 } else {
184 // move into the direction of the center, as a basic position for the rotation
185 pC1->AdjustX( -x0 );
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) );
190 pC1->AdjustX(cx );
191 }
192 RotatePoint(*pC1,rCenter,sn,cs);
193 }
194 if (bC2) {
195 if (bVert) {
196 // move into the direction of the center, as a basic position for the rotation
197 pC2->AdjustY( -y0 );
198 // resize, account for the distance from the center
199 pC2->setY(FRound(static_cast<double>(pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X())) );
200 pC2->AdjustY(cy );
201 } else {
202 // move into the direction of the center, as a basic position for the rotation
203 pC2->AdjustX( -x0 );
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) );
208 pC2->AdjustX(cx );
209 }
210 RotatePoint(*pC2,rCenter,sn,cs);
211 }
212 rSin=sn;
213 rCos=cs;
214 return nAngle;
215}
216
217double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
218 const Point& rRad, double& rSin, double& rCos, bool bVert)
219{
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;
227 if (bVert) {
228 tools::Long nStart=rCenter.X()-rRad.X();
229 dx1=rPnt.X()-nStart;
230 rPnt.setX(nStart );
231 if (bC1) {
232 dxC1=pC1->X()-nStart;
233 pC1->setX(nStart );
234 }
235 if (bC2) {
236 dxC2=pC2->X()-nStart;
237 pC2->setX(nStart );
238 }
239 } else {
240 tools::Long nStart=rCenter.Y()-rRad.Y();
241 dy1=rPnt.Y()-nStart;
242 rPnt.setY(nStart );
243 if (bC1) {
244 dyC1=pC1->Y()-nStart;
245 pC1->setY(nStart );
246 }
247 if (bC2) {
248 dyC2=pC2->Y()-nStart;
249 pC2->setY(nStart );
250 }
251 }
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); }
258 if (bVert) {
259 rPnt.AdjustX(dx1 );
260 if (bC1) pC1->AdjustX(dxC1 );
261 if (bC2) pC2->AdjustX(dxC2 );
262 } else {
263 rPnt.AdjustY(dy1 );
264 if (bC1) pC1->AdjustY(dyC1 );
265 if (bC2) pC2->AdjustY(dyC2 );
266 }
267 rSin=sn;
268 rCos=cs;
269 return nAngle;
270}
271
272double 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)
275{
276 tools::Long y0=rPnt.Y();
277 CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
278 if (bVert) {
279 } else {
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;
285 a*=dy;
286 rPnt.setY(y0+FRound(a) );
287 }
288 return 0.0;
289}
290
291
292void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
293{
294 double nSin,nCos;
295 sal_uInt16 nPointCnt=rPoly.GetPointCount();
296 sal_uInt16 i=0;
297 while (i<nPointCnt) {
298 Point* pPnt=&rPoly[i];
299 Point* pC1=nullptr;
300 Point* pC2=nullptr;
301 if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
302 pC1=pPnt;
303 i++;
304 pPnt=&rPoly[i];
305 }
306 i++;
307 if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
308 pC2=&rPoly[i];
309 i++;
310 }
311 CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
312 }
313}
314
315void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
316{
317 double nSin,nCos;
318 sal_uInt16 nPointCnt=rPoly.GetPointCount();
319 sal_uInt16 i=0;
320 while (i<nPointCnt) {
321 Point* pPnt=&rPoly[i];
322 Point* pC1=nullptr;
323 Point* pC2=nullptr;
324 if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
325 pC1=pPnt;
326 i++;
327 pPnt=&rPoly[i];
328 }
329 i++;
330 if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
331 pC2=&rPoly[i];
332 i++;
333 }
334 CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
335 }
336}
337
338void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
339{
340 double nSin,nCos;
341 sal_uInt16 nPointCnt=rPoly.GetPointCount();
342 sal_uInt16 i=0;
343 while (i<nPointCnt) {
344 Point* pPnt=&rPoly[i];
345 Point* pC1=nullptr;
346 Point* pC2=nullptr;
347 if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
348 pC1=pPnt;
349 i++;
350 pPnt=&rPoly[i];
351 }
352 i++;
353 if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
354 pC2=&rPoly[i];
355 i++;
356 }
357 CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
358 }
359}
360
361
362void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
363{
364 sal_uInt16 nPolyCount=rPoly.Count();
365 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
366 CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
367 }
368}
369
370void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
371{
372 sal_uInt16 nPolyCount=rPoly.Count();
373 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
374 CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
375 }
376}
377
378void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
379{
380 sal_uInt16 nPolyCount=rPoly.Count();
381 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
382 CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
383 }
384}
385
386
388{
389 Degree100 a;
390 if (rPnt.Y()==0) {
391 if (rPnt.X()<0) a=-18000_deg100;
392 } else if (rPnt.X()==0) {
393 if (rPnt.Y()>0) a=-9000_deg100;
394 else a=9000_deg100;
395 } else {
396 a = Degree100(FRound(basegfx::rad2deg<100>(atan2(static_cast<double>(-rPnt.Y()), static_cast<double>(rPnt.X())))));
397 }
398 return a;
399}
400
402{
403 while (a<-18000_deg100) a+=36000_deg100;
404 while (a>=18000_deg100) a-=36000_deg100;
405 return a;
406}
407
409{
410 a %= 36000_deg100;
411 if (a < 0_deg100)
412 a += 36000_deg100;
413 return a;
414}
415
416sal_uInt16 GetAngleSector(Degree100 nAngle) { return (NormAngle36000(nAngle) / 9000_deg100).get(); }
417
419{
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
423 x*=x;
424 y*=y;
425 x+=y;
426 x=FRound(sqrt(static_cast<double>(x)));
427 return x;
428 } else {
429 double nx=x;
430 double ny=y;
431 nx*=nx;
432 ny*=ny;
433 nx+=ny;
434 nx=sqrt(nx);
435 if (nx>0x7FFFFFFF) {
436 return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
437 } else {
438 return FRound(nx);
439 }
440 }
441}
442
443
445{
446 if (m_nRotationAngle==0_deg100) {
449 } else {
450 double a = toRadians(m_nRotationAngle);
453 }
454}
455
457{
458 if (m_nShearAngle==0_deg100) {
459 mfTanShearAngle=0.0;
460 } else {
461 double a = toRadians(m_nShearAngle);
462 mfTanShearAngle=tan(a);
463 }
464}
465
466
468{
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.m_nShearAngle) ShearPoly(aPol,rRect.TopLeft(),rGeo.mfTanShearAngle);
477 return aPol;
478}
479
480namespace svx
481{
483{
484 rGeo.m_nRotationAngle = GetAngle(rPolygon[1] - rPolygon[0]);
486
487 // rotation successful
488 rGeo.RecalcSinCos();
489
490 Point aPoint1(rPolygon[1] - rPolygon[0]);
491 if (rGeo.m_nRotationAngle)
492 RotatePoint(aPoint1, Point(0,0), -rGeo.mfSinRotationAngle, rGeo.mfCosRotationAngle); // -Sin to reverse rotation
493 tools::Long nWidth = aPoint1.X();
494
495 Point aPoint0(rPolygon[0]);
496 Point aPoint3(rPolygon[3] - rPolygon[0]);
497 if (rGeo.m_nRotationAngle)
498 RotatePoint(aPoint3, Point(0,0), -rGeo.mfSinRotationAngle, rGeo.mfCosRotationAngle); // -Sin to reverse rotation
499 tools::Long nHeight = aPoint3.Y();
500
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
504
505 bool bMirror = aPoint3.Y() < 0;
506 if (bMirror)
507 { // "exchange of points" when mirroring
508 nHeight = -nHeight;
509 nShearAngle += 18000_deg100;
510 aPoint0 = rPolygon[3];
511 }
512
513 nShearAngle = NormAngle18000(nShearAngle);
514 if (nShearAngle < -9000_deg100 || nShearAngle > 9000_deg100)
515 {
516 nShearAngle = NormAngle18000(nShearAngle + 18000_deg100);
517 }
518
519 if (nShearAngle < -SDRMAXSHEAR)
520 nShearAngle = -SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
521
522 if (nShearAngle > SDRMAXSHEAR)
523 nShearAngle = SDRMAXSHEAR;
524
525 rGeo.m_nShearAngle = nShearAngle;
526 rGeo.RecalcTan();
527
528 Point aRU(aPoint0);
529 aRU.AdjustX(nWidth);
530 aRU.AdjustY(nHeight);
531
532 return tools::Rectangle(aPoint0, aRU);
533}
534
535} // end svx
536
537void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
538{
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) ) );
548 } else {
549 rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
550 }
551}
552
553void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
554{
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) ) );
561 } else {
562 rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
563 }
564}
565
566
568{
569 if (!nDiv)
570 return 0x7fffffff;
571 return BigInt::Scale(nVal, nMul, nDiv);
572}
573
575{
576 const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
577 return FrPair(nNum, nDen);
578}
579
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)
582
584{
585 switch (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 : {
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());
601 }
602 case MapUnit::MapAppFont: case MapUnit::MapSysFont: {
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());
609 }
610 default: break;
611 }
612 return Fraction(1,1);
613}
614
615// Calculate the factor that we need to convert units from eS to eD.
616// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
617
619{
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); }
632 return aRet;
633};
634
636{
637 if (eS==eD) return FrPair(1,1,1,1);
638 auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD);
639 if (eFrom == o3tl::Length::invalid)
640 {
641 if (eTo == o3tl::Length::invalid)
642 return FrPair(1,1,1,1);
644 }
645 else if (eTo == o3tl::Length::invalid)
647 return toPair(eFrom, eTo);
648};
649
651{
654 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
655 {
656 const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
657 sal_Int64 nMul = mul;
658 sal_Int64 nDiv = div;
659 short nComma = 0;
660
661 // shorten trailing zeros for dividend
662 while (0 == (nMul % 10))
663 {
664 nComma--;
665 nMul /= 10;
666 }
667
668 // shorten trailing zeros for divisor
669 while (0 == (nDiv % 10))
670 {
671 nComma++;
672 nDiv /= 10;
673 }
674 m_nMul = nMul;
675 m_nDiv = nDiv;
676 m_nComma = nComma;
677 }
678 else
679 {
680 m_nMul = m_nDiv = 1;
681 m_nComma = 0;
682 }
683 m_bDirty=false;
684}
685
686
688{
689 static constexpr OUStringLiteral aNullCode(u"0");
690
691 if(!nVal)
692 {
693 return aNullCode;
694 }
695
696 // we may lose some decimal places here, because of MulDiv instead of Real
697 bool bNeg(nVal < 0);
698 SvtSysLocale aSysLoc;
699 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
700
701 if (m_bDirty)
702 const_cast<SdrFormatter*>(this)->Undirty();
703
704 sal_Int16 nC(m_nComma);
705
706 if(bNeg)
707 nVal = -nVal;
708
709 while(nC <= -3)
710 {
711 nVal *= 1000;
712 nC += 3;
713 }
714
715 while(nC <= -1)
716 {
717 nVal *= 10;
718 nC++;
719 }
720
721 if(m_nMul != m_nDiv)
722 nVal = BigMulDiv(nVal, m_nMul, m_nDiv);
723
724 OUStringBuffer aStr = OUString::number(nVal);
725
726 if(nC > 0 && aStr.getLength() <= nC )
727 {
728 // decimal separator necessary
729 sal_Int32 nCount(nC - aStr.getLength());
730
732 nCount++;
733
734 for(sal_Int32 i=0; i<nCount; i++)
735 aStr.insert(0, aNullCode);
736
737 // remove superfluous decimal points
738 sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits());
739 sal_Int32 nWeg(nC - nNumDigits);
740
741 if(nWeg > 0)
742 {
743 // TODO: we should round here
744 aStr.remove(aStr.getLength() - nWeg, nWeg);
745 nC = nNumDigits;
746 }
747 }
748
749 // remember everything before the decimal separator for later
750 sal_Int32 nForComma(aStr.getLength() - nC);
751
752 if(nC > 0)
753 {
754 // insert comma char (decimal separator)
755 // remove trailing zeros
756 while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode.getStr()[0])
757 {
758 aStr.remove(aStr.getLength() - 1, 1);
759 nC--;
760 }
761
762 if(nC > 0)
763 {
764 // do we still have decimal places?
765 sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
766 aStr.insert(nForComma, cDec);
767 }
768 }
769
770 // add in thousands separator (if necessary)
771 if( nForComma > 3 )
772 {
773 const OUString& aThoSep( rLoc.getNumThousandSep() );
774 if ( aThoSep.getLength() > 0 )
775 {
776 sal_Unicode cTho( aThoSep[0] );
777 sal_Int32 i(nForComma - 3);
778
779 while(i > 0)
780 {
781 aStr.insert(i, cTho);
782 i -= 3;
783 }
784 }
785 }
786
787 if(aStr.isEmpty())
788 aStr.append(aNullCode);
789
790 if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode.getStr()[0]))
791 {
792 aStr.insert(0, "-");
793 }
794
795 return aStr.makeStringAndClear();
796}
797
799{
800 switch(eUnit)
801 {
802 // metrically
803 case MapUnit::Map100thMM :
804 return "/100mm";
805 case MapUnit::Map10thMM :
806 return "/10mm";
807 case MapUnit::MapMM :
808 return "mm";
809 case MapUnit::MapCM :
810 return "cm";
811
812 // Inch
813 case MapUnit::Map1000thInch:
814 return "/1000\"";
815 case MapUnit::Map100thInch :
816 return "/100\"";
817 case MapUnit::Map10thInch :
818 return "/10\"";
819 case MapUnit::MapInch :
820 return "\"";
821 case MapUnit::MapPoint :
822 return "pt";
823 case MapUnit::MapTwip :
824 return "twip";
825
826 // others
827 case MapUnit::MapPixel :
828 return "pixel";
829 case MapUnit::MapSysFont :
830 return "sysfont";
831 case MapUnit::MapAppFont :
832 return "appfont";
833 case MapUnit::MapRelative :
834 return "%";
835 default:
836 return OUString();
837 }
838}
839
841{
842 switch(eUnit)
843 {
844 default :
845 case FieldUnit::NONE :
846 case FieldUnit::CUSTOM :
847 return OUString();
848
849 // metrically
850 case FieldUnit::MM_100TH:
851 return "/100mm";
852 case FieldUnit::MM :
853 return "mm";
854 case FieldUnit::CM :
855 return "cm";
856 case FieldUnit::M :
857 return "m";
858 case FieldUnit::KM :
859 return "km";
860
861 // Inch
862 case FieldUnit::TWIP :
863 return "twip";
864 case FieldUnit::POINT :
865 return "pt";
866 case FieldUnit::PICA :
867 return "pica";
868 case FieldUnit::INCH :
869 return "\"";
870 case FieldUnit::FOOT :
871 return "ft";
872 case FieldUnit::MILE :
873 return "mile(s)";
874
875 // others
876 case FieldUnit::PERCENT:
877 return "%";
878 }
879}
880
881
882/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
constexpr o3tl::Length MapToO3tlLength(MapUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
double ny
double nx
static tools::Long Scale(tools::Long nVal, tools::Long nMult, tools::Long nDiv)
const Fraction & X() const
Definition: svdtrans.hxx:236
const Fraction & Y() const
Definition: svdtrans.hxx:237
bool IsValid() const
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:201
double mfTanShearAngle
Definition: svdtrans.hxx:205
double mfCosRotationAngle
Definition: svdtrans.hxx:207
double mfSinRotationAngle
Definition: svdtrans.hxx:206
void RecalcTan()
Definition: svdtrans.cxx:456
void RecalcSinCos()
Definition: svdtrans.cxx:444
Degree100 m_nShearAngle
Definition: svdtrans.hxx:204
Degree100 m_nRotationAngle
Definition: svdtrans.hxx:203
const OUString & getNumThousandSep() const
const OUString & getNumDecimalSep() const
static sal_uInt16 getNumDigits()
static bool isNumLeadingZero()
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
tools::Long m_nDiv
Definition: svdtrans.hxx:268
SVX_DLLPRIVATE void Undirty()
Definition: svdtrans.cxx:650
static OUString GetUnitStr(MapUnit eUnit)
Definition: svdtrans.cxx:798
tools::Long m_nMul
Definition: svdtrans.hxx:267
MapUnit m_eDstMU
Definition: svdtrans.hxx:272
MapUnit m_eSrcMU
Definition: svdtrans.hxx:271
short m_nComma
Definition: svdtrans.hxx:269
OUString GetStr(tools::Long nVal) const
Definition: svdtrans.cxx:687
const LocaleDataWrapper & GetLocaleData() const
sal_uInt16 Count() const
Definition: _xpoly.cxx:885
void Move(tools::Long nHorzMove, tools::Long nVertMove)
Definition: _xpoly.cxx:381
bool IsControl(sal_uInt16 nPos) const
short path to read the CONTROL flag directly (TODO: better explain what the sense behind this flag is...
Definition: _xpoly.cxx:466
sal_uInt16 GetPointCount() const
Definition: _xpoly.cxx:346
sal_uInt16 GetSize() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr void SetRight(tools::Long v)
constexpr tools::Long Right() const
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr void SetBottom(tools::Long v)
constexpr Point BottomRight() const
constexpr Point TopRight() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr Point BottomLeft() const
int nCount
double toRadians(D x)
float u
float y
float x
FieldUnit
tools::Long FRound(double fVal)
uno_Any a
#define SAL_WARN(area, stream)
MapUnit
aStr
int i
double div(const double &fNumerator, const double &fDenominator)
tools::Rectangle polygonToRectangle(const tools::Polygon &rPolygon, GeoStat &rGeo)
Definition: svdtrans.cxx:482
long Long
void ResizeRect(tools::Rectangle &rRect, const Point &rRef, const Fraction &rxFact, const Fraction &ryFact)
Definition: svdtrans.cxx:38
void CrookStretchPoly(XPolygon &rPoly, const Point &rCenter, const Point &rRad, bool bVert, const tools::Rectangle &rRefRect)
Definition: svdtrans.cxx:338
void CrookRotatePoly(XPolygon &rPoly, const Point &rCenter, const Point &rRad, bool bVert)
Definition: svdtrans.cxx:292
void ResizeXPoly(XPolygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:73
double CrookRotateXPoint(Point &rPnt, Point *pC1, Point *pC2, const Point &rCenter, const Point &rRad, double &rSin, double &rCos, bool bVert)
The following methods accept a point of an XPolygon, whereas the neighbouring control points of the a...
Definition: svdtrans.cxx:163
void ShearXPoly(XPolygon &rPoly, const Point &rRef, double tn, bool bVShear)
Definition: svdtrans.cxx:155
FrPair GetMapFactor(MapUnit eS, MapUnit eD)
Definition: svdtrans.cxx:618
void OrthoDistance4(const Point &rPt0, Point &rPt, bool bBigOrtho)
Definition: svdtrans.cxx:553
tools::Polygon Rect2Poly(const tools::Rectangle &rRect, const GeoStat &rGeo)
Definition: svdtrans.cxx:467
void RotateXPoly(XPolygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:89
double CrookSlantXPoint(Point &rPnt, Point *pC1, Point *pC2, const Point &rCenter, const Point &rRad, double &rSin, double &rCos, bool bVert)
Definition: svdtrans.cxx:217
static FrPair GetInchOrMM(MapUnit eU)
Definition: svdtrans.cxx:583
void OrthoDistance8(const Point &rPt0, Point &rPt, bool bBigOrtho)
Definition: svdtrans.cxx:537
double CrookStretchXPoint(Point &rPnt, Point *pC1, Point *pC2, const Point &rCenter, const Point &rRad, double &rSin, double &rCos, bool bVert, const tools::Rectangle &rRefRect)
Definition: svdtrans.cxx:272
sal_uInt16 GetAngleSector(Degree100 nAngle)
Normalize angle to 0.00..359.99.
Definition: svdtrans.cxx:416
void CrookSlantPoly(XPolygon &rPoly, const Point &rCenter, const Point &rRad, bool bVert)
Definition: svdtrans.cxx:315
Degree100 GetAngle(const Point &rPnt)
The Y axis points down! The function negates the Y axis, when calculating the angle,...
Definition: svdtrans.cxx:387
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
void RotatePoly(tools::Polygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:81
void ShearPoly(tools::Polygon &rPoly, const Point &rRef, double tn)
Definition: svdtrans.cxx:147
Degree100 NormAngle18000(Degree100 a)
Definition: svdtrans.cxx:401
tools::Long GetLen(const Point &rPnt)
Determine sector within the cartesian coordinate system.
Definition: svdtrans.cxx:418
static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo)
Definition: svdtrans.cxx:574
tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
Definition: svdtrans.cxx:567
Degree100 NormAngle36000(Degree100 a)
Normalize angle to -180.00..179.99.
Definition: svdtrans.cxx:408
void ResizePoly(tools::Polygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:65
void MoveXPoly(XPolygon &rPoly, const Size &S)
Definition: svdtrans.cxx:33
void MirrorXPoly(XPolygon &rPoly, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:139
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:109
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:101
constexpr Degree100 SDRMAXSHEAR(8900)
double GetCrookAngle(Point &rPnt, const Point &rCenter, const Point &rRad, bool bVertical)
rPnt.X/rPnt.Y is set to rCenter.X or rCenter.Y! We then only need to rotate rPnt by rCenter.
Definition: svdtrans.hxx:122
void ResizePoint(Point &rPnt, const Point &rRef, const Fraction &xFract, const Fraction &yFract)
Definition: svdtrans.hxx:93
bool IsInch(MapUnit eU)
Definition: svdtrans.hxx:250
sal_uInt16 sal_Unicode