Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / svx / source / svdraw / svdtrans.cxx
bloba9c585366b6e11e8733ed6b502fe367af42b7fa9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <svx/svdtrans.hxx>
31 #include <math.h>
32 #include <svx/xpoly.hxx>
34 #include <vcl/virdev.hxx>
35 #include <tools/bigint.hxx>
36 #include <tools/debug.hxx>
37 #include <unotools/syslocale.hxx>
39 void MoveXPoly(XPolygon& rPoly, const Size& S)
41 rPoly.Move(S.Width(),S.Height());
44 void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact, bool bNoJustify)
46 Fraction xFact(rxFact);
47 Fraction yFact(ryFact);
50 if (xFact.GetDenominator()==0) {
51 long nWdt=rRect.Right()-rRect.Left();
52 if (xFact.GetNumerator()>=0) { // catch divisions by zero
53 xFact=Fraction(xFact.GetNumerator(),1);
54 if (nWdt==0) rRect.Right()++;
55 } else {
56 xFact=Fraction(xFact.GetNumerator(),-1);
57 if (nWdt==0) rRect.Left()--;
60 rRect.Left() =rRef.X()+Round(((double)(rRect.Left() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
61 rRect.Right() =rRef.X()+Round(((double)(rRect.Right() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
64 if (yFact.GetDenominator()==0) {
65 long nHgt=rRect.Bottom()-rRect.Top();
66 if (yFact.GetNumerator()>=0) { // catch divisions by zero
67 yFact=Fraction(yFact.GetNumerator(),1);
68 if (nHgt==0) rRect.Bottom()++;
69 } else {
70 yFact=Fraction(yFact.GetNumerator(),-1);
71 if (nHgt==0) rRect.Top()--;
74 yFact=Fraction(yFact.GetNumerator(),1); // catch divisions by zero
76 rRect.Top() =rRef.Y()+Round(((double)(rRect.Top() -rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
77 rRect.Bottom()=rRef.Y()+Round(((double)(rRect.Bottom()-rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
79 if (!bNoJustify) rRect.Justify();
83 void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
85 sal_uInt16 nAnz=rPoly.GetSize();
86 for (sal_uInt16 i=0; i<nAnz; i++) {
87 ResizePoint(rPoly[i],rRef,xFact,yFact);
91 void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
93 sal_uInt16 nAnz=rPoly.GetPointCount();
94 for (sal_uInt16 i=0; i<nAnz; i++) {
95 ResizePoint(rPoly[i],rRef,xFact,yFact);
99 void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
101 sal_uInt16 nAnz=rPoly.GetSize();
102 for (sal_uInt16 i=0; i<nAnz; i++) {
103 RotatePoint(rPoly[i],rRef,sn,cs);
107 void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
109 sal_uInt16 nAnz=rPoly.GetPointCount();
110 for (sal_uInt16 i=0; i<nAnz; i++) {
111 RotatePoint(rPoly[i],rRef,sn,cs);
115 void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
117 sal_uInt16 nAnz=rPoly.Count();
118 for (sal_uInt16 i=0; i<nAnz; i++) {
119 RotateXPoly(rPoly[i],rRef,sn,cs);
123 void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
125 long mx=rRef2.X()-rRef1.X();
126 long my=rRef2.Y()-rRef1.Y();
127 if (mx==0) { // vertical axis
128 long dx=rRef1.X()-rPnt.X();
129 rPnt.X()+=2*dx;
130 } else if (my==0) { // horizontal axis
131 long dy=rRef1.Y()-rPnt.Y();
132 rPnt.Y()+=2*dy;
133 } else if (mx==my) { // diagonal axis '\'
134 long dx1=rPnt.X()-rRef1.X();
135 long dy1=rPnt.Y()-rRef1.Y();
136 rPnt.X()=rRef1.X()+dy1;
137 rPnt.Y()=rRef1.Y()+dx1;
138 } else if (mx==-my) { // diagonal axis '/'
139 long dx1=rPnt.X()-rRef1.X();
140 long dy1=rPnt.Y()-rRef1.Y();
141 rPnt.X()=rRef1.X()-dy1;
142 rPnt.Y()=rRef1.Y()-dx1;
143 } else { // arbitrary axis
144 // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
145 long nRefWink=GetAngle(rRef2-rRef1);
146 rPnt-=rRef1;
147 long nPntWink=GetAngle(rPnt);
148 long nWink=2*(nRefWink-nPntWink);
149 double a=nWink*nPi180;
150 double nSin=sin(a);
151 double nCos=cos(a);
152 RotatePoint(rPnt,Point(),nSin,nCos);
153 rPnt+=rRef1;
157 void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
159 sal_uInt16 nAnz=rPoly.GetSize();
160 for (sal_uInt16 i=0; i<nAnz; i++) {
161 MirrorPoint(rPoly[i],rRef1,rRef2);
165 void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
167 sal_uInt16 nAnz=rPoly.GetPointCount();
168 for (sal_uInt16 i=0; i<nAnz; i++) {
169 MirrorPoint(rPoly[i],rRef1,rRef2);
173 void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear)
175 sal_uInt16 nAnz=rPoly.GetSize();
176 for (sal_uInt16 i=0; i<nAnz; i++) {
177 ShearPoint(rPoly[i],rRef,tn,bVShear);
181 void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
183 sal_uInt16 nAnz=rPoly.GetPointCount();
184 for (sal_uInt16 i=0; i<nAnz; i++) {
185 ShearPoint(rPoly[i],rRef,tn,bVShear);
189 double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
190 const Point& rRad, double& rSin, double& rCos, bool bVert)
192 bool bC1=pC1!=NULL;
193 bool bC2=pC2!=NULL;
194 long x0=rPnt.X();
195 long y0=rPnt.Y();
196 long cx=rCenter.X();
197 long cy=rCenter.Y();
198 double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
199 double sn=sin(nWink);
200 double cs=cos(nWink);
201 RotatePoint(rPnt,rCenter,sn,cs);
202 if (bC1) {
203 if (bVert) {
204 // move into the direction of the center, as a basic position for the rotation
205 pC1->Y()-=y0;
206 // resize, account for the distance from the center
207 pC1->Y()=Round(((double)pC1->Y()) /rRad.X()*(cx-pC1->X()));
208 pC1->Y()+=cy;
209 } else {
210 // move into the direction of the center, as a basic position for the rotation
211 pC1->X()-=x0;
212 // resize, account for the distance from the center
213 long nPntRad=cy-pC1->Y();
214 double nFact=(double)nPntRad/(double)rRad.Y();
215 pC1->X()=Round((double)pC1->X()*nFact);
216 pC1->X()+=cx;
218 RotatePoint(*pC1,rCenter,sn,cs);
220 if (bC2) {
221 if (bVert) {
222 // move into the direction of the center, as a basic position for the rotation
223 pC2->Y()-=y0;
224 // resize, account for the distance from the center
225 pC2->Y()=Round(((double)pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X()));
226 pC2->Y()+=cy;
227 } else {
228 // move into the direction of the center, as a basic position for the rotation
229 pC2->X()-=x0;
230 // resize, account for the distance from the center
231 long nPntRad=rCenter.Y()-pC2->Y();
232 double nFact=(double)nPntRad/(double)rRad.Y();
233 pC2->X()=Round((double)pC2->X()*nFact);
234 pC2->X()+=cx;
236 RotatePoint(*pC2,rCenter,sn,cs);
238 rSin=sn;
239 rCos=cs;
240 return nWink;
243 double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
244 const Point& rRad, double& rSin, double& rCos, bool bVert)
246 bool bC1=pC1!=NULL;
247 bool bC2=pC2!=NULL;
248 long x0=rPnt.X();
249 long y0=rPnt.Y();
250 long dx1=0,dy1=0;
251 long dxC1=0,dyC1=0;
252 long dxC2=0,dyC2=0;
253 if (bVert) {
254 long nStart=rCenter.X()-rRad.X();
255 dx1=rPnt.X()-nStart;
256 rPnt.X()=nStart;
257 if (bC1) {
258 dxC1=pC1->X()-nStart;
259 pC1->X()=nStart;
261 if (bC2) {
262 dxC2=pC2->X()-nStart;
263 pC2->X()=nStart;
265 } else {
266 long nStart=rCenter.Y()-rRad.Y();
267 dy1=rPnt.Y()-nStart;
268 rPnt.Y()=nStart;
269 if (bC1) {
270 dyC1=pC1->Y()-nStart;
271 pC1->Y()=nStart;
273 if (bC2) {
274 dyC2=pC2->Y()-nStart;
275 pC2->Y()=nStart;
278 double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
279 double sn=sin(nWink);
280 double cs=cos(nWink);
281 RotatePoint(rPnt,rCenter,sn,cs);
282 if (bC1) { if (bVert) pC1->Y()-=y0-rCenter.Y(); else pC1->X()-=x0-rCenter.X(); RotatePoint(*pC1,rCenter,sn,cs); }
283 if (bC2) { if (bVert) pC2->Y()-=y0-rCenter.Y(); else pC2->X()-=x0-rCenter.X(); RotatePoint(*pC2,rCenter,sn,cs); }
284 if (bVert) {
285 rPnt.X()+=dx1;
286 if (bC1) pC1->X()+=dxC1;
287 if (bC2) pC2->X()+=dxC2;
288 } else {
289 rPnt.Y()+=dy1;
290 if (bC1) pC1->Y()+=dyC1;
291 if (bC2) pC2->Y()+=dyC2;
293 rSin=sn;
294 rCos=cs;
295 return nWink;
298 double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
299 const Point& rRad, double& rSin, double& rCos, bool bVert,
300 const Rectangle rRefRect)
302 long y0=rPnt.Y();
303 CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
304 if (bVert) {
305 } else {
306 long nTop=rRefRect.Top();
307 long nBtm=rRefRect.Bottom();
308 long nHgt=nBtm-nTop;
309 long dy=rPnt.Y()-y0;
310 double a=((double)(y0-nTop))/nHgt;
311 a*=dy;
312 rPnt.Y()=y0+Round(a);
313 } return 0.0;
316 ////////////////////////////////////////////////////////////////////////////////////////////////////
318 void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
320 double nSin,nCos;
321 sal_uInt16 nPointAnz=rPoly.GetPointCount();
322 sal_uInt16 i=0;
323 while (i<nPointAnz) {
324 Point* pPnt=&rPoly[i];
325 Point* pC1=NULL;
326 Point* pC2=NULL;
327 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
328 pC1=pPnt;
329 i++;
330 pPnt=&rPoly[i];
332 i++;
333 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
334 pC2=&rPoly[i];
335 i++;
337 CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
341 void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
343 double nSin,nCos;
344 sal_uInt16 nPointAnz=rPoly.GetPointCount();
345 sal_uInt16 i=0;
346 while (i<nPointAnz) {
347 Point* pPnt=&rPoly[i];
348 Point* pC1=NULL;
349 Point* pC2=NULL;
350 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
351 pC1=pPnt;
352 i++;
353 pPnt=&rPoly[i];
355 i++;
356 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
357 pC2=&rPoly[i];
358 i++;
360 CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
364 void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
366 double nSin,nCos;
367 sal_uInt16 nPointAnz=rPoly.GetPointCount();
368 sal_uInt16 i=0;
369 while (i<nPointAnz) {
370 Point* pPnt=&rPoly[i];
371 Point* pC1=NULL;
372 Point* pC2=NULL;
373 if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
374 pC1=pPnt;
375 i++;
376 pPnt=&rPoly[i];
378 i++;
379 if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
380 pC2=&rPoly[i];
381 i++;
383 CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
387 ////////////////////////////////////////////////////////////////////////////////////////////////////
389 void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
391 sal_uInt16 nPolyAnz=rPoly.Count();
392 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
393 CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
397 void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
399 sal_uInt16 nPolyAnz=rPoly.Count();
400 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
401 CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
405 void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
407 sal_uInt16 nPolyAnz=rPoly.Count();
408 for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
409 CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
413 ////////////////////////////////////////////////////////////////////////////////////////////////////
415 long GetAngle(const Point& rPnt)
417 long a=0;
418 if (rPnt.Y()==0) {
419 if (rPnt.X()<0) a=-18000;
420 } else if (rPnt.X()==0) {
421 if (rPnt.Y()>0) a=-9000;
422 else a=9000;
423 } else {
424 a=Round((atan2((double)-rPnt.Y(),(double)rPnt.X())/nPi180));
426 return a;
429 long NormAngle180(long a)
431 while (a<18000) a+=36000;
432 while (a>=18000) a-=36000;
433 return a;
436 long NormAngle360(long a)
438 while (a<0) a+=36000;
439 while (a>=36000) a-=36000;
440 return a;
443 sal_uInt16 GetAngleSector(long nWink)
445 while (nWink<0) nWink+=36000;
446 while (nWink>=36000) nWink-=36000;
447 if (nWink< 9000) return 0;
448 if (nWink<18000) return 1;
449 if (nWink<27000) return 2;
450 return 3;
453 long GetLen(const Point& rPnt)
455 long x=Abs(rPnt.X());
456 long y=Abs(rPnt.Y());
457 if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
458 x*=x;
459 y*=y;
460 x+=y;
461 x=Round(sqrt((double)x));
462 return x;
463 } else {
464 double nx=x;
465 double ny=y;
466 nx*=nx;
467 ny*=ny;
468 nx+=ny;
469 nx=sqrt(nx);
470 if (nx>0x7FFFFFFF) {
471 return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
472 } else {
473 return Round(nx);
478 ////////////////////////////////////////////////////////////////////////////////////////////////////
480 void GeoStat::RecalcSinCos()
482 if (nDrehWink==0) {
483 nSin=0.0;
484 nCos=1.0;
485 } else {
486 double a=nDrehWink*nPi180;
487 nSin=sin(a);
488 nCos=cos(a);
492 void GeoStat::RecalcTan()
494 if (nShearWink==0) {
495 nTan=0.0;
496 } else {
497 double a=nShearWink*nPi180;
498 nTan=tan(a);
502 ////////////////////////////////////////////////////////////////////////////////////////////////////
504 Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
506 Polygon aPol(5);
507 aPol[0]=rRect.TopLeft();
508 aPol[1]=rRect.TopRight();
509 aPol[2]=rRect.BottomRight();
510 aPol[3]=rRect.BottomLeft();
511 aPol[4]=rRect.TopLeft();
512 if (rGeo.nShearWink!=0) ShearPoly(aPol,rRect.TopLeft(),rGeo.nTan);
513 if (rGeo.nDrehWink!=0) RotatePoly(aPol,rRect.TopLeft(),rGeo.nSin,rGeo.nCos);
514 return aPol;
517 void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
519 rGeo.nDrehWink=GetAngle(rPol[1]-rPol[0]);
520 rGeo.nDrehWink=NormAngle360(rGeo.nDrehWink);
521 // rotation successful
522 rGeo.RecalcSinCos();
524 Point aPt1(rPol[1]-rPol[0]);
525 if (rGeo.nDrehWink!=0) RotatePoint(aPt1,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
526 long nWdt=aPt1.X();
528 Point aPt0(rPol[0]);
529 Point aPt3(rPol[3]-rPol[0]);
530 if (rGeo.nDrehWink!=0) RotatePoint(aPt3,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
531 long nHgt=aPt3.Y();
534 long nShW=GetAngle(aPt3);
535 nShW-=27000; // ShearWink is measured against a vertical line
536 nShW=-nShW; // Negieren, denn '+' ist Rechtskursivierung
538 bool bMirr=aPt3.Y()<0;
539 if (bMirr) { // "exchange of points" when mirroring
540 nHgt=-nHgt;
541 nShW+=18000;
542 aPt0=rPol[3];
544 nShW=NormAngle180(nShW);
545 if (nShW<-9000 || nShW>9000) {
546 nShW=NormAngle180(nShW+18000);
548 if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
549 if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
550 rGeo.nShearWink=nShW;
551 rGeo.RecalcTan();
552 Point aRU(aPt0);
553 aRU.X()+=nWdt;
554 aRU.Y()+=nHgt;
555 rRect=Rectangle(aPt0,aRU);
558 ////////////////////////////////////////////////////////////////////////////////////////////////////
560 void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
562 long dx=rPt.X()-rPt0.X();
563 long dy=rPt.Y()-rPt0.Y();
564 long dxa=Abs(dx);
565 long dya=Abs(dy);
566 if (dx==0 || dy==0 || dxa==dya) return;
567 if (dxa>=dya*2) { rPt.Y()=rPt0.Y(); return; }
568 if (dya>=dxa*2) { rPt.X()=rPt0.X(); return; }
569 if ((dxa<dya) != bBigOrtho) {
570 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
571 } else {
572 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
576 void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
578 long dx=rPt.X()-rPt0.X();
579 long dy=rPt.Y()-rPt0.Y();
580 long dxa=Abs(dx);
581 long dya=Abs(dy);
582 if ((dxa<dya) != bBigOrtho) {
583 rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
584 } else {
585 rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
589 ////////////////////////////////////////////////////////////////////////////////////////////////////
591 long BigMulDiv(long nVal, long nMul, long nDiv)
593 BigInt aVal(nVal);
594 aVal*=nMul;
595 if (aVal.IsNeg()!=(nDiv<0)) {
596 aVal-=nDiv/2; // to round correctly
597 } else {
598 aVal+=nDiv/2; // to round correctly
600 if(nDiv)
602 aVal/=nDiv;
603 return long(aVal);
605 return 0x7fffffff;
608 void Kuerzen(Fraction& rF, unsigned nDigits)
610 sal_Int32 nMul=rF.GetNumerator();
611 sal_Int32 nDiv=rF.GetDenominator();
612 bool bNeg = false;
613 if (nMul<0) { nMul=-nMul; bNeg=!bNeg; }
614 if (nDiv<0) { nDiv=-nDiv; bNeg=!bNeg; }
615 if (nMul==0 || nDiv==0) return;
616 sal_uInt32 a;
617 a=sal_uInt32(nMul); unsigned nMulZ=0; // count leading zeros
618 while (a<0x00800000) { nMulZ+=8; a<<=8; }
619 while (a<0x80000000) { nMulZ++; a<<=1; }
620 a=sal_uInt32(nDiv); unsigned nDivZ=0; // count leading zeros
621 while (a<0x00800000) { nDivZ+=8; a<<=8; }
622 while (a<0x80000000) { nDivZ++; a<<=1; }
623 // count the number of digits
624 int nMulDigits=32-nMulZ;
625 int nDivDigits=32-nDivZ;
626 // count how many decimal places can be removed
627 int nMulWeg=nMulDigits-nDigits; if (nMulWeg<0) nMulWeg=0;
628 int nDivWeg=nDivDigits-nDigits; if (nDivWeg<0) nDivWeg=0;
629 int nWeg=Min(nMulWeg,nDivWeg);
630 nMul>>=nWeg;
631 nDiv>>=nWeg;
632 if (nMul==0 || nDiv==0) {
633 DBG_WARNING("Math error after canceling decimal places.");
634 return;
636 if (bNeg) nMul=-nMul;
637 rF=Fraction(nMul,nDiv);
640 ////////////////////////////////////////////////////////////////////////////////////////////////////
641 // How many eU units fit into a mm, respectively an inch?
642 // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
644 FrPair GetInchOrMM(MapUnit eU)
646 switch (eU) {
647 case MAP_1000TH_INCH: return FrPair(1000,1);
648 case MAP_100TH_INCH : return FrPair( 100,1);
649 case MAP_10TH_INCH : return FrPair( 10,1);
650 case MAP_INCH : return FrPair( 1,1);
651 case MAP_POINT : return FrPair( 72,1);
652 case MAP_TWIP : return FrPair(1440,1);
653 case MAP_100TH_MM : return FrPair( 100,1);
654 case MAP_10TH_MM : return FrPair( 10,1);
655 case MAP_MM : return FrPair( 1,1);
656 case MAP_CM : return FrPair( 1,10);
657 case MAP_PIXEL : {
658 VirtualDevice aVD;
659 aVD.SetMapMode(MapMode(MAP_100TH_MM));
660 Point aP(aVD.PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
661 return FrPair(6400,aP.X(),6400,aP.Y());
663 case MAP_APPFONT: case MAP_SYSFONT: {
664 VirtualDevice aVD;
665 aVD.SetMapMode(MapMode(eU));
666 Point aP(aVD.LogicToPixel(Point(32,32))); // 32 units for more accuracy
667 aVD.SetMapMode(MapMode(MAP_100TH_MM));
668 aP=aVD.PixelToLogic(aP);
669 return FrPair(3200,aP.X(),3200,aP.Y());
671 default: break;
673 return Fraction(1,1);
676 FrPair GetInchOrMM(FieldUnit eU)
678 switch (eU) {
679 case FUNIT_INCH : return FrPair( 1,1);
680 case FUNIT_POINT : return FrPair( 72,1);
681 case FUNIT_TWIP : return FrPair(1440,1);
682 case FUNIT_100TH_MM : return FrPair( 100,1);
683 case FUNIT_MM : return FrPair( 1,1);
684 case FUNIT_CM : return FrPair( 1,10);
685 case FUNIT_M : return FrPair( 1,1000);
686 case FUNIT_KM : return FrPair( 1,1000000);
687 case FUNIT_PICA : return FrPair( 6,1);
688 case FUNIT_FOOT : return FrPair( 1,12);
689 case FUNIT_MILE : return FrPair( 1,63360);
690 default: break;
692 return Fraction(1,1);
695 // Calculate the factor that we need to convert units from eS to eD.
696 // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
698 FrPair GetMapFactor(MapUnit eS, MapUnit eD)
700 if (eS==eD) return FrPair(1,1,1,1);
701 FrPair aS(GetInchOrMM(eS));
702 FrPair aD(GetInchOrMM(eD));
703 bool bSInch=IsInch(eS);
704 bool bDInch=IsInch(eD);
705 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
706 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
707 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
708 return aRet;
711 FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
713 if (eS==eD) return FrPair(1,1,1,1);
714 FrPair aS(GetInchOrMM(eS));
715 FrPair aD(GetInchOrMM(eD));
716 bool bSInch=IsInch(eS);
717 bool bDInch=IsInch(eD);
718 FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
719 if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
720 if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
721 return aRet;
724 ////////////////////////////////////////////////////////////////////////////////////////////////////
726 // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
727 // 1 furlong = 10 chains = 7.920" = 201.168,0mm
728 // 1 chain = 4 poles = 792" = 20.116,8mm
729 // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
730 // 1 yd = 3 ft = 36" = 914,4mm
731 // 1 ft = 12 " = 1" = 304,8mm
733 void GetMeterOrInch(MapUnit eMU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
735 rnMul=1; rnDiv=1;
736 short nKomma=0;
737 bool bMetr = false, bInch = false;
738 switch (eMU) {
739 // Metrisch
740 case MAP_100TH_MM : bMetr = true; nKomma=5; break;
741 case MAP_10TH_MM : bMetr = true; nKomma=4; break;
742 case MAP_MM : bMetr = true; nKomma=3; break;
743 case MAP_CM : bMetr = true; nKomma=2; break;
744 // Inch
745 case MAP_1000TH_INCH: bInch = true; nKomma=3; break;
746 case MAP_100TH_INCH : bInch = true; nKomma=2; break;
747 case MAP_10TH_INCH : bInch = true; nKomma=1; break;
748 case MAP_INCH : bInch = true; nKomma=0; break;
749 case MAP_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
750 case MAP_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
751 // Sonstiges
752 case MAP_PIXEL : break;
753 case MAP_SYSFONT : break;
754 case MAP_APPFONT : break;
755 case MAP_RELATIVE : break;
756 default: break;
757 } // switch
758 rnKomma=nKomma;
759 rbMetr=bMetr;
760 rbInch=bInch;
763 void GetMeterOrInch(FieldUnit eFU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
765 rnMul=1; rnDiv=1;
766 short nKomma=0;
767 bool bMetr = false, bInch = false;
768 switch (eFU) {
769 case FUNIT_NONE : break;
770 // metrically
771 case FUNIT_100TH_MM : bMetr = true; nKomma=5; break;
772 case FUNIT_MM : bMetr = true; nKomma=3; break;
773 case FUNIT_CM : bMetr = true; nKomma=2; break;
774 case FUNIT_M : bMetr = true; nKomma=0; break;
775 case FUNIT_KM : bMetr = true; nKomma=-3; break;
776 // Inch
777 case FUNIT_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
778 case FUNIT_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
779 case FUNIT_PICA : bInch = true; rnDiv=6; break; // 1Pica = 1/6" ?
780 case FUNIT_INCH : bInch = true; break; // 1" = 1"
781 case FUNIT_FOOT : bInch = true; rnMul=12; break; // 1Ft = 12"
782 case FUNIT_MILE : bInch = true; rnMul=6336; nKomma=-1; break; // 1mile = 63360"
783 // others
784 case FUNIT_CUSTOM : break;
785 case FUNIT_PERCENT : nKomma=2; break;
786 // TODO: Add code to handle the following (added to remove warning)
787 case FUNIT_CHAR : break;
788 case FUNIT_LINE : break;
789 } // switch
790 rnKomma=nKomma;
791 rbMetr=bMetr;
792 rbInch=bInch;
795 void SdrFormatter::Undirty()
797 if (aScale.GetNumerator()==0 || aScale.GetDenominator()==0) aScale=Fraction(1,1);
798 bool bSrcMetr,bSrcInch,bDstMetr,bDstInch;
799 long nMul1,nDiv1,nMul2,nDiv2;
800 short nKomma1,nKomma2;
801 // first: normalize to m or in
802 if (!bSrcFU) {
803 GetMeterOrInch(eSrcMU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
804 } else {
805 GetMeterOrInch(eSrcFU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
807 if (!bDstFU) {
808 GetMeterOrInch(eDstMU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
809 } else {
810 GetMeterOrInch(eDstFU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
812 nMul1*=nDiv2;
813 nDiv1*=nMul2;
814 nKomma1=nKomma1-nKomma2;
816 if (bSrcInch && bDstMetr) {
817 nKomma1+=4;
818 nMul1*=254;
820 if (bSrcMetr && bDstInch) {
821 nKomma1-=4;
822 nDiv1*=254;
825 // temporary fraction for canceling
826 Fraction aTempFract(nMul1,nDiv1);
827 nMul1=aTempFract.GetNumerator();
828 nDiv1=aTempFract.GetDenominator();
830 nMul_=nMul1;
831 nDiv_=nDiv1;
832 nKomma_=nKomma1;
833 bDirty=sal_False;
837 void SdrFormatter::TakeStr(long nVal, XubString& rStr) const
839 sal_Unicode aNullCode('0');
841 if(!nVal)
843 rStr = UniString();
844 rStr += aNullCode;
845 return;
848 // we may lose some decimal places here, because of MulDiv instead of Real
849 sal_Bool bNeg(nVal < 0);
850 SvtSysLocale aSysLoc;
851 const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
853 ForceUndirty();
855 sal_Int16 nK(nKomma_);
856 XubString aStr;
858 if(bNeg)
859 nVal = -nVal;
861 while(nK <= -3)
863 nVal *= 1000;
864 nK += 3;
867 while(nK <= -1)
869 nVal *= 10;
870 nK++;
873 if(nMul_ != nDiv_)
874 nVal = BigMulDiv(nVal, nMul_, nDiv_);
876 aStr = UniString::CreateFromInt32(nVal);
878 if(nK > 0 && aStr.Len() <= nK )
880 // decimal separator necessary
881 sal_Int16 nAnz(nK - aStr.Len());
883 if(nAnz >= 0 && rLoc.isNumLeadingZero())
884 nAnz++;
886 for(xub_StrLen i=0; i<nAnz; i++)
887 aStr.Insert(aNullCode, 0);
889 // remove superfluous decimal points
890 xub_StrLen nNumDigits(rLoc.getNumDigits());
891 xub_StrLen nWeg(nK - nNumDigits);
893 if(nWeg > 0)
895 // TODO: we should round here
896 aStr.Erase(aStr.Len() - nWeg);
897 nK = nNumDigits;
901 // remember everything before the decimal separator for later
902 xub_StrLen nVorKomma(aStr.Len() - nK);
904 if(nK > 0)
906 // insert KommaChar (decimal separator)
907 // remove trailing zeros
908 while(nK > 0 && aStr.GetChar(aStr.Len() - 1) == aNullCode)
910 aStr.Erase(aStr.Len() - 1);
911 nK--;
914 if(nK > 0)
916 // do we still have decimal places?
917 sal_Unicode cDec(rLoc.getNumDecimalSep().GetChar(0));
918 aStr.Insert(cDec, nVorKomma);
922 // add in thousands separator (if necessary)
923 if( nVorKomma > 3 )
925 String aThoSep( rLoc.getNumThousandSep() );
926 if ( aThoSep.Len() > 0 )
928 sal_Unicode cTho( aThoSep.GetChar(0) );
929 sal_Int32 i(nVorKomma - 3);
931 while(i > 0)
933 rStr.Insert(cTho, (xub_StrLen)i);
934 i -= 3;
939 if(!aStr.Len())
940 aStr += aNullCode;
942 if(bNeg && (aStr.Len() > 1 || aStr.GetChar(0) != aNullCode))
944 rStr.Insert(sal_Unicode('-'), 0);
947 rStr = aStr;
950 void SdrFormatter::TakeUnitStr(MapUnit eUnit, XubString& rStr)
952 switch(eUnit)
954 // metrically
955 case MAP_100TH_MM :
957 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
958 break;
960 case MAP_10TH_MM :
962 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10mm"));
963 break;
965 case MAP_MM :
967 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
968 break;
970 case MAP_CM :
972 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
973 break;
976 // Inch
977 case MAP_1000TH_INCH:
979 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/1000\""));
980 break;
982 case MAP_100TH_INCH :
984 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100\""));
985 break;
987 case MAP_10TH_INCH :
989 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10\""));
990 break;
992 case MAP_INCH :
994 rStr = UniString();
995 rStr += sal_Unicode('"');
996 break;
998 case MAP_POINT :
1000 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
1001 break;
1003 case MAP_TWIP :
1005 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
1006 break;
1009 // others
1010 case MAP_PIXEL :
1012 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pixel"));
1013 break;
1015 case MAP_SYSFONT :
1017 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("sysfont"));
1018 break;
1020 case MAP_APPFONT :
1022 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("appfont"));
1023 break;
1025 case MAP_RELATIVE :
1027 rStr = UniString();
1028 rStr += sal_Unicode('%');
1029 break;
1031 default: break;
1035 void SdrFormatter::TakeUnitStr(FieldUnit eUnit, XubString& rStr)
1037 switch(eUnit)
1039 default :
1040 case FUNIT_NONE :
1041 case FUNIT_CUSTOM :
1043 rStr = UniString();
1044 break;
1047 // metrically
1048 case FUNIT_100TH_MM:
1050 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
1051 break;
1053 case FUNIT_MM :
1055 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
1056 break;
1058 case FUNIT_CM :
1060 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
1061 break;
1063 case FUNIT_M :
1065 rStr = UniString();
1066 rStr += sal_Unicode('m');
1067 break;
1069 case FUNIT_KM :
1071 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("km"));
1072 break;
1075 // Inch
1076 case FUNIT_TWIP :
1078 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
1079 break;
1081 case FUNIT_POINT :
1083 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
1084 break;
1086 case FUNIT_PICA :
1088 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pica"));
1089 break;
1091 case FUNIT_INCH :
1093 rStr = UniString();
1094 rStr += sal_Unicode('"');
1095 break;
1097 case FUNIT_FOOT :
1099 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("ft"));
1100 break;
1102 case FUNIT_MILE :
1104 rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mile(s)"));
1105 break;
1108 // others
1109 case FUNIT_PERCENT:
1111 rStr = UniString();
1112 rStr += sal_Unicode('%');
1113 break;
1118 ////////////////////////////////////////////////////////////////////////////////////////////////////
1121 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */