update credits
[LibreOffice.git] / svx / source / svdraw / svdtrans.cxx
blob91e3f77a2f188b2a4edb6b731bd8f9600a5b9319
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);
41 if (xFact.GetDenominator()==0) {
42 long nWdt=rRect.Right()-rRect.Left();
43 if (xFact.GetNumerator()>=0) { // catch divisions by zero
44 xFact=Fraction(xFact.GetNumerator(),1);
45 if (nWdt==0) rRect.Right()++;
46 } else {
47 xFact=Fraction(xFact.GetNumerator(),-1);
48 if (nWdt==0) rRect.Left()--;
51 rRect.Left() =rRef.X()+Round(((double)(rRect.Left() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
52 rRect.Right() =rRef.X()+Round(((double)(rRect.Right() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
55 if (yFact.GetDenominator()==0) {
56 long nHgt=rRect.Bottom()-rRect.Top();
57 if (yFact.GetNumerator()>=0) { // catch divisions by zero
58 yFact=Fraction(yFact.GetNumerator(),1);
59 if (nHgt==0) rRect.Bottom()++;
60 } else {
61 yFact=Fraction(yFact.GetNumerator(),-1);
62 if (nHgt==0) rRect.Top()--;
65 yFact=Fraction(yFact.GetNumerator(),1); // catch divisions by zero
67 rRect.Top() =rRef.Y()+Round(((double)(rRect.Top() -rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
68 rRect.Bottom()=rRef.Y()+Round(((double)(rRect.Bottom()-rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
70 if (!bNoJustify) rRect.Justify();
74 void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
76 sal_uInt16 nAnz=rPoly.GetSize();
77 for (sal_uInt16 i=0; i<nAnz; i++) {
78 ResizePoint(rPoly[i],rRef,xFact,yFact);
82 void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
84 sal_uInt16 nAnz=rPoly.GetPointCount();
85 for (sal_uInt16 i=0; i<nAnz; i++) {
86 ResizePoint(rPoly[i],rRef,xFact,yFact);
90 void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
92 sal_uInt16 nAnz=rPoly.GetSize();
93 for (sal_uInt16 i=0; i<nAnz; i++) {
94 RotatePoint(rPoly[i],rRef,sn,cs);
98 void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
100 sal_uInt16 nAnz=rPoly.GetPointCount();
101 for (sal_uInt16 i=0; i<nAnz; i++) {
102 RotatePoint(rPoly[i],rRef,sn,cs);
106 void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
108 sal_uInt16 nAnz=rPoly.Count();
109 for (sal_uInt16 i=0; i<nAnz; i++) {
110 RotateXPoly(rPoly[i],rRef,sn,cs);
114 void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
116 long mx=rRef2.X()-rRef1.X();
117 long my=rRef2.Y()-rRef1.Y();
118 if (mx==0) { // vertical axis
119 long dx=rRef1.X()-rPnt.X();
120 rPnt.X()+=2*dx;
121 } else if (my==0) { // horizontal axis
122 long dy=rRef1.Y()-rPnt.Y();
123 rPnt.Y()+=2*dy;
124 } else if (mx==my) { // diagonal axis '\'
125 long dx1=rPnt.X()-rRef1.X();
126 long dy1=rPnt.Y()-rRef1.Y();
127 rPnt.X()=rRef1.X()+dy1;
128 rPnt.Y()=rRef1.Y()+dx1;
129 } else if (mx==-my) { // diagonal axis '/'
130 long dx1=rPnt.X()-rRef1.X();
131 long dy1=rPnt.Y()-rRef1.Y();
132 rPnt.X()=rRef1.X()-dy1;
133 rPnt.Y()=rRef1.Y()-dx1;
134 } else { // arbitrary axis
135 // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
136 long nRefWink=GetAngle(rRef2-rRef1);
137 rPnt-=rRef1;
138 long nPntWink=GetAngle(rPnt);
139 long nWink=2*(nRefWink-nPntWink);
140 double a=nWink*nPi180;
141 double nSin=sin(a);
142 double nCos=cos(a);
143 RotatePoint(rPnt,Point(),nSin,nCos);
144 rPnt+=rRef1;
148 void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
150 sal_uInt16 nAnz=rPoly.GetSize();
151 for (sal_uInt16 i=0; i<nAnz; i++) {
152 MirrorPoint(rPoly[i],rRef1,rRef2);
156 void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
158 sal_uInt16 nAnz=rPoly.GetPointCount();
159 for (sal_uInt16 i=0; i<nAnz; i++) {
160 MirrorPoint(rPoly[i],rRef1,rRef2);
164 void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear)
166 sal_uInt16 nAnz=rPoly.GetSize();
167 for (sal_uInt16 i=0; i<nAnz; i++) {
168 ShearPoint(rPoly[i],rRef,tn,bVShear);
172 void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
174 sal_uInt16 nAnz=rPoly.GetPointCount();
175 for (sal_uInt16 i=0; i<nAnz; i++) {
176 ShearPoint(rPoly[i],rRef,tn,bVShear);
180 double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
181 const Point& rRad, double& rSin, double& rCos, bool bVert)
183 bool bC1=pC1!=NULL;
184 bool bC2=pC2!=NULL;
185 long x0=rPnt.X();
186 long y0=rPnt.Y();
187 long cx=rCenter.X();
188 long cy=rCenter.Y();
189 double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
190 double sn=sin(nWink);
191 double cs=cos(nWink);
192 RotatePoint(rPnt,rCenter,sn,cs);
193 if (bC1) {
194 if (bVert) {
195 // move into the direction of the center, as a basic position for the rotation
196 pC1->Y()-=y0;
197 // resize, account for the distance from the center
198 pC1->Y()=Round(((double)pC1->Y()) /rRad.X()*(cx-pC1->X()));
199 pC1->Y()+=cy;
200 } else {
201 // move into the direction of the center, as a basic position for the rotation
202 pC1->X()-=x0;
203 // resize, account for the distance from the center
204 long nPntRad=cy-pC1->Y();
205 double nFact=(double)nPntRad/(double)rRad.Y();
206 pC1->X()=Round((double)pC1->X()*nFact);
207 pC1->X()+=cx;
209 RotatePoint(*pC1,rCenter,sn,cs);
211 if (bC2) {
212 if (bVert) {
213 // move into the direction of the center, as a basic position for the rotation
214 pC2->Y()-=y0;
215 // resize, account for the distance from the center
216 pC2->Y()=Round(((double)pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X()));
217 pC2->Y()+=cy;
218 } else {
219 // move into the direction of the center, as a basic position for the rotation
220 pC2->X()-=x0;
221 // resize, account for the distance from the center
222 long nPntRad=rCenter.Y()-pC2->Y();
223 double nFact=(double)nPntRad/(double)rRad.Y();
224 pC2->X()=Round((double)pC2->X()*nFact);
225 pC2->X()+=cx;
227 RotatePoint(*pC2,rCenter,sn,cs);
229 rSin=sn;
230 rCos=cs;
231 return nWink;
234 double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
235 const Point& rRad, double& rSin, double& rCos, bool bVert)
237 bool bC1=pC1!=NULL;
238 bool bC2=pC2!=NULL;
239 long x0=rPnt.X();
240 long y0=rPnt.Y();
241 long dx1=0,dy1=0;
242 long dxC1=0,dyC1=0;
243 long dxC2=0,dyC2=0;
244 if (bVert) {
245 long nStart=rCenter.X()-rRad.X();
246 dx1=rPnt.X()-nStart;
247 rPnt.X()=nStart;
248 if (bC1) {
249 dxC1=pC1->X()-nStart;
250 pC1->X()=nStart;
252 if (bC2) {
253 dxC2=pC2->X()-nStart;
254 pC2->X()=nStart;
256 } else {
257 long nStart=rCenter.Y()-rRad.Y();
258 dy1=rPnt.Y()-nStart;
259 rPnt.Y()=nStart;
260 if (bC1) {
261 dyC1=pC1->Y()-nStart;
262 pC1->Y()=nStart;
264 if (bC2) {
265 dyC2=pC2->Y()-nStart;
266 pC2->Y()=nStart;
269 double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
270 double sn=sin(nWink);
271 double cs=cos(nWink);
272 RotatePoint(rPnt,rCenter,sn,cs);
273 if (bC1) { if (bVert) pC1->Y()-=y0-rCenter.Y(); else pC1->X()-=x0-rCenter.X(); RotatePoint(*pC1,rCenter,sn,cs); }
274 if (bC2) { if (bVert) pC2->Y()-=y0-rCenter.Y(); else pC2->X()-=x0-rCenter.X(); RotatePoint(*pC2,rCenter,sn,cs); }
275 if (bVert) {
276 rPnt.X()+=dx1;
277 if (bC1) pC1->X()+=dxC1;
278 if (bC2) pC2->X()+=dxC2;
279 } else {
280 rPnt.Y()+=dy1;
281 if (bC1) pC1->Y()+=dyC1;
282 if (bC2) pC2->Y()+=dyC2;
284 rSin=sn;
285 rCos=cs;
286 return nWink;
289 double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
290 const Point& rRad, double& rSin, double& rCos, bool bVert,
291 const Rectangle rRefRect)
293 long y0=rPnt.Y();
294 CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
295 if (bVert) {
296 } else {
297 long nTop=rRefRect.Top();
298 long nBtm=rRefRect.Bottom();
299 long nHgt=nBtm-nTop;
300 long dy=rPnt.Y()-y0;
301 double a=((double)(y0-nTop))/nHgt;
302 a*=dy;
303 rPnt.Y()=y0+Round(a);
304 } return 0.0;
307 ////////////////////////////////////////////////////////////////////////////////////////////////////
309 void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
311 double nSin,nCos;
312 sal_uInt16 nPointAnz=rPoly.GetPointCount();
313 sal_uInt16 i=0;
314 while (i<nPointAnz) {
315 Point* pPnt=&rPoly[i];
316 Point* pC1=NULL;
317 Point* pC2=NULL;
318 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
319 pC1=pPnt;
320 i++;
321 pPnt=&rPoly[i];
323 i++;
324 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
325 pC2=&rPoly[i];
326 i++;
328 CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
332 void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
334 double nSin,nCos;
335 sal_uInt16 nPointAnz=rPoly.GetPointCount();
336 sal_uInt16 i=0;
337 while (i<nPointAnz) {
338 Point* pPnt=&rPoly[i];
339 Point* pC1=NULL;
340 Point* pC2=NULL;
341 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
342 pC1=pPnt;
343 i++;
344 pPnt=&rPoly[i];
346 i++;
347 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
348 pC2=&rPoly[i];
349 i++;
351 CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
355 void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
357 double nSin,nCos;
358 sal_uInt16 nPointAnz=rPoly.GetPointCount();
359 sal_uInt16 i=0;
360 while (i<nPointAnz) {
361 Point* pPnt=&rPoly[i];
362 Point* pC1=NULL;
363 Point* pC2=NULL;
364 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
365 pC1=pPnt;
366 i++;
367 pPnt=&rPoly[i];
369 i++;
370 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
371 pC2=&rPoly[i];
372 i++;
374 CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
378 ////////////////////////////////////////////////////////////////////////////////////////////////////
380 void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
382 sal_uInt16 nPolyAnz=rPoly.Count();
383 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
384 CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
388 void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
390 sal_uInt16 nPolyAnz=rPoly.Count();
391 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
392 CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
396 void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
398 sal_uInt16 nPolyAnz=rPoly.Count();
399 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
400 CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
404 ////////////////////////////////////////////////////////////////////////////////////////////////////
406 long GetAngle(const Point& rPnt)
408 long a=0;
409 if (rPnt.Y()==0) {
410 if (rPnt.X()<0) a=-18000;
411 } else if (rPnt.X()==0) {
412 if (rPnt.Y()>0) a=-9000;
413 else a=9000;
414 } else {
415 a=Round((atan2((double)-rPnt.Y(),(double)rPnt.X())/nPi180));
417 return a;
420 long NormAngle180(long a)
422 while (a<18000) a+=36000;
423 while (a>=18000) a-=36000;
424 return a;
427 long NormAngle360(long a)
429 while (a<0) a+=36000;
430 while (a>=36000) a-=36000;
431 return a;
434 sal_uInt16 GetAngleSector(long nWink)
436 while (nWink<0) nWink+=36000;
437 while (nWink>=36000) nWink-=36000;
438 if (nWink< 9000) return 0;
439 if (nWink<18000) return 1;
440 if (nWink<27000) return 2;
441 return 3;
444 long GetLen(const Point& rPnt)
446 long x=std::abs(rPnt.X());
447 long y=std::abs(rPnt.Y());
448 if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
449 x*=x;
450 y*=y;
451 x+=y;
452 x=Round(sqrt((double)x));
453 return x;
454 } else {
455 double nx=x;
456 double ny=y;
457 nx*=nx;
458 ny*=ny;
459 nx+=ny;
460 nx=sqrt(nx);
461 if (nx>0x7FFFFFFF) {
462 return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
463 } else {
464 return Round(nx);
469 ////////////////////////////////////////////////////////////////////////////////////////////////////
471 void GeoStat::RecalcSinCos()
473 if (nDrehWink==0) {
474 nSin=0.0;
475 nCos=1.0;
476 } else {
477 double a=nDrehWink*nPi180;
478 nSin=sin(a);
479 nCos=cos(a);
483 void GeoStat::RecalcTan()
485 if (nShearWink==0) {
486 nTan=0.0;
487 } else {
488 double a=nShearWink*nPi180;
489 nTan=tan(a);
493 ////////////////////////////////////////////////////////////////////////////////////////////////////
495 Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
497 Polygon aPol(5);
498 aPol[0]=rRect.TopLeft();
499 aPol[1]=rRect.TopRight();
500 aPol[2]=rRect.BottomRight();
501 aPol[3]=rRect.BottomLeft();
502 aPol[4]=rRect.TopLeft();
503 if (rGeo.nShearWink!=0) ShearPoly(aPol,rRect.TopLeft(),rGeo.nTan);
504 if (rGeo.nDrehWink!=0) RotatePoly(aPol,rRect.TopLeft(),rGeo.nSin,rGeo.nCos);
505 return aPol;
508 void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
510 rGeo.nDrehWink=GetAngle(rPol[1]-rPol[0]);
511 rGeo.nDrehWink=NormAngle360(rGeo.nDrehWink);
512 // rotation successful
513 rGeo.RecalcSinCos();
515 Point aPt1(rPol[1]-rPol[0]);
516 if (rGeo.nDrehWink!=0) RotatePoint(aPt1,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
517 long nWdt=aPt1.X();
519 Point aPt0(rPol[0]);
520 Point aPt3(rPol[3]-rPol[0]);
521 if (rGeo.nDrehWink!=0) RotatePoint(aPt3,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
522 long nHgt=aPt3.Y();
525 long nShW=GetAngle(aPt3);
526 nShW-=27000; // ShearWink is measured against a vertical line
527 nShW=-nShW; // Negieren, denn '+' ist Rechtskursivierung
529 bool bMirr=aPt3.Y()<0;
530 if (bMirr) { // "exchange of points" when mirroring
531 nHgt=-nHgt;
532 nShW+=18000;
533 aPt0=rPol[3];
535 nShW=NormAngle180(nShW);
536 if (nShW<-9000 || nShW>9000) {
537 nShW=NormAngle180(nShW+18000);
539 if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
540 if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
541 rGeo.nShearWink=nShW;
542 rGeo.RecalcTan();
543 Point aRU(aPt0);
544 aRU.X()+=nWdt;
545 aRU.Y()+=nHgt;
546 rRect=Rectangle(aPt0,aRU);
549 ////////////////////////////////////////////////////////////////////////////////////////////////////
551 void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
553 long dx=rPt.X()-rPt0.X();
554 long dy=rPt.Y()-rPt0.Y();
555 long dxa=std::abs(dx);
556 long dya=std::abs(dy);
557 if (dx==0 || dy==0 || dxa==dya) return;
558 if (dxa>=dya*2) { rPt.Y()=rPt0.Y(); return; }
559 if (dya>=dxa*2) { rPt.X()=rPt0.X(); return; }
560 if ((dxa<dya) != bBigOrtho) {
561 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
562 } else {
563 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
567 void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
569 long dx=rPt.X()-rPt0.X();
570 long dy=rPt.Y()-rPt0.Y();
571 long dxa=std::abs(dx);
572 long dya=std::abs(dy);
573 if ((dxa<dya) != bBigOrtho) {
574 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
575 } else {
576 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
580 ////////////////////////////////////////////////////////////////////////////////////////////////////
582 long BigMulDiv(long nVal, long nMul, long nDiv)
584 BigInt aVal(nVal);
585 aVal*=nMul;
586 if (aVal.IsNeg()!=(nDiv<0)) {
587 aVal-=nDiv/2; // to round correctly
588 } else {
589 aVal+=nDiv/2; // to round correctly
591 if(nDiv)
593 aVal/=nDiv;
594 return long(aVal);
596 return 0x7fffffff;
599 void Kuerzen(Fraction& rF, unsigned nDigits)
601 sal_Int32 nMul=rF.GetNumerator();
602 sal_Int32 nDiv=rF.GetDenominator();
603 bool bNeg = false;
604 if (nMul<0) { nMul=-nMul; bNeg=!bNeg; }
605 if (nDiv<0) { nDiv=-nDiv; bNeg=!bNeg; }
606 if (nMul==0 || nDiv==0) return;
607 sal_uInt32 a;
608 a=sal_uInt32(nMul); unsigned nMulZ=0; // count leading zeros
609 while (a<0x00800000) { nMulZ+=8; a<<=8; }
610 while (a<0x80000000) { nMulZ++; a<<=1; }
611 a=sal_uInt32(nDiv); unsigned nDivZ=0; // count leading zeros
612 while (a<0x00800000) { nDivZ+=8; a<<=8; }
613 while (a<0x80000000) { nDivZ++; a<<=1; }
614 // count the number of digits
615 int nMulDigits=32-nMulZ;
616 int nDivDigits=32-nDivZ;
617 // count how many decimal places can be removed
618 int nMulWeg=nMulDigits-nDigits; if (nMulWeg<0) nMulWeg=0;
619 int nDivWeg=nDivDigits-nDigits; if (nDivWeg<0) nDivWeg=0;
620 int nWeg=std::min(nMulWeg,nDivWeg);
621 nMul>>=nWeg;
622 nDiv>>=nWeg;
623 if (nMul==0 || nDiv==0) {
624 DBG_WARNING("Math error after canceling decimal places.");
625 return;
627 if (bNeg) nMul=-nMul;
628 rF=Fraction(nMul,nDiv);
631 ////////////////////////////////////////////////////////////////////////////////////////////////////
632 // How many eU units fit into a mm, respectively an inch?
633 // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
635 FrPair GetInchOrMM(MapUnit eU)
637 switch (eU) {
638 case MAP_1000TH_INCH: return FrPair(1000,1);
639 case MAP_100TH_INCH : return FrPair( 100,1);
640 case MAP_10TH_INCH : return FrPair( 10,1);
641 case MAP_INCH : return FrPair( 1,1);
642 case MAP_POINT : return FrPair( 72,1);
643 case MAP_TWIP : return FrPair(1440,1);
644 case MAP_100TH_MM : return FrPair( 100,1);
645 case MAP_10TH_MM : return FrPair( 10,1);
646 case MAP_MM : return FrPair( 1,1);
647 case MAP_CM : return FrPair( 1,10);
648 case MAP_PIXEL : {
649 VirtualDevice aVD;
650 aVD.SetMapMode(MapMode(MAP_100TH_MM));
651 Point aP(aVD.PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
652 return FrPair(6400,aP.X(),6400,aP.Y());
654 case MAP_APPFONT: case MAP_SYSFONT: {
655 VirtualDevice aVD;
656 aVD.SetMapMode(MapMode(eU));
657 Point aP(aVD.LogicToPixel(Point(32,32))); // 32 units for more accuracy
658 aVD.SetMapMode(MapMode(MAP_100TH_MM));
659 aP=aVD.PixelToLogic(aP);
660 return FrPair(3200,aP.X(),3200,aP.Y());
662 default: break;
664 return Fraction(1,1);
667 FrPair GetInchOrMM(FieldUnit eU)
669 switch (eU) {
670 case FUNIT_INCH : return FrPair( 1,1);
671 case FUNIT_POINT : return FrPair( 72,1);
672 case FUNIT_TWIP : return FrPair(1440,1);
673 case FUNIT_100TH_MM : return FrPair( 100,1);
674 case FUNIT_MM : return FrPair( 1,1);
675 case FUNIT_CM : return FrPair( 1,10);
676 case FUNIT_M : return FrPair( 1,1000);
677 case FUNIT_KM : return FrPair( 1,1000000);
678 case FUNIT_PICA : return FrPair( 6,1);
679 case FUNIT_FOOT : return FrPair( 1,12);
680 case FUNIT_MILE : return FrPair( 1,63360);
681 default: break;
683 return Fraction(1,1);
686 // Calculate the factor that we need to convert units from eS to eD.
687 // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
689 FrPair GetMapFactor(MapUnit eS, MapUnit eD)
691 if (eS==eD) return FrPair(1,1,1,1);
692 FrPair aS(GetInchOrMM(eS));
693 FrPair aD(GetInchOrMM(eD));
694 bool bSInch=IsInch(eS);
695 bool bDInch=IsInch(eD);
696 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
697 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
698 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
699 return aRet;
702 FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
704 if (eS==eD) return FrPair(1,1,1,1);
705 FrPair aS(GetInchOrMM(eS));
706 FrPair aD(GetInchOrMM(eD));
707 bool bSInch=IsInch(eS);
708 bool bDInch=IsInch(eD);
709 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
710 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
711 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
712 return aRet;
715 ////////////////////////////////////////////////////////////////////////////////////////////////////
717 // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
718 // 1 furlong = 10 chains = 7.920" = 201.168,0mm
719 // 1 chain = 4 poles = 792" = 20.116,8mm
720 // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
721 // 1 yd = 3 ft = 36" = 914,4mm
722 // 1 ft = 12 " = 1" = 304,8mm
724 void GetMeterOrInch(MapUnit eMU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
726 rnMul=1; rnDiv=1;
727 short nKomma=0;
728 bool bMetr = false, bInch = false;
729 switch (eMU) {
730 // Metrisch
731 case MAP_100TH_MM : bMetr = true; nKomma=5; break;
732 case MAP_10TH_MM : bMetr = true; nKomma=4; break;
733 case MAP_MM : bMetr = true; nKomma=3; break;
734 case MAP_CM : bMetr = true; nKomma=2; break;
735 // Inch
736 case MAP_1000TH_INCH: bInch = true; nKomma=3; break;
737 case MAP_100TH_INCH : bInch = true; nKomma=2; break;
738 case MAP_10TH_INCH : bInch = true; nKomma=1; break;
739 case MAP_INCH : bInch = true; nKomma=0; break;
740 case MAP_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
741 case MAP_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
742 // Sonstiges
743 case MAP_PIXEL : break;
744 case MAP_SYSFONT : break;
745 case MAP_APPFONT : break;
746 case MAP_RELATIVE : break;
747 default: break;
748 } // switch
749 rnKomma=nKomma;
750 rbMetr=bMetr;
751 rbInch=bInch;
754 void GetMeterOrInch(FieldUnit eFU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
756 rnMul=1; rnDiv=1;
757 short nKomma=0;
758 bool bMetr = false, bInch = false;
759 switch (eFU) {
760 case FUNIT_NONE : break;
761 // metrically
762 case FUNIT_100TH_MM : bMetr = true; nKomma=5; break;
763 case FUNIT_MM : bMetr = true; nKomma=3; break;
764 case FUNIT_CM : bMetr = true; nKomma=2; break;
765 case FUNIT_M : bMetr = true; nKomma=0; break;
766 case FUNIT_KM : bMetr = true; nKomma=-3; break;
767 // Inch
768 case FUNIT_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
769 case FUNIT_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
770 case FUNIT_PICA : bInch = true; rnDiv=6; break; // 1Pica = 1/6" ?
771 case FUNIT_INCH : bInch = true; break; // 1" = 1"
772 case FUNIT_FOOT : bInch = true; rnMul=12; break; // 1Ft = 12"
773 case FUNIT_MILE : bInch = true; rnMul=6336; nKomma=-1; break; // 1mile = 63360"
774 // others
775 case FUNIT_CUSTOM : break;
776 case FUNIT_PERCENT : nKomma=2; break;
777 // TODO: Add code to handle the following (added to remove warning)
778 case FUNIT_CHAR : break;
779 case FUNIT_LINE : break;
780 } // switch
781 rnKomma=nKomma;
782 rbMetr=bMetr;
783 rbInch=bInch;
786 void SdrFormatter::Undirty()
788 if (aScale.GetNumerator()==0 || aScale.GetDenominator()==0) aScale=Fraction(1,1);
789 bool bSrcMetr,bSrcInch,bDstMetr,bDstInch;
790 long nMul1,nDiv1,nMul2,nDiv2;
791 short nKomma1,nKomma2;
792 // first: normalize to m or in
793 if (!bSrcFU) {
794 GetMeterOrInch(eSrcMU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
795 } else {
796 GetMeterOrInch(eSrcFU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
798 if (!bDstFU) {
799 GetMeterOrInch(eDstMU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
800 } else {
801 GetMeterOrInch(eDstFU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
803 nMul1*=nDiv2;
804 nDiv1*=nMul2;
805 nKomma1=nKomma1-nKomma2;
807 if (bSrcInch && bDstMetr) {
808 nKomma1+=4;
809 nMul1*=254;
811 if (bSrcMetr && bDstInch) {
812 nKomma1-=4;
813 nDiv1*=254;
816 // temporary fraction for canceling
817 Fraction aTempFract(nMul1,nDiv1);
818 nMul1=aTempFract.GetNumerator();
819 nDiv1=aTempFract.GetDenominator();
821 nMul_=nMul1;
822 nDiv_=nDiv1;
823 nKomma_=nKomma1;
824 bDirty=sal_False;
828 void SdrFormatter::TakeStr(long nVal, OUString& rStr) const
830 OUString aNullCode("0");
832 if(!nVal)
834 rStr = aNullCode;
835 return;
838 // we may lose some decimal places here, because of MulDiv instead of Real
839 bool bNeg(nVal < 0);
840 SvtSysLocale aSysLoc;
841 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
843 ForceUndirty();
845 sal_Int16 nC(nKomma_);
847 if(bNeg)
848 nVal = -nVal;
850 while(nC <= -3)
852 nVal *= 1000;
853 nC += 3;
856 while(nC <= -1)
858 nVal *= 10;
859 nC++;
862 if(nMul_ != nDiv_)
863 nVal = BigMulDiv(nVal, nMul_, nDiv_);
865 OUStringBuffer aStr = OUString::valueOf(nVal);
867 if(nC > 0 && aStr.getLength() <= nC )
869 // decimal separator necessary
870 sal_Int32 nAnz(nC - aStr.getLength());
872 if(nAnz >= 0 && rLoc.isNumLeadingZero())
873 nAnz++;
875 for(sal_Int32 i=0; i<nAnz; i++)
876 aStr.insert(0, aNullCode);
878 // remove superfluous decimal points
879 sal_Int32 nNumDigits(rLoc.getNumDigits());
880 sal_Int32 nWeg(nC - nNumDigits);
882 if(nWeg > 0)
884 // TODO: we should round here
885 aStr.remove(aStr.getLength() - nWeg, nWeg);
886 nC = nNumDigits;
890 // remember everything before the decimal separator for later
891 sal_Int32 nForComma(aStr.getLength() - nC);
893 if(nC > 0)
895 // insert comma char (decimal separator)
896 // remove trailing zeros
897 while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode[0])
899 aStr.remove(aStr.getLength() - 1, 1);
900 nC--;
903 if(nC > 0)
905 // do we still have decimal places?
906 sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
907 aStr.insert(nForComma, cDec);
911 // add in thousands separator (if necessary)
912 if( nForComma > 3 )
914 OUString aThoSep( rLoc.getNumThousandSep() );
915 if ( aThoSep.getLength() > 0 )
917 sal_Unicode cTho( aThoSep[0] );
918 sal_Int32 i(nForComma - 3);
920 while(i > 0)
922 aStr.insert(i, cTho);
923 i -= 3;
928 if(!aStr.getLength())
929 aStr.insert(aStr.getLength(), aNullCode);
931 if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode[0]))
933 aStr.insert(0, "-");
936 rStr = aStr.makeStringAndClear();
939 void SdrFormatter::TakeUnitStr(MapUnit eUnit, OUString& rStr)
941 switch(eUnit)
943 // metrically
944 case MAP_100TH_MM :
946 rStr = "/100mm";
947 break;
949 case MAP_10TH_MM :
951 rStr = "/10mm";
952 break;
954 case MAP_MM :
956 rStr = "mm";
957 break;
959 case MAP_CM :
961 rStr = "cm";
962 break;
965 // Inch
966 case MAP_1000TH_INCH:
968 rStr = "/1000\"";
969 break;
971 case MAP_100TH_INCH :
973 rStr = "/100\"";
974 break;
976 case MAP_10TH_INCH :
978 rStr = "/10\"";
979 break;
981 case MAP_INCH :
983 rStr = "\"";
984 break;
986 case MAP_POINT :
988 rStr = "pt";
989 break;
991 case MAP_TWIP :
993 rStr = "twip";
994 break;
997 // others
998 case MAP_PIXEL :
1000 rStr = "pixel";
1001 break;
1003 case MAP_SYSFONT :
1005 rStr = "sysfont";
1006 break;
1008 case MAP_APPFONT :
1010 rStr = "appfont";
1011 break;
1013 case MAP_RELATIVE :
1015 rStr = "%";
1016 break;
1018 default: break;
1022 void SdrFormatter::TakeUnitStr(FieldUnit eUnit, OUString& rStr)
1024 switch(eUnit)
1026 default :
1027 case FUNIT_NONE :
1028 case FUNIT_CUSTOM :
1030 rStr = OUString();
1031 break;
1034 // metrically
1035 case FUNIT_100TH_MM:
1037 rStr = "/100mm";
1038 break;
1040 case FUNIT_MM :
1042 rStr = "mm";
1043 break;
1045 case FUNIT_CM :
1047 rStr = "cm";
1048 break;
1050 case FUNIT_M :
1052 rStr = "m";
1053 break;
1055 case FUNIT_KM :
1057 rStr = "km";
1058 break;
1061 // Inch
1062 case FUNIT_TWIP :
1064 rStr = "twip";
1065 break;
1067 case FUNIT_POINT :
1069 rStr = "pt";
1070 break;
1072 case FUNIT_PICA :
1074 rStr = "pica";
1075 break;
1077 case FUNIT_INCH :
1079 rStr = "\"";
1080 break;
1082 case FUNIT_FOOT :
1084 rStr = "ft";
1085 break;
1087 case FUNIT_MILE :
1089 rStr = "mile(s)";
1090 break;
1093 // others
1094 case FUNIT_PERCENT:
1096 rStr = "%";
1097 break;
1102 ////////////////////////////////////////////////////////////////////////////////////////////////////
1105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */