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>
28 #include <tools/UnitConversion.hxx>
29 #include <unotools/syslocale.hxx>
31 #include <sal/log.hxx>
32 
33 void MoveXPoly(XPolygon& rPoly, const Size& S)
34 {
35  rPoly.Move(S.Width(),S.Height());
36 }
37 
38 void 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.Justify();
62 }
63 
64 
65 void 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 
73 void 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 
81 void 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 
89 void 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 
97 void 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 
105 void 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 = nAngle.get() * F_PI18000;
132  double nSin=sin(a);
133  double nCos=cos(a);
134  RotatePoint(rPnt,Point(),nSin,nCos);
135  rPnt+=rRef1;
136  }
137 }
138 
139 void 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 
147 void 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 
155 void 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 
163 double 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 
217 double 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 
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)
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 
292 void 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 
315 void 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 
338 void 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 
362 void 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 
370 void 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 
378 void 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 
387 Degree100 GetAngle(const Point& rPnt)
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(atan2(static_cast<double>(-rPnt.Y()), static_cast<double>(rPnt.X()))
397  / F_PI18000));
398  }
399  return a;
400 }
401 
403 {
404  while (a<-18000_deg100) a+=36000_deg100;
405  while (a>=18000_deg100) a-=36000_deg100;
406  return a;
407 }
408 
410 {
411  // do an add because we want -90 to end up as 270
412  int a = 36000 + deg100.get();
413  a %= 36000;
414  a = std::abs(a);
415  return Degree100(a);
416 }
417 
418 sal_uInt16 GetAngleSector(Degree100 nAngle)
419 {
420  nAngle = NormAngle36000(nAngle);
421  if (nAngle< 9000_deg100) return 0;
422  if (nAngle<18000_deg100) return 1;
423  if (nAngle<27000_deg100) return 2;
424  return 3;
425 }
426 
427 tools::Long GetLen(const Point& rPnt)
428 {
429  tools::Long x=std::abs(rPnt.X());
430  tools::Long y=std::abs(rPnt.Y());
431  if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
432  x*=x;
433  y*=y;
434  x+=y;
435  x=FRound(sqrt(static_cast<double>(x)));
436  return x;
437  } else {
438  double nx=x;
439  double ny=y;
440  nx*=nx;
441  ny*=ny;
442  nx+=ny;
443  nx=sqrt(nx);
444  if (nx>0x7FFFFFFF) {
445  return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
446  } else {
447  return FRound(nx);
448  }
449  }
450 }
451 
452 
454 {
455  if (nRotationAngle==0_deg100) {
456  mfSinRotationAngle=0.0;
457  mfCosRotationAngle=1.0;
458  } else {
459  double a = nRotationAngle.get() * F_PI18000;
460  mfSinRotationAngle=sin(a);
461  mfCosRotationAngle=cos(a);
462  }
463 }
464 
466 {
467  if (nShearAngle==0_deg100) {
468  mfTanShearAngle=0.0;
469  } else {
470  double a = nShearAngle.get() * F_PI18000;
471  mfTanShearAngle=tan(a);
472  }
473 }
474 
475 
477 {
478  tools::Polygon aPol(5);
479  aPol[0]=rRect.TopLeft();
480  aPol[1]=rRect.TopRight();
481  aPol[2]=rRect.BottomRight();
482  aPol[3]=rRect.BottomLeft();
483  aPol[4]=rRect.TopLeft();
484  if (rGeo.nShearAngle) ShearPoly(aPol,rRect.TopLeft(),rGeo.mfTanShearAngle);
485  if (rGeo.nRotationAngle) RotatePoly(aPol,rRect.TopLeft(),rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle);
486  return aPol;
487 }
488 
489 void Poly2Rect(const tools::Polygon& rPol, tools::Rectangle& rRect, GeoStat& rGeo)
490 {
491  rGeo.nRotationAngle=GetAngle(rPol[1]-rPol[0]);
493  // rotation successful
494  rGeo.RecalcSinCos();
495 
496  Point aPt1(rPol[1]-rPol[0]);
497  if (rGeo.nRotationAngle) RotatePoint(aPt1,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation
498  tools::Long nWdt=aPt1.X();
499 
500  Point aPt0(rPol[0]);
501  Point aPt3(rPol[3]-rPol[0]);
502  if (rGeo.nRotationAngle) RotatePoint(aPt3,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation
503  tools::Long nHgt=aPt3.Y();
504 
505 
506  Degree100 nShW=GetAngle(aPt3);
507  nShW-=27000_deg100; // ShearWink is measured against a vertical line
508  nShW=-nShW; // negating, because '+' is shearing clock-wise
509 
510  bool bMirr=aPt3.Y()<0;
511  if (bMirr) { // "exchange of points" when mirroring
512  nHgt=-nHgt;
513  nShW+=18000_deg100;
514  aPt0=rPol[3];
515  }
516  nShW=NormAngle18000(nShW);
517  if (nShW<-9000_deg100 || nShW>9000_deg100) {
518  nShW=NormAngle18000(nShW+18000_deg100);
519  }
520  if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
521  if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
522  rGeo.nShearAngle=nShW;
523  rGeo.RecalcTan();
524  Point aRU(aPt0);
525  aRU.AdjustX(nWdt );
526  aRU.AdjustY(nHgt );
527  rRect=tools::Rectangle(aPt0,aRU);
528 }
529 
530 
531 void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
532 {
533  tools::Long dx=rPt.X()-rPt0.X();
534  tools::Long dy=rPt.Y()-rPt0.Y();
535  tools::Long dxa=std::abs(dx);
536  tools::Long dya=std::abs(dy);
537  if (dx==0 || dy==0 || dxa==dya) return;
538  if (dxa>=dya*2) { rPt.setY(rPt0.Y() ); return; }
539  if (dya>=dxa*2) { rPt.setX(rPt0.X() ); return; }
540  if ((dxa<dya) != bBigOrtho) {
541  rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
542  } else {
543  rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
544  }
545 }
546 
547 void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
548 {
549  tools::Long dx=rPt.X()-rPt0.X();
550  tools::Long dy=rPt.Y()-rPt0.Y();
551  tools::Long dxa=std::abs(dx);
552  tools::Long dya=std::abs(dy);
553  if ((dxa<dya) != bBigOrtho) {
554  rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
555  } else {
556  rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
557  }
558 }
559 
560 
562 {
563  if (!nDiv)
564  return 0x7fffffff;
565  return BigInt::Scale(nVal, nMul, nDiv);
566 }
567 
569 {
570  const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
571  return FrPair(nNum, nDen);
572 }
573 
574 // How many eU units fit into a mm, respectively an inch?
575 // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
576 
578 {
579  switch (eU) {
580  case MapUnit::Map1000thInch: return toPair(o3tl::Length::in, o3tl::Length::in1000);
581  case MapUnit::Map100thInch : return toPair(o3tl::Length::in, o3tl::Length::in100);
582  case MapUnit::Map10thInch : return toPair(o3tl::Length::in, o3tl::Length::in10);
583  case MapUnit::MapInch : return toPair(o3tl::Length::in, o3tl::Length::in);
584  case MapUnit::MapPoint : return toPair(o3tl::Length::in, o3tl::Length::pt);
585  case MapUnit::MapTwip : return toPair(o3tl::Length::in, o3tl::Length::twip);
586  case MapUnit::Map100thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm100);
587  case MapUnit::Map10thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm10);
588  case MapUnit::MapMM : return toPair(o3tl::Length::mm, o3tl::Length::mm);
589  case MapUnit::MapCM : return toPair(o3tl::Length::mm, o3tl::Length::cm);
590  case MapUnit::MapPixel : {
592  pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
593  Point aP(pVD->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
594  return FrPair(6400,aP.X(),6400,aP.Y());
595  }
596  case MapUnit::MapAppFont: case MapUnit::MapSysFont: {
598  pVD->SetMapMode(MapMode(eU));
599  Point aP(pVD->LogicToPixel(Point(32,32))); // 32 units for more accuracy
600  pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
601  aP=pVD->PixelToLogic(aP);
602  return FrPair(3200,aP.X(),3200,aP.Y());
603  }
604  default: break;
605  }
606  return Fraction(1,1);
607 }
608 
609 // Calculate the factor that we need to convert units from eS to eD.
610 // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
611 
613 {
614  if (eS==eD) return FrPair(1,1,1,1);
615  const auto eFrom = MapToO3tlLength(eS, o3tl::Length::invalid);
616  const auto eTo = MapToO3tlLength(eD, o3tl::Length::invalid);
617  if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
618  return toPair(eFrom, eTo);
619  FrPair aS(GetInchOrMM(eS));
620  FrPair aD(GetInchOrMM(eD));
621  bool bSInch=IsInch(eS);
622  bool bDInch=IsInch(eD);
623  FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
624  if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
625  if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
626  return aRet;
627 };
628 
630 {
631  if (eS==eD) return FrPair(1,1,1,1);
632  auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD);
633  if (eFrom == o3tl::Length::invalid)
634  {
635  if (eTo == o3tl::Length::invalid)
636  return FrPair(1,1,1,1);
637  eFrom = IsInch(eD) ? o3tl::Length::in : o3tl::Length::mm;
638  }
639  else if (eTo == o3tl::Length::invalid)
641  return toPair(eFrom, eTo);
642 };
643 
645 {
648  if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
649  {
650  const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
651  sal_Int64 nMul = mul;
652  sal_Int64 nDiv = div;
653  short nComma = 0;
654 
655  // shorten trailing zeros for dividend
656  while (0 == (nMul % 10))
657  {
658  nComma--;
659  nMul /= 10;
660  }
661 
662  // shorten trailing zeros for divisor
663  while (0 == (nDiv % 10))
664  {
665  nComma++;
666  nDiv /= 10;
667  }
668  nMul_ = nMul;
669  nDiv_ = nDiv;
670  nComma_ = nComma;
671  }
672  else
673  {
674  nMul_ = nDiv_ = 1;
675  nComma_ = 0;
676  }
677  bDirty=false;
678 }
679 
680 
681 OUString SdrFormatter::GetStr(tools::Long nVal) const
682 {
683  const OUString aNullCode("0");
684 
685  if(!nVal)
686  {
687  return aNullCode;
688  }
689 
690  // we may lose some decimal places here, because of MulDiv instead of Real
691  bool bNeg(nVal < 0);
692  SvtSysLocale aSysLoc;
693  const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
694 
695  if (bDirty)
696  const_cast<SdrFormatter*>(this)->Undirty();
697 
698  sal_Int16 nC(nComma_);
699 
700  if(bNeg)
701  nVal = -nVal;
702 
703  while(nC <= -3)
704  {
705  nVal *= 1000;
706  nC += 3;
707  }
708 
709  while(nC <= -1)
710  {
711  nVal *= 10;
712  nC++;
713  }
714 
715  if(nMul_ != nDiv_)
716  nVal = BigMulDiv(nVal, nMul_, nDiv_);
717 
718  OUStringBuffer aStr = OUString::number(nVal);
719 
720  if(nC > 0 && aStr.getLength() <= nC )
721  {
722  // decimal separator necessary
723  sal_Int32 nCount(nC - aStr.getLength());
724 
726  nCount++;
727 
728  for(sal_Int32 i=0; i<nCount; i++)
729  aStr.insert(0, aNullCode);
730 
731  // remove superfluous decimal points
732  sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits());
733  sal_Int32 nWeg(nC - nNumDigits);
734 
735  if(nWeg > 0)
736  {
737  // TODO: we should round here
738  aStr.remove(aStr.getLength() - nWeg, nWeg);
739  nC = nNumDigits;
740  }
741  }
742 
743  // remember everything before the decimal separator for later
744  sal_Int32 nForComma(aStr.getLength() - nC);
745 
746  if(nC > 0)
747  {
748  // insert comma char (decimal separator)
749  // remove trailing zeros
750  while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode[0])
751  {
752  aStr.remove(aStr.getLength() - 1, 1);
753  nC--;
754  }
755 
756  if(nC > 0)
757  {
758  // do we still have decimal places?
759  sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
760  aStr.insert(nForComma, cDec);
761  }
762  }
763 
764  // add in thousands separator (if necessary)
765  if( nForComma > 3 )
766  {
767  const OUString& aThoSep( rLoc.getNumThousandSep() );
768  if ( aThoSep.getLength() > 0 )
769  {
770  sal_Unicode cTho( aThoSep[0] );
771  sal_Int32 i(nForComma - 3);
772 
773  while(i > 0)
774  {
775  aStr.insert(i, cTho);
776  i -= 3;
777  }
778  }
779  }
780 
781  if(aStr.isEmpty())
782  aStr.append(aNullCode);
783 
784  if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode[0]))
785  {
786  aStr.insert(0, "-");
787  }
788 
789  return aStr.makeStringAndClear();
790 }
791 
793 {
794  switch(eUnit)
795  {
796  // metrically
797  case MapUnit::Map100thMM :
798  return "/100mm";
799  case MapUnit::Map10thMM :
800  return "/10mm";
801  case MapUnit::MapMM :
802  return "mm";
803  case MapUnit::MapCM :
804  return "cm";
805 
806  // Inch
807  case MapUnit::Map1000thInch:
808  return "/1000\"";
809  case MapUnit::Map100thInch :
810  return "/100\"";
811  case MapUnit::Map10thInch :
812  return "/10\"";
813  case MapUnit::MapInch :
814  return "\"";
815  case MapUnit::MapPoint :
816  return "pt";
817  case MapUnit::MapTwip :
818  return "twip";
819 
820  // others
821  case MapUnit::MapPixel :
822  return "pixel";
823  case MapUnit::MapSysFont :
824  return "sysfont";
825  case MapUnit::MapAppFont :
826  return "appfont";
827  case MapUnit::MapRelative :
828  return "%";
829  default:
830  return OUString();
831  }
832 }
833 
835 {
836  switch(eUnit)
837  {
838  default :
839  case FieldUnit::NONE :
840  case FieldUnit::CUSTOM :
841  return OUString();
842 
843  // metrically
844  case FieldUnit::MM_100TH:
845  return "/100mm";
846  case FieldUnit::MM :
847  return "mm";
848  case FieldUnit::CM :
849  return "cm";
850  case FieldUnit::M :
851  return "m";
852  case FieldUnit::KM :
853  return "km";
854 
855  // Inch
856  case FieldUnit::TWIP :
857  return "twip";
858  case FieldUnit::POINT :
859  return "pt";
860  case FieldUnit::PICA :
861  return "pica";
862  case FieldUnit::INCH :
863  return "\"";
864  case FieldUnit::FOOT :
865  return "ft";
866  case FieldUnit::MILE :
867  return "mile(s)";
868 
869  // others
870  case FieldUnit::PERCENT:
871  return "%";
872  }
873 }
874 
875 
876 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString GetUnitStr(MapUnit eUnit)
Definition: svdtrans.cxx:792
FieldUnit
void ShearXPoly(XPolygon &rPoly, const Point &rRef, double tn, bool bVShear)
Definition: svdtrans.cxx:155
sal_uInt16 Count() const
Definition: _xpoly.cxx:890
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:122
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
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:135
void ResizePoint(Point &rPnt, const Point &rRef, const Fraction &xFract, const Fraction &yFract)
Definition: svdtrans.hxx:106
void ResizePoly(tools::Polygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:65
Point BottomLeft() const
constexpr Degree100 SDRMAXSHEAR(8900)
void ResizeXPoly(XPolygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:73
void Poly2Rect(const tools::Polygon &rPol, tools::Rectangle &rRect, GeoStat &rGeo)
Definition: svdtrans.cxx:489
double ny
long Long
double mfSinRotationAngle
Definition: svdtrans.hxx:219
tools::Long GetLen(const Point &rPnt)
Determine sector within the cartesian coordinate system.
Definition: svdtrans.cxx:427
void Move(tools::Long nHorzMove, tools::Long nVertMove)
Definition: _xpoly.cxx:381
constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
static sal_uInt16 getNumDigits()
static bool isNumLeadingZero()
static FrPair GetInchOrMM(MapUnit eU)
Definition: svdtrans.cxx:577
void RotatePoly(tools::Polygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:81
void RecalcTan()
Definition: svdtrans.cxx:465
float x
void SetRight(tools::Long v)
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 ShearPoly(tools::Polygon &rPoly, const Point &rRef, double tn)
Definition: svdtrans.cxx:147
constexpr tools::Long Width() const
sal_uInt16 sal_Unicode
const LocaleDataWrapper & GetLocaleData() const
void CrookRotatePoly(XPolygon &rPoly, const Point &rCenter, const Point &rRad, bool bVert)
Definition: svdtrans.cxx:292
tools::Long Left() const
void SetLeft(tools::Long v)
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
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:214
int nCount
tools::Long Bottom() const
Degree100 NormAngle36000(Degree100 deg100)
Normalize angle to -180.00..179.99.
Definition: svdtrans.cxx:409
tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
Definition: svdtrans.cxx:561
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
double mfTanShearAngle
Definition: svdtrans.hxx:218
float y
Point BottomRight() const
const OUString & getNumDecimalSep() const
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
UNDERLYING_TYPE get() const
constexpr std::pair< sal_Int64, sal_Int64 > getConversionMulDiv(U from, U to)
int i
MapUnit eSrcMU
Definition: svdtrans.hxx:280
void MirrorXPoly(XPolygon &rPoly, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:139
short nComma_
Definition: svdtrans.hxx:278
uno_Any a
const Fraction & Y() const
Definition: svdtrans.hxx:246
tools::Long FRound(double fVal)
Degree100 GetAngle(const Point &rPnt)
The Y axis points down! The function negates the Y axis, when calculating the angle, such that GetAngle(Point(0,-1))=90 deg.
Definition: svdtrans.cxx:387
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
const Fraction & X() const
Definition: svdtrans.hxx:245
static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo)
Definition: svdtrans.cxx:568
void OrthoDistance8(const Point &rPt0, Point &rPt, bool bBigOrtho)
Definition: svdtrans.cxx:531
sal_uInt16 GetSize() const
tools::Polygon Rect2Poly(const tools::Rectangle &rRect, const GeoStat &rGeo)
Definition: svdtrans.cxx:476
void SetTop(tools::Long v)
void SetBottom(tools::Long v)
MapUnit eDstMU
Definition: svdtrans.hxx:281
tools::Long Top() const
constexpr Point TopLeft() const
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:114
FrPair GetMapFactor(MapUnit eS, MapUnit eD)
Definition: svdtrans.cxx:612
tools::Long nMul_
Definition: svdtrans.hxx:276
double nx
constexpr tools::Long Height() const
void RecalcSinCos()
Definition: svdtrans.cxx:453
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
constexpr o3tl::Length MapToO3tlLength(MapUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
Degree100 nRotationAngle
Definition: svdtrans.hxx:216
double CrookSlantXPoint(Point &rPnt, Point *pC1, Point *pC2, const Point &rCenter, const Point &rRad, double &rSin, double &rCos, bool bVert)
Definition: svdtrans.cxx:217
constexpr Point TopRight() const
double mfCosRotationAngle
Definition: svdtrans.hxx:220
#define F_PI18000
tools::Long nDiv_
Definition: svdtrans.hxx:277
static tools::Long Scale(tools::Long nVal, tools::Long nMult, tools::Long nDiv)
bool IsInch(MapUnit eU)
Definition: svdtrans.hxx:259
const OUString & getNumThousandSep() const
SVX_DLLPRIVATE void Undirty()
Definition: svdtrans.cxx:644
Degree100 NormAngle18000(Degree100 a)
Definition: svdtrans.cxx:402
void RotateXPoly(XPolygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:89
MapUnit
#define SAL_WARN(area, stream)
bool IsValid() const
void CrookSlantPoly(XPolygon &rPoly, const Point &rCenter, const Point &rRad, bool bVert)
Definition: svdtrans.cxx:315
sal_uInt16 GetPointCount() const
Definition: _xpoly.cxx:346
void MoveXPoly(XPolygon &rPoly, const Size &S)
Definition: svdtrans.cxx:33
void OrthoDistance4(const Point &rPt0, Point &rPt, bool bBigOrtho)
Definition: svdtrans.cxx:547
aStr
Degree100 nShearAngle
Definition: svdtrans.hxx:217
tools::Long Right() const
double div(const double &fNumerator, const double &fDenominator)
sal_uInt16 GetAngleSector(Degree100 nAngle)
Normalize angle to 0.00..359.99.
Definition: svdtrans.cxx:418
OUString GetStr(tools::Long nVal) const
Definition: svdtrans.cxx:681