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