bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / svdraw / svdtrans.cxx
blob476b4be808e41ea8b7d4f4ffb3e319ebdfa8c480
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdtrans.hxx>
22 #include <math.h>
23 #include <svx/xpoly.hxx>
25 #include <vcl/virdev.hxx>
26 #include <tools/bigint.hxx>
27 #include <tools/debug.hxx>
28 #include <unotools/syslocale.hxx>
30 void MoveXPoly(XPolygon& rPoly, const Size& S)
32 rPoly.Move(S.Width(),S.Height());
35 void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact, bool bNoJustify)
37 Fraction xFact(rxFact);
38 Fraction yFact(ryFact);
40 if (!xFact.IsValid()) {
41 SAL_WARN( "svx.svdraw", "invalid fraction xFract, using Fraction(1,1)" );
42 xFact = Fraction(1,1);
43 long nWdt = rRect.Right() - rRect.Left();
44 if (nWdt == 0) rRect.Right()++;
46 rRect.Left() = rRef.X() + Round( (rRect.Left() - rRef.X()) * double(xFact) );
47 rRect.Right() = rRef.X() + Round( (rRect.Right() - rRef.X()) * double(xFact) );
49 if (!yFact.IsValid()) {
50 SAL_WARN( "svx.svdraw", "invalid fraction yFract, using Fraction(1,1)" );
51 yFact = Fraction(1,1);
52 long nHgt = rRect.Bottom() - rRect.Top();
53 if (nHgt == 0) rRect.Bottom()++;
55 rRect.Top() = rRef.Y() + Round( (rRect.Top() - rRef.Y()) * double(yFact) );
56 rRect.Bottom() = rRef.Y() + Round( (rRect.Bottom() - rRef.Y()) * double(yFact) );
58 if (!bNoJustify) rRect.Justify();
62 void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
64 sal_uInt16 nCount=rPoly.GetSize();
65 for (sal_uInt16 i=0; i<nCount; i++) {
66 ResizePoint(rPoly[i],rRef,xFact,yFact);
70 void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
72 sal_uInt16 nCount=rPoly.GetPointCount();
73 for (sal_uInt16 i=0; i<nCount; i++) {
74 ResizePoint(rPoly[i],rRef,xFact,yFact);
78 void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
80 sal_uInt16 nCount=rPoly.GetSize();
81 for (sal_uInt16 i=0; i<nCount; i++) {
82 RotatePoint(rPoly[i],rRef,sn,cs);
86 void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
88 sal_uInt16 nCount=rPoly.GetPointCount();
89 for (sal_uInt16 i=0; i<nCount; i++) {
90 RotatePoint(rPoly[i],rRef,sn,cs);
94 void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
96 sal_uInt16 nCount=rPoly.Count();
97 for (sal_uInt16 i=0; i<nCount; i++) {
98 RotateXPoly(rPoly[i],rRef,sn,cs);
102 void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
104 long mx=rRef2.X()-rRef1.X();
105 long my=rRef2.Y()-rRef1.Y();
106 if (mx==0) { // vertical axis
107 long dx=rRef1.X()-rPnt.X();
108 rPnt.X()+=2*dx;
109 } else if (my==0) { // horizontal axis
110 long dy=rRef1.Y()-rPnt.Y();
111 rPnt.Y()+=2*dy;
112 } else if (mx==my) { // diagonal axis '\'
113 long dx1=rPnt.X()-rRef1.X();
114 long dy1=rPnt.Y()-rRef1.Y();
115 rPnt.X()=rRef1.X()+dy1;
116 rPnt.Y()=rRef1.Y()+dx1;
117 } else if (mx==-my) { // diagonal axis '/'
118 long dx1=rPnt.X()-rRef1.X();
119 long dy1=rPnt.Y()-rRef1.Y();
120 rPnt.X()=rRef1.X()-dy1;
121 rPnt.Y()=rRef1.Y()-dx1;
122 } else { // arbitrary axis
123 // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
124 long nRefWink=GetAngle(rRef2-rRef1);
125 rPnt-=rRef1;
126 long nPntWink=GetAngle(rPnt);
127 long nAngle=2*(nRefWink-nPntWink);
128 double a=nAngle*nPi180;
129 double nSin=sin(a);
130 double nCos=cos(a);
131 RotatePoint(rPnt,Point(),nSin,nCos);
132 rPnt+=rRef1;
136 void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
138 sal_uInt16 nCount=rPoly.GetSize();
139 for (sal_uInt16 i=0; i<nCount; i++) {
140 MirrorPoint(rPoly[i],rRef1,rRef2);
144 void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
146 sal_uInt16 nCount=rPoly.GetPointCount();
147 for (sal_uInt16 i=0; i<nCount; i++) {
148 MirrorPoint(rPoly[i],rRef1,rRef2);
152 void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear)
154 sal_uInt16 nCount=rPoly.GetSize();
155 for (sal_uInt16 i=0; i<nCount; i++) {
156 ShearPoint(rPoly[i],rRef,tn,bVShear);
160 void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
162 sal_uInt16 nCount=rPoly.GetPointCount();
163 for (sal_uInt16 i=0; i<nCount; i++) {
164 ShearPoint(rPoly[i],rRef,tn,bVShear);
168 double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
169 const Point& rRad, double& rSin, double& rCos, bool bVert)
171 bool bC1=pC1!=NULL;
172 bool bC2=pC2!=NULL;
173 long x0=rPnt.X();
174 long y0=rPnt.Y();
175 long cx=rCenter.X();
176 long cy=rCenter.Y();
177 double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
178 double sn=sin(nAngle);
179 double cs=cos(nAngle);
180 RotatePoint(rPnt,rCenter,sn,cs);
181 if (bC1) {
182 if (bVert) {
183 // move into the direction of the center, as a basic position for the rotation
184 pC1->Y()-=y0;
185 // resize, account for the distance from the center
186 pC1->Y()=Round(((double)pC1->Y()) /rRad.X()*(cx-pC1->X()));
187 pC1->Y()+=cy;
188 } else {
189 // move into the direction of the center, as a basic position for the rotation
190 pC1->X()-=x0;
191 // resize, account for the distance from the center
192 long nPntRad=cy-pC1->Y();
193 double nFact=(double)nPntRad/(double)rRad.Y();
194 pC1->X()=Round((double)pC1->X()*nFact);
195 pC1->X()+=cx;
197 RotatePoint(*pC1,rCenter,sn,cs);
199 if (bC2) {
200 if (bVert) {
201 // move into the direction of the center, as a basic position for the rotation
202 pC2->Y()-=y0;
203 // resize, account for the distance from the center
204 pC2->Y()=Round(((double)pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X()));
205 pC2->Y()+=cy;
206 } else {
207 // move into the direction of the center, as a basic position for the rotation
208 pC2->X()-=x0;
209 // resize, account for the distance from the center
210 long nPntRad=rCenter.Y()-pC2->Y();
211 double nFact=(double)nPntRad/(double)rRad.Y();
212 pC2->X()=Round((double)pC2->X()*nFact);
213 pC2->X()+=cx;
215 RotatePoint(*pC2,rCenter,sn,cs);
217 rSin=sn;
218 rCos=cs;
219 return nAngle;
222 double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
223 const Point& rRad, double& rSin, double& rCos, bool bVert)
225 bool bC1=pC1!=NULL;
226 bool bC2=pC2!=NULL;
227 long x0=rPnt.X();
228 long y0=rPnt.Y();
229 long dx1=0,dy1=0;
230 long dxC1=0,dyC1=0;
231 long dxC2=0,dyC2=0;
232 if (bVert) {
233 long nStart=rCenter.X()-rRad.X();
234 dx1=rPnt.X()-nStart;
235 rPnt.X()=nStart;
236 if (bC1) {
237 dxC1=pC1->X()-nStart;
238 pC1->X()=nStart;
240 if (bC2) {
241 dxC2=pC2->X()-nStart;
242 pC2->X()=nStart;
244 } else {
245 long nStart=rCenter.Y()-rRad.Y();
246 dy1=rPnt.Y()-nStart;
247 rPnt.Y()=nStart;
248 if (bC1) {
249 dyC1=pC1->Y()-nStart;
250 pC1->Y()=nStart;
252 if (bC2) {
253 dyC2=pC2->Y()-nStart;
254 pC2->Y()=nStart;
257 double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
258 double sn=sin(nAngle);
259 double cs=cos(nAngle);
260 RotatePoint(rPnt,rCenter,sn,cs);
261 if (bC1) { if (bVert) pC1->Y()-=y0-rCenter.Y(); else pC1->X()-=x0-rCenter.X(); RotatePoint(*pC1,rCenter,sn,cs); }
262 if (bC2) { if (bVert) pC2->Y()-=y0-rCenter.Y(); else pC2->X()-=x0-rCenter.X(); RotatePoint(*pC2,rCenter,sn,cs); }
263 if (bVert) {
264 rPnt.X()+=dx1;
265 if (bC1) pC1->X()+=dxC1;
266 if (bC2) pC2->X()+=dxC2;
267 } else {
268 rPnt.Y()+=dy1;
269 if (bC1) pC1->Y()+=dyC1;
270 if (bC2) pC2->Y()+=dyC2;
272 rSin=sn;
273 rCos=cs;
274 return nAngle;
277 double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
278 const Point& rRad, double& rSin, double& rCos, bool bVert,
279 const Rectangle& rRefRect)
281 long y0=rPnt.Y();
282 CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
283 if (bVert) {
284 } else {
285 long nTop=rRefRect.Top();
286 long nBtm=rRefRect.Bottom();
287 long nHgt=nBtm-nTop;
288 long dy=rPnt.Y()-y0;
289 double a=((double)(y0-nTop))/nHgt;
290 a*=dy;
291 rPnt.Y()=y0+Round(a);
292 } return 0.0;
297 void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
299 double nSin,nCos;
300 sal_uInt16 nPointAnz=rPoly.GetPointCount();
301 sal_uInt16 i=0;
302 while (i<nPointAnz) {
303 Point* pPnt=&rPoly[i];
304 Point* pC1=NULL;
305 Point* pC2=NULL;
306 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
307 pC1=pPnt;
308 i++;
309 pPnt=&rPoly[i];
311 i++;
312 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
313 pC2=&rPoly[i];
314 i++;
316 CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
320 void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
322 double nSin,nCos;
323 sal_uInt16 nPointAnz=rPoly.GetPointCount();
324 sal_uInt16 i=0;
325 while (i<nPointAnz) {
326 Point* pPnt=&rPoly[i];
327 Point* pC1=NULL;
328 Point* pC2=NULL;
329 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
330 pC1=pPnt;
331 i++;
332 pPnt=&rPoly[i];
334 i++;
335 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
336 pC2=&rPoly[i];
337 i++;
339 CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
343 void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle& rRefRect)
345 double nSin,nCos;
346 sal_uInt16 nPointAnz=rPoly.GetPointCount();
347 sal_uInt16 i=0;
348 while (i<nPointAnz) {
349 Point* pPnt=&rPoly[i];
350 Point* pC1=NULL;
351 Point* pC2=NULL;
352 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
353 pC1=pPnt;
354 i++;
355 pPnt=&rPoly[i];
357 i++;
358 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
359 pC2=&rPoly[i];
360 i++;
362 CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
368 void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
370 sal_uInt16 nPolyCount=rPoly.Count();
371 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
372 CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
376 void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
378 sal_uInt16 nPolyCount=rPoly.Count();
379 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
380 CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
384 void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle& rRefRect)
386 sal_uInt16 nPolyCount=rPoly.Count();
387 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
388 CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
394 long GetAngle(const Point& rPnt)
396 long a=0;
397 if (rPnt.Y()==0) {
398 if (rPnt.X()<0) a=-18000;
399 } else if (rPnt.X()==0) {
400 if (rPnt.Y()>0) a=-9000;
401 else a=9000;
402 } else {
403 a=Round((atan2((double)-rPnt.Y(),(double)rPnt.X())/nPi180));
405 return a;
408 long NormAngle180(long a)
410 while (a<18000) a+=36000;
411 while (a>=18000) a-=36000;
412 return a;
415 long NormAngle360(long a)
417 while (a<0) a+=36000;
418 while (a>=36000) a-=36000;
419 return a;
422 sal_uInt16 GetAngleSector(long nAngle)
424 while (nAngle<0) nAngle+=36000;
425 while (nAngle>=36000) nAngle-=36000;
426 if (nAngle< 9000) return 0;
427 if (nAngle<18000) return 1;
428 if (nAngle<27000) return 2;
429 return 3;
432 long GetLen(const Point& rPnt)
434 long x=std::abs(rPnt.X());
435 long y=std::abs(rPnt.Y());
436 if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
437 x*=x;
438 y*=y;
439 x+=y;
440 x=Round(sqrt((double)x));
441 return x;
442 } else {
443 double nx=x;
444 double ny=y;
445 nx*=nx;
446 ny*=ny;
447 nx+=ny;
448 nx=sqrt(nx);
449 if (nx>0x7FFFFFFF) {
450 return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
451 } else {
452 return Round(nx);
459 void GeoStat::RecalcSinCos()
461 if (nRotationAngle==0) {
462 nSin=0.0;
463 nCos=1.0;
464 } else {
465 double a=nRotationAngle*nPi180;
466 nSin=sin(a);
467 nCos=cos(a);
471 void GeoStat::RecalcTan()
473 if (nShearAngle==0) {
474 nTan=0.0;
475 } else {
476 double a=nShearAngle*nPi180;
477 nTan=tan(a);
483 Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
485 Polygon aPol(5);
486 aPol[0]=rRect.TopLeft();
487 aPol[1]=rRect.TopRight();
488 aPol[2]=rRect.BottomRight();
489 aPol[3]=rRect.BottomLeft();
490 aPol[4]=rRect.TopLeft();
491 if (rGeo.nShearAngle!=0) ShearPoly(aPol,rRect.TopLeft(),rGeo.nTan);
492 if (rGeo.nRotationAngle!=0) RotatePoly(aPol,rRect.TopLeft(),rGeo.nSin,rGeo.nCos);
493 return aPol;
496 void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
498 rGeo.nRotationAngle=GetAngle(rPol[1]-rPol[0]);
499 rGeo.nRotationAngle=NormAngle360(rGeo.nRotationAngle);
500 // rotation successful
501 rGeo.RecalcSinCos();
503 Point aPt1(rPol[1]-rPol[0]);
504 if (rGeo.nRotationAngle!=0) RotatePoint(aPt1,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
505 long nWdt=aPt1.X();
507 Point aPt0(rPol[0]);
508 Point aPt3(rPol[3]-rPol[0]);
509 if (rGeo.nRotationAngle!=0) RotatePoint(aPt3,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
510 long nHgt=aPt3.Y();
513 long nShW=GetAngle(aPt3);
514 nShW-=27000; // ShearWink is measured against a vertical line
515 nShW=-nShW; // Negieren, denn '+' ist Rechtskursivierung
517 bool bMirr=aPt3.Y()<0;
518 if (bMirr) { // "exchange of points" when mirroring
519 nHgt=-nHgt;
520 nShW+=18000;
521 aPt0=rPol[3];
523 nShW=NormAngle180(nShW);
524 if (nShW<-9000 || nShW>9000) {
525 nShW=NormAngle180(nShW+18000);
527 if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
528 if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
529 rGeo.nShearAngle=nShW;
530 rGeo.RecalcTan();
531 Point aRU(aPt0);
532 aRU.X()+=nWdt;
533 aRU.Y()+=nHgt;
534 rRect=Rectangle(aPt0,aRU);
539 void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
541 long dx=rPt.X()-rPt0.X();
542 long dy=rPt.Y()-rPt0.Y();
543 long dxa=std::abs(dx);
544 long dya=std::abs(dy);
545 if (dx==0 || dy==0 || dxa==dya) return;
546 if (dxa>=dya*2) { rPt.Y()=rPt0.Y(); return; }
547 if (dya>=dxa*2) { rPt.X()=rPt0.X(); return; }
548 if ((dxa<dya) != bBigOrtho) {
549 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
550 } else {
551 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
555 void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
557 long dx=rPt.X()-rPt0.X();
558 long dy=rPt.Y()-rPt0.Y();
559 long dxa=std::abs(dx);
560 long dya=std::abs(dy);
561 if ((dxa<dya) != bBigOrtho) {
562 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
563 } else {
564 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
570 long BigMulDiv(long nVal, long nMul, long nDiv)
572 BigInt aVal(nVal);
573 aVal*=nMul;
574 if (aVal.IsNeg()!=(nDiv<0)) {
575 aVal-=nDiv/2; // to round correctly
576 } else {
577 aVal+=nDiv/2; // to round correctly
579 if(nDiv)
581 aVal/=nDiv;
582 return long(aVal);
584 return 0x7fffffff;
587 void Kuerzen(Fraction& rF, unsigned nDigits)
589 sal_Int32 nMul=rF.GetNumerator();
590 sal_Int32 nDiv=rF.GetDenominator();
591 bool bNeg = false;
592 if (nMul<0) { nMul=-nMul; bNeg=!bNeg; }
593 if (nDiv<0) { nDiv=-nDiv; bNeg=!bNeg; }
594 if (nMul==0 || nDiv==0) return;
595 sal_uInt32 a;
596 a=sal_uInt32(nMul); unsigned nMulZ=0; // count leading zeros
597 while (a<0x00800000) { nMulZ+=8; a<<=8; }
598 while (a<0x80000000) { nMulZ++; a<<=1; }
599 a=sal_uInt32(nDiv); unsigned nDivZ=0; // count leading zeros
600 while (a<0x00800000) { nDivZ+=8; a<<=8; }
601 while (a<0x80000000) { nDivZ++; a<<=1; }
602 // count the number of digits
603 int nMulDigits=32-nMulZ;
604 int nDivDigits=32-nDivZ;
605 // count how many decimal places can be removed
606 int nMulWeg=nMulDigits-nDigits; if (nMulWeg<0) nMulWeg=0;
607 int nDivWeg=nDivDigits-nDigits; if (nDivWeg<0) nDivWeg=0;
608 int nWeg=std::min(nMulWeg,nDivWeg);
609 nMul>>=nWeg;
610 nDiv>>=nWeg;
611 if (nMul==0 || nDiv==0) {
612 DBG_WARNING("Math error after canceling decimal places.");
613 return;
615 if (bNeg) nMul=-nMul;
616 rF=Fraction(nMul,nDiv);
620 // How many eU units fit into a mm, respectively an inch?
621 // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
623 FrPair GetInchOrMM(MapUnit eU)
625 switch (eU) {
626 case MAP_1000TH_INCH: return FrPair(1000,1);
627 case MAP_100TH_INCH : return FrPair( 100,1);
628 case MAP_10TH_INCH : return FrPair( 10,1);
629 case MAP_INCH : return FrPair( 1,1);
630 case MAP_POINT : return FrPair( 72,1);
631 case MAP_TWIP : return FrPair(1440,1);
632 case MAP_100TH_MM : return FrPair( 100,1);
633 case MAP_10TH_MM : return FrPair( 10,1);
634 case MAP_MM : return FrPair( 1,1);
635 case MAP_CM : return FrPair( 1,10);
636 case MAP_PIXEL : {
637 ScopedVclPtrInstance< VirtualDevice > pVD;
638 pVD->SetMapMode(MapMode(MAP_100TH_MM));
639 Point aP(pVD->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
640 return FrPair(6400,aP.X(),6400,aP.Y());
642 case MAP_APPFONT: case MAP_SYSFONT: {
643 ScopedVclPtrInstance< VirtualDevice > pVD;
644 pVD->SetMapMode(MapMode(eU));
645 Point aP(pVD->LogicToPixel(Point(32,32))); // 32 units for more accuracy
646 pVD->SetMapMode(MapMode(MAP_100TH_MM));
647 aP=pVD->PixelToLogic(aP);
648 return FrPair(3200,aP.X(),3200,aP.Y());
650 default: break;
652 return Fraction(1,1);
655 FrPair GetInchOrMM(FieldUnit eU)
657 switch (eU) {
658 case FUNIT_INCH : return FrPair( 1,1);
659 case FUNIT_POINT : return FrPair( 72,1);
660 case FUNIT_TWIP : return FrPair(1440,1);
661 case FUNIT_100TH_MM : return FrPair( 100,1);
662 case FUNIT_MM : return FrPair( 1,1);
663 case FUNIT_CM : return FrPair( 1,10);
664 case FUNIT_M : return FrPair( 1,1000);
665 case FUNIT_KM : return FrPair( 1,1000000);
666 case FUNIT_PICA : return FrPair( 6,1);
667 case FUNIT_FOOT : return FrPair( 1,12);
668 case FUNIT_MILE : return FrPair( 1,63360);
669 default: break;
671 return Fraction(1,1);
674 // Calculate the factor that we need to convert units from eS to eD.
675 // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
677 FrPair GetMapFactor(MapUnit eS, MapUnit eD)
679 if (eS==eD) return FrPair(1,1,1,1);
680 FrPair aS(GetInchOrMM(eS));
681 FrPair aD(GetInchOrMM(eD));
682 bool bSInch=IsInch(eS);
683 bool bDInch=IsInch(eD);
684 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
685 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
686 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
687 return aRet;
690 FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
692 if (eS==eD) return FrPair(1,1,1,1);
693 FrPair aS(GetInchOrMM(eS));
694 FrPair aD(GetInchOrMM(eD));
695 bool bSInch=IsInch(eS);
696 bool bDInch=IsInch(eD);
697 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
698 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
699 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
700 return aRet;
705 // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
706 // 1 furlong = 10 chains = 7.920" = 201.168,0mm
707 // 1 chain = 4 poles = 792" = 20.116,8mm
708 // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
709 // 1 yd = 3 ft = 36" = 914,4mm
710 // 1 ft = 12 " = 1" = 304,8mm
712 void GetMeterOrInch(MapUnit eMU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
714 rnMul=1; rnDiv=1;
715 short nKomma=0;
716 bool bMetr = false, bInch = false;
717 switch (eMU) {
718 // Metrisch
719 case MAP_100TH_MM : bMetr = true; nKomma=5; break;
720 case MAP_10TH_MM : bMetr = true; nKomma=4; break;
721 case MAP_MM : bMetr = true; nKomma=3; break;
722 case MAP_CM : bMetr = true; nKomma=2; break;
723 // Inch
724 case MAP_1000TH_INCH: bInch = true; nKomma=3; break;
725 case MAP_100TH_INCH : bInch = true; nKomma=2; break;
726 case MAP_10TH_INCH : bInch = true; nKomma=1; break;
727 case MAP_INCH : bInch = true; nKomma=0; break;
728 case MAP_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
729 case MAP_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
730 // Sonstiges
731 case MAP_PIXEL : break;
732 case MAP_SYSFONT : break;
733 case MAP_APPFONT : break;
734 case MAP_RELATIVE : break;
735 default: break;
736 } // switch
737 rnKomma=nKomma;
738 rbMetr=bMetr;
739 rbInch=bInch;
742 void GetMeterOrInch(FieldUnit eFU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
744 rnMul=1; rnDiv=1;
745 short nKomma=0;
746 bool bMetr = false, bInch = false;
747 switch (eFU) {
748 case FUNIT_NONE : break;
749 // metrically
750 case FUNIT_100TH_MM : bMetr = true; nKomma=5; break;
751 case FUNIT_MM : bMetr = true; nKomma=3; break;
752 case FUNIT_CM : bMetr = true; nKomma=2; break;
753 case FUNIT_M : bMetr = true; nKomma=0; break;
754 case FUNIT_KM : bMetr = true; nKomma=-3; break;
755 // Inch
756 case FUNIT_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
757 case FUNIT_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
758 case FUNIT_PICA : bInch = true; rnDiv=6; break; // 1Pica = 1/6" ?
759 case FUNIT_INCH : bInch = true; break; // 1" = 1"
760 case FUNIT_FOOT : bInch = true; rnMul=12; break; // 1Ft = 12"
761 case FUNIT_MILE : bInch = true; rnMul=6336; nKomma=-1; break; // 1mile = 63360"
762 // others
763 case FUNIT_CUSTOM : break;
764 case FUNIT_PERCENT : nKomma=2; break;
765 // TODO: Add code to handle the following (added to remove warning)
766 case FUNIT_CHAR : break;
767 case FUNIT_LINE : break;
768 case FUNIT_PIXEL : break;
769 case FUNIT_DEGREE : break;
770 case FUNIT_SECOND : break;
771 case FUNIT_MILLISECOND : break;
772 } // switch
773 rnKomma=nKomma;
774 rbMetr=bMetr;
775 rbInch=bInch;
778 void SdrFormatter::Undirty()
780 bool bSrcMetr,bSrcInch,bDstMetr,bDstInch;
781 long nMul1,nDiv1,nMul2,nDiv2;
782 short nKomma1,nKomma2;
783 // first: normalize to m or in
784 if (!bSrcFU) {
785 GetMeterOrInch(eSrcMU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
786 } else {
787 GetMeterOrInch(eSrcFU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
789 if (!bDstFU) {
790 GetMeterOrInch(eDstMU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
791 } else {
792 GetMeterOrInch(eDstFU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
794 nMul1*=nDiv2;
795 nDiv1*=nMul2;
796 nKomma1=nKomma1-nKomma2;
798 if (bSrcInch && bDstMetr) {
799 nKomma1+=4;
800 nMul1*=254;
802 if (bSrcMetr && bDstInch) {
803 nKomma1-=4;
804 nDiv1*=254;
807 // temporary fraction for canceling
808 Fraction aTempFract(nMul1,nDiv1);
809 nMul1=aTempFract.GetNumerator();
810 nDiv1=aTempFract.GetDenominator();
812 nMul_=nMul1;
813 nDiv_=nDiv1;
814 nKomma_=nKomma1;
815 bDirty=false;
819 void SdrFormatter::TakeStr(long nVal, OUString& rStr) const
821 OUString aNullCode("0");
823 if(!nVal)
825 rStr = aNullCode;
826 return;
829 // we may lose some decimal places here, because of MulDiv instead of Real
830 bool bNeg(nVal < 0);
831 SvtSysLocale aSysLoc;
832 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
834 ForceUndirty();
836 sal_Int16 nC(nKomma_);
838 if(bNeg)
839 nVal = -nVal;
841 while(nC <= -3)
843 nVal *= 1000;
844 nC += 3;
847 while(nC <= -1)
849 nVal *= 10;
850 nC++;
853 if(nMul_ != nDiv_)
854 nVal = BigMulDiv(nVal, nMul_, nDiv_);
856 OUStringBuffer aStr = OUString::number(nVal);
858 if(nC > 0 && aStr.getLength() <= nC )
860 // decimal separator necessary
861 sal_Int32 nCount(nC - aStr.getLength());
863 if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
864 nCount++;
866 for(sal_Int32 i=0; i<nCount; i++)
867 aStr.insert(0, aNullCode);
869 // remove superfluous decimal points
870 sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits());
871 sal_Int32 nWeg(nC - nNumDigits);
873 if(nWeg > 0)
875 // TODO: we should round here
876 aStr.remove(aStr.getLength() - nWeg, nWeg);
877 nC = nNumDigits;
881 // remember everything before the decimal separator for later
882 sal_Int32 nForComma(aStr.getLength() - nC);
884 if(nC > 0)
886 // insert comma char (decimal separator)
887 // remove trailing zeros
888 while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode[0])
890 aStr.remove(aStr.getLength() - 1, 1);
891 nC--;
894 if(nC > 0)
896 // do we still have decimal places?
897 sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
898 aStr.insert(nForComma, cDec);
902 // add in thousands separator (if necessary)
903 if( nForComma > 3 )
905 OUString aThoSep( rLoc.getNumThousandSep() );
906 if ( aThoSep.getLength() > 0 )
908 sal_Unicode cTho( aThoSep[0] );
909 sal_Int32 i(nForComma - 3);
911 while(i > 0)
913 aStr.insert(i, cTho);
914 i -= 3;
919 if(aStr.isEmpty())
920 aStr.insert(aStr.getLength(), aNullCode);
922 if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode[0]))
924 aStr.insert(0, "-");
927 rStr = aStr.makeStringAndClear();
930 void SdrFormatter::TakeUnitStr(MapUnit eUnit, OUString& rStr)
932 switch(eUnit)
934 // metrically
935 case MAP_100TH_MM :
937 rStr = "/100mm";
938 break;
940 case MAP_10TH_MM :
942 rStr = "/10mm";
943 break;
945 case MAP_MM :
947 rStr = "mm";
948 break;
950 case MAP_CM :
952 rStr = "cm";
953 break;
956 // Inch
957 case MAP_1000TH_INCH:
959 rStr = "/1000\"";
960 break;
962 case MAP_100TH_INCH :
964 rStr = "/100\"";
965 break;
967 case MAP_10TH_INCH :
969 rStr = "/10\"";
970 break;
972 case MAP_INCH :
974 rStr = "\"";
975 break;
977 case MAP_POINT :
979 rStr = "pt";
980 break;
982 case MAP_TWIP :
984 rStr = "twip";
985 break;
988 // others
989 case MAP_PIXEL :
991 rStr = "pixel";
992 break;
994 case MAP_SYSFONT :
996 rStr = "sysfont";
997 break;
999 case MAP_APPFONT :
1001 rStr = "appfont";
1002 break;
1004 case MAP_RELATIVE :
1006 rStr = "%";
1007 break;
1009 default: break;
1013 void SdrFormatter::TakeUnitStr(FieldUnit eUnit, OUString& rStr)
1015 switch(eUnit)
1017 default :
1018 case FUNIT_NONE :
1019 case FUNIT_CUSTOM :
1021 rStr.clear();
1022 break;
1025 // metrically
1026 case FUNIT_100TH_MM:
1028 rStr = "/100mm";
1029 break;
1031 case FUNIT_MM :
1033 rStr = "mm";
1034 break;
1036 case FUNIT_CM :
1038 rStr = "cm";
1039 break;
1041 case FUNIT_M :
1043 rStr = "m";
1044 break;
1046 case FUNIT_KM :
1048 rStr = "km";
1049 break;
1052 // Inch
1053 case FUNIT_TWIP :
1055 rStr = "twip";
1056 break;
1058 case FUNIT_POINT :
1060 rStr = "pt";
1061 break;
1063 case FUNIT_PICA :
1065 rStr = "pica";
1066 break;
1068 case FUNIT_INCH :
1070 rStr = "\"";
1071 break;
1073 case FUNIT_FOOT :
1075 rStr = "ft";
1076 break;
1078 case FUNIT_MILE :
1080 rStr = "mile(s)";
1081 break;
1084 // others
1085 case FUNIT_PERCENT:
1087 rStr = "%";
1088 break;
1096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */