xref: /trunk/main/svx/source/svdraw/svdtrans.cxx (revision 181dec1222d2f9246c23e1b969c3569952426da0)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svx.hxx"
24 
25 #include <svx/svdtrans.hxx>
26 #include <math.h>
27 #include <svx/xpoly.hxx>
28 
29 #include <vcl/virdev.hxx>
30 #include <tools/bigint.hxx>
31 #include <tools/debug.hxx>
32 #include <unotools/syslocale.hxx>
33 
34 void MoveXPoly(XPolygon& rPoly, const Size& S)
35 {
36     rPoly.Move(S.Width(),S.Height());
37 }
38 
39 void MoveXPoly(XPolyPolygon& rPoly, const Size& S)
40 {
41     rPoly.Move(S.Width(),S.Height());
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////////////////////////////
45 
46 void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact, FASTBOOL bNoJustify)
47 {
48     Fraction xFact(rxFact);
49     Fraction yFact(ryFact);
50     //long nHgt=rRect.Bottom()-rRect.Top();
51 
52     {
53         if (xFact.GetDenominator()==0) {
54             long nWdt=rRect.Right()-rRect.Left();
55             if (xFact.GetNumerator()>=0) { // DivZero abfangen
56                 xFact=Fraction(xFact.GetNumerator(),1);
57                 if (nWdt==0) rRect.Right()++;
58             } else {
59                 xFact=Fraction(xFact.GetNumerator(),-1);
60                 if (nWdt==0) rRect.Left()--;
61             }
62         }
63         rRect.Left()  =rRef.X()+Round(((double)(rRect.Left()  -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
64         rRect.Right() =rRef.X()+Round(((double)(rRect.Right() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
65     }
66     {
67         if (yFact.GetDenominator()==0) {
68             long nHgt=rRect.Bottom()-rRect.Top();
69             if (yFact.GetNumerator()>=0) { // DivZero abfangen
70                 yFact=Fraction(yFact.GetNumerator(),1);
71                 if (nHgt==0) rRect.Bottom()++;
72             } else {
73                 yFact=Fraction(yFact.GetNumerator(),-1);
74                 if (nHgt==0) rRect.Top()--;
75             }
76 
77             yFact=Fraction(yFact.GetNumerator(),1); // DivZero abfangen
78         }
79         rRect.Top()   =rRef.Y()+Round(((double)(rRect.Top()   -rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
80         rRect.Bottom()=rRef.Y()+Round(((double)(rRect.Bottom()-rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
81     }
82     if (!bNoJustify) rRect.Justify();
83 }
84 
85 
86 void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
87 {
88     sal_uInt16 nAnz=rPoly.GetSize();
89     for (sal_uInt16 i=0; i<nAnz; i++) {
90         ResizePoint(rPoly[i],rRef,xFact,yFact);
91     }
92 }
93 
94 void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
95 {
96     sal_uInt16 nAnz=rPoly.GetPointCount();
97     for (sal_uInt16 i=0; i<nAnz; i++) {
98         ResizePoint(rPoly[i],rRef,xFact,yFact);
99     }
100 }
101 
102 void ResizePoly(PolyPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
103 {
104     sal_uInt16 nAnz=rPoly.Count();
105     for (sal_uInt16 i=0; i<nAnz; i++) {
106         ResizePoly(rPoly[i],rRef,xFact,yFact);
107     }
108 }
109 
110 void ResizeXPoly(XPolyPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
111 {
112     sal_uInt16 nAnz=rPoly.Count();
113     for (sal_uInt16 i=0; i<nAnz; i++) {
114         ResizeXPoly(rPoly[i],rRef,xFact,yFact);
115     }
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////////////////////////
119 
120 void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
121 {
122     sal_uInt16 nAnz=rPoly.GetSize();
123     for (sal_uInt16 i=0; i<nAnz; i++) {
124         RotatePoint(rPoly[i],rRef,sn,cs);
125     }
126 }
127 
128 void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
129 {
130     sal_uInt16 nAnz=rPoly.GetPointCount();
131     for (sal_uInt16 i=0; i<nAnz; i++) {
132         RotatePoint(rPoly[i],rRef,sn,cs);
133     }
134 }
135 
136 void RotatePoly(PolyPolygon& rPoly, const Point& rRef, double sn, double cs)
137 {
138     sal_uInt16 nAnz=rPoly.Count();
139     for (sal_uInt16 i=0; i<nAnz; i++) {
140         RotatePoly(rPoly[i],rRef,sn,cs);
141     }
142 }
143 
144 void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
145 {
146     sal_uInt16 nAnz=rPoly.Count();
147     for (sal_uInt16 i=0; i<nAnz; i++) {
148         RotateXPoly(rPoly[i],rRef,sn,cs);
149     }
150 }
151 
152 ////////////////////////////////////////////////////////////////////////////////////////////////////
153 
154 void MirrorRect(Rectangle& rRect, const Point& /*rRef1*/, const Point& /*rRef2*/, FASTBOOL bNoJustify)
155 {
156     // !!! fehlende Implementation !!!
157     if (!bNoJustify) rRect.Justify();
158 }
159 
160 void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
161 {
162     long mx=rRef2.X()-rRef1.X();
163     long my=rRef2.Y()-rRef1.Y();
164     if (mx==0) { // Achse senkrecht
165         long dx=rRef1.X()-rPnt.X();
166         rPnt.X()+=2*dx;
167     } else if (my==0) { // Achse waagerecht
168         long dy=rRef1.Y()-rPnt.Y();
169         rPnt.Y()+=2*dy;
170     } else if (mx==my) { // Achse diagonal '\'
171         long dx1=rPnt.X()-rRef1.X();
172         long dy1=rPnt.Y()-rRef1.Y();
173         rPnt.X()=rRef1.X()+dy1;
174         rPnt.Y()=rRef1.Y()+dx1;
175     } else if (mx==-my) { // Achse diagonal '/'
176         long dx1=rPnt.X()-rRef1.X();
177         long dy1=rPnt.Y()-rRef1.Y();
178         rPnt.X()=rRef1.X()-dy1;
179         rPnt.Y()=rRef1.Y()-dx1;
180     } else { // beliebige Achse
181         // mal optimieren !!!
182         // Lot auf der Spiegelachse fällen oder so
183         long nRefWink=GetAngle(rRef2-rRef1);
184         rPnt-=rRef1;
185         long nPntWink=GetAngle(rPnt);
186         long nWink=2*(nRefWink-nPntWink);
187         double a=nWink*nPi180;
188         double nSin=sin(a);
189         double nCos=cos(a);
190         RotatePoint(rPnt,Point(),nSin,nCos);
191         rPnt+=rRef1;
192     }
193 }
194 
195 void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
196 {
197     sal_uInt16 nAnz=rPoly.GetSize();
198     for (sal_uInt16 i=0; i<nAnz; i++) {
199         MirrorPoint(rPoly[i],rRef1,rRef2);
200     }
201 }
202 
203 void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
204 {
205     sal_uInt16 nAnz=rPoly.GetPointCount();
206     for (sal_uInt16 i=0; i<nAnz; i++) {
207         MirrorPoint(rPoly[i],rRef1,rRef2);
208     }
209 }
210 
211 void MirrorPoly(PolyPolygon& rPoly, const Point& rRef1, const Point& rRef2)
212 {
213     sal_uInt16 nAnz=rPoly.Count();
214     for (sal_uInt16 i=0; i<nAnz; i++) {
215         MirrorPoly(rPoly[i],rRef1,rRef2);
216     }
217 }
218 
219 void MirrorXPoly(XPolyPolygon& rPoly, const Point& rRef1, const Point& rRef2)
220 {
221     sal_uInt16 nAnz=rPoly.Count();
222     for (sal_uInt16 i=0; i<nAnz; i++) {
223         MirrorXPoly(rPoly[i],rRef1,rRef2);
224     }
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////////////////////////
228 
229 void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, FASTBOOL bVShear)
230 {
231     sal_uInt16 nAnz=rPoly.GetSize();
232     for (sal_uInt16 i=0; i<nAnz; i++) {
233         ShearPoint(rPoly[i],rRef,tn,bVShear);
234     }
235 }
236 
237 void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, FASTBOOL bVShear)
238 {
239     sal_uInt16 nAnz=rPoly.GetPointCount();
240     for (sal_uInt16 i=0; i<nAnz; i++) {
241         ShearPoint(rPoly[i],rRef,tn,bVShear);
242     }
243 }
244 
245 void ShearPoly(PolyPolygon& rPoly, const Point& rRef, double tn, FASTBOOL bVShear)
246 {
247     sal_uInt16 nAnz=rPoly.Count();
248     for (sal_uInt16 i=0; i<nAnz; i++) {
249         ShearPoly(rPoly[i],rRef,tn,bVShear);
250     }
251 }
252 
253 void ShearXPoly(XPolyPolygon& rPoly, const Point& rRef, double tn, FASTBOOL bVShear)
254 {
255     sal_uInt16 nAnz=rPoly.Count();
256     for (sal_uInt16 i=0; i<nAnz; i++) {
257         ShearXPoly(rPoly[i],rRef,tn,bVShear);
258     }
259 }
260 
261 ////////////////////////////////////////////////////////////////////////////////////////////////////
262 // CROOK
263 ////////////////////////////////////////////////////////////////////////////////////////////////////
264 
265 double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
266                          const Point& rRad, double& rSin, double& rCos, FASTBOOL bVert)
267 {
268     FASTBOOL bC1=pC1!=NULL;
269     FASTBOOL bC2=pC2!=NULL;
270     long x0=rPnt.X();
271     long y0=rPnt.Y();
272     long cx=rCenter.X();
273     long cy=rCenter.Y();
274     double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
275     double sn=sin(nWink);
276     double cs=cos(nWink);
277     RotatePoint(rPnt,rCenter,sn,cs);
278     if (bC1) {
279         if (bVert) {
280             // Richtung Zentrum verschieben, als Ausgangsposition für Rotate
281             pC1->Y()-=y0;
282             // Resize, entsprechend der Entfernung vom Zentrum
283             pC1->Y()=Round(((double)pC1->Y()) /rRad.X()*(cx-pC1->X()));
284             pC1->Y()+=cy;
285         } else {
286             // Richtung Zentrum verschieben, als Ausgangsposition für Rotate
287             pC1->X()-=x0;
288             // Resize, entsprechend der Entfernung vom Zentrum
289             long nPntRad=cy-pC1->Y();
290             double nFact=(double)nPntRad/(double)rRad.Y();
291             pC1->X()=Round((double)pC1->X()*nFact);
292             pC1->X()+=cx;
293         }
294         RotatePoint(*pC1,rCenter,sn,cs);
295     }
296     if (bC2) {
297         if (bVert) {
298             // Richtung Zentrum verschieben, als Ausgangsposition für Rotate
299             pC2->Y()-=y0;
300             // Resize, entsprechend der Entfernung vom Zentrum
301             pC2->Y()=Round(((double)pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X()));
302             pC2->Y()+=cy;
303         } else {
304             // Richtung Zentrum verschieben, als Ausgangsposition für Rotate
305             pC2->X()-=x0;
306             // Resize, entsprechend der Entfernung vom Zentrum
307             long nPntRad=rCenter.Y()-pC2->Y();
308             double nFact=(double)nPntRad/(double)rRad.Y();
309             pC2->X()=Round((double)pC2->X()*nFact);
310             pC2->X()+=cx;
311         }
312         RotatePoint(*pC2,rCenter,sn,cs);
313     }
314     rSin=sn;
315     rCos=cs;
316     return nWink;
317 }
318 
319 double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
320                         const Point& rRad, double& rSin, double& rCos, FASTBOOL bVert)
321 {
322     FASTBOOL bC1=pC1!=NULL;
323     FASTBOOL bC2=pC2!=NULL;
324     long x0=rPnt.X();
325     long y0=rPnt.Y();
326     long dx1=0,dy1=0;
327     long dxC1=0,dyC1=0;
328     long dxC2=0,dyC2=0;
329     if (bVert) {
330         long nStart=rCenter.X()-rRad.X();
331         dx1=rPnt.X()-nStart;
332         rPnt.X()=nStart;
333         if (bC1) {
334             dxC1=pC1->X()-nStart;
335             pC1->X()=nStart;
336         }
337         if (bC2) {
338             dxC2=pC2->X()-nStart;
339             pC2->X()=nStart;
340         }
341     } else {
342         long nStart=rCenter.Y()-rRad.Y();
343         dy1=rPnt.Y()-nStart;
344         rPnt.Y()=nStart;
345         if (bC1) {
346             dyC1=pC1->Y()-nStart;
347             pC1->Y()=nStart;
348         }
349         if (bC2) {
350             dyC2=pC2->Y()-nStart;
351             pC2->Y()=nStart;
352         }
353     }
354     double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
355     double sn=sin(nWink);
356     double cs=cos(nWink);
357     RotatePoint(rPnt,rCenter,sn,cs);
358     if (bC1) { if (bVert) pC1->Y()-=y0-rCenter.Y(); else pC1->X()-=x0-rCenter.X(); RotatePoint(*pC1,rCenter,sn,cs); }
359     if (bC2) { if (bVert) pC2->Y()-=y0-rCenter.Y(); else pC2->X()-=x0-rCenter.X(); RotatePoint(*pC2,rCenter,sn,cs); }
360     if (bVert) {
361         rPnt.X()+=dx1;
362         if (bC1) pC1->X()+=dxC1;
363         if (bC2) pC2->X()+=dxC2;
364     } else {
365         rPnt.Y()+=dy1;
366         if (bC1) pC1->Y()+=dyC1;
367         if (bC2) pC2->Y()+=dyC2;
368     }
369     rSin=sn;
370     rCos=cs;
371     return nWink;
372 }
373 
374 double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
375                           const Point& rRad, double& rSin, double& rCos, FASTBOOL bVert,
376                           const Rectangle rRefRect)
377 {
378     //FASTBOOL bC1=pC1!=NULL;
379     //FASTBOOL bC2=pC2!=NULL;
380     //long x0=rPnt.X();
381     long y0=rPnt.Y();
382     CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
383     if (bVert) {
384     } else {
385         //long nBase=rCenter.Y()-rRad.Y();
386         long nTop=rRefRect.Top();
387         long nBtm=rRefRect.Bottom();
388         long nHgt=nBtm-nTop;
389         long dy=rPnt.Y()-y0;
390         //FASTBOOL bOben=rRad.Y()<0;
391         double a=((double)(y0-nTop))/nHgt;
392         a*=dy;
393         rPnt.Y()=y0+Round(a);
394     } return 0.0;
395 }
396 
397 ////////////////////////////////////////////////////////////////////////////////////////////////////
398 
399 void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert)
400 {
401     double nSin,nCos;
402     sal_uInt16 nPointCount=rPoly.GetPointCount();
403     sal_uInt16 i=0;
404     while (i<nPointCount) {
405         Point* pPnt=&rPoly[i];
406         Point* pC1=NULL;
407         Point* pC2=NULL;
408         if (i+1<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt links
409             pC1=pPnt;
410             i++;
411             pPnt=&rPoly[i];
412         }
413         i++;
414         if (i<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt rechts
415             pC2=&rPoly[i];
416             i++;
417         }
418         CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
419     }
420 }
421 
422 void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert)
423 {
424     double nSin,nCos;
425     sal_uInt16 nPointCount=rPoly.GetPointCount();
426     sal_uInt16 i=0;
427     while (i<nPointCount) {
428         Point* pPnt=&rPoly[i];
429         Point* pC1=NULL;
430         Point* pC2=NULL;
431         if (i+1<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt links
432             pC1=pPnt;
433             i++;
434             pPnt=&rPoly[i];
435         }
436         i++;
437         if (i<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt rechts
438             pC2=&rPoly[i];
439             i++;
440         }
441         CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
442     }
443 }
444 
445 void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert, const Rectangle rRefRect)
446 {
447     double nSin,nCos;
448     sal_uInt16 nPointCount=rPoly.GetPointCount();
449     sal_uInt16 i=0;
450     while (i<nPointCount) {
451         Point* pPnt=&rPoly[i];
452         Point* pC1=NULL;
453         Point* pC2=NULL;
454         if (i+1<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt links
455             pC1=pPnt;
456             i++;
457             pPnt=&rPoly[i];
458         }
459         i++;
460         if (i<nPointCount && rPoly.IsControl(i)) { // Kontrollpunkt rechts
461             pC2=&rPoly[i];
462             i++;
463         }
464         CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
465     }
466 }
467 
468 ////////////////////////////////////////////////////////////////////////////////////////////////////
469 
470 void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert)
471 {
472     sal_uInt16 nPolyCount=rPoly.Count();
473     for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
474         CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
475     }
476 }
477 
478 void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert)
479 {
480     sal_uInt16 nPolyCount=rPoly.Count();
481     for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
482         CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
483     }
484 }
485 
486 void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, FASTBOOL bVert, const Rectangle rRefRect)
487 {
488     sal_uInt16 nPolyCount=rPoly.Count();
489     for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
490         CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
491     }
492 }
493 
494 ////////////////////////////////////////////////////////////////////////////////////////////////////
495 
496 long GetAngle(const Point& rPnt)
497 {
498     long a=0;
499     if (rPnt.Y()==0) {
500         if (rPnt.X()<0) a=-18000;
501     } else if (rPnt.X()==0) {
502         if (rPnt.Y()>0) a=-9000;
503         else a=9000;
504     } else {
505         a=Round((atan2((double)-rPnt.Y(),(double)rPnt.X())/nPi180));
506     }
507     return a;
508 }
509 
510 long NormAngle180(long a)
511 {
512     while (a<18000) a+=36000;
513     while (a>=18000) a-=36000;
514     return a;
515 }
516 
517 long NormAngle360(long a)
518 {
519     while (a<0) a+=36000;
520     while (a>=36000) a-=36000;
521     return a;
522 }
523 
524 sal_uInt16 GetAngleSector(long nWink)
525 {
526     while (nWink<0) nWink+=36000;
527     while (nWink>=36000) nWink-=36000;
528     if (nWink< 9000) return 0;
529     if (nWink<18000) return 1;
530     if (nWink<27000) return 2;
531     return 3;
532 }
533 
534 long GetLen(const Point& rPnt)
535 {
536     long x=Abs(rPnt.X());
537     long y=Abs(rPnt.Y());
538     if (x+y<0x8000) { // weil 7FFF * 7FFF * 2 = 7FFE0002
539         x*=x;
540         y*=y;
541         x+=y;
542         x=Round(sqrt((double)x));
543         return x;
544     } else {
545         double nx=x;
546         double ny=y;
547         nx*=nx;
548         ny*=ny;
549         nx+=ny;
550         nx=sqrt(nx);
551         if (nx>0x7FFFFFFF) {
552             return 0x7FFFFFFF; // Überlauf, mehr ist nicht!
553         } else {
554             return Round(nx);
555         }
556     }
557 }
558 
559 ////////////////////////////////////////////////////////////////////////////////////////////////////
560 
561 void GeoStat::RecalcSinCos()
562 {
563     if (nDrehWink==0) {
564         nSin=0.0;
565         nCos=1.0;
566     } else {
567         double a=nDrehWink*nPi180;
568         nSin=sin(a);
569         nCos=cos(a);
570     }
571 }
572 
573 void GeoStat::RecalcTan()
574 {
575     if (nShearWink==0) {
576         nTan=0.0;
577     } else {
578         double a=nShearWink*nPi180;
579         nTan=tan(a);
580     }
581 }
582 
583 ////////////////////////////////////////////////////////////////////////////////////////////////////
584 
585 Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
586 {
587     Polygon aPol(5);
588     aPol[0]=rRect.TopLeft();
589     aPol[1]=rRect.TopRight();
590     aPol[2]=rRect.BottomRight();
591     aPol[3]=rRect.BottomLeft();
592     aPol[4]=rRect.TopLeft();
593     if (rGeo.nShearWink!=0) ShearPoly(aPol,rRect.TopLeft(),rGeo.nTan);
594     if (rGeo.nDrehWink!=0) RotatePoly(aPol,rRect.TopLeft(),rGeo.nSin,rGeo.nCos);
595     return aPol;
596 }
597 
598 void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
599 {
600     rGeo.nDrehWink=GetAngle(rPol[1]-rPol[0]);
601     rGeo.nDrehWink=NormAngle360(rGeo.nDrehWink);
602     // Drehung ist damit im Kasten
603     rGeo.RecalcSinCos();
604 
605     Point aPt1(rPol[1]-rPol[0]);
606     if (rGeo.nDrehWink!=0) RotatePoint(aPt1,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin für Rückdrehung
607     long nWdt=aPt1.X();
608 
609     Point aPt0(rPol[0]);
610     Point aPt3(rPol[3]-rPol[0]);
611     if (rGeo.nDrehWink!=0) RotatePoint(aPt3,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin für Rückdrehung
612     long nHgt=aPt3.Y();
613 
614     if(aPt3.X())
615     {
616         // #i74358# the axes are not orthogonal, so for getting the correct height,
617         // calculate the length of aPt3
618 
619         // #i74358# this change was wrong, in the field of the old geometry stuff
620         // it is not an error. The new height always is the same as before; shear
621         // does not change object height at all. This is different from the interactions,
622         // but obviously wanted in the old versions.
623         //
624         // nHgt = static_cast< long >(sqrt(static_cast< double >(aPt3.X() * aPt3.X() + aPt3.Y() * aPt3.Y())));
625     }
626 
627     long nShW=GetAngle(aPt3);
628     nShW-=27000; // ShearWink wird zur Senkrechten gemessen
629     nShW=-nShW; // Negieren, denn '+' ist Rechtskursivierung
630 
631     FASTBOOL bMirr=aPt3.Y()<0;
632     if (bMirr) { // "Punktetausch" bei Spiegelung
633         nHgt=-nHgt;
634         nShW+=18000;
635         aPt0=rPol[3];
636     }
637     nShW=NormAngle180(nShW);
638     if (nShW<-9000 || nShW>9000) {
639         nShW=NormAngle180(nShW+18000);
640     }
641     if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // ShearWinkel begrenzen auf +/- 89.00 deg
642     if (nShW>SDRMAXSHEAR)  nShW=SDRMAXSHEAR;
643     rGeo.nShearWink=nShW;
644     rGeo.RecalcTan();
645     Point aRU(aPt0);
646     aRU.X()+=nWdt;
647     aRU.Y()+=nHgt;
648     rRect=Rectangle(aPt0,aRU);
649 }
650 
651 ////////////////////////////////////////////////////////////////////////////////////////////////////
652 
653 void OrthoDistance8(const Point& rPt0, Point& rPt, FASTBOOL bBigOrtho)
654 {
655     long dx=rPt.X()-rPt0.X();
656     long dy=rPt.Y()-rPt0.Y();
657     long dxa=Abs(dx);
658     long dya=Abs(dy);
659     if (dx==0 || dy==0 || dxa==dya) return;
660     if (dxa>=dya*2) { rPt.Y()=rPt0.Y(); return; }
661     if (dya>=dxa*2) { rPt.X()=rPt0.X(); return; }
662     if ((dxa<dya) != bBigOrtho) {
663         rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
664     } else {
665         rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
666     }
667 }
668 
669 void OrthoDistance4(const Point& rPt0, Point& rPt, FASTBOOL bBigOrtho)
670 {
671     long dx=rPt.X()-rPt0.X();
672     long dy=rPt.Y()-rPt0.Y();
673     long dxa=Abs(dx);
674     long dya=Abs(dy);
675     if ((dxa<dya) != bBigOrtho) {
676         rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
677     } else {
678         rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
679     }
680 }
681 
682 ////////////////////////////////////////////////////////////////////////////////////////////////////
683 
684 long BigMulDiv(long nVal, long nMul, long nDiv)
685 {
686     BigInt aVal(nVal);
687     aVal*=nMul;
688     if (aVal.IsNeg()!=(nDiv<0)) {
689         aVal-=nDiv/2; // für korrektes Runden
690     } else {
691         aVal+=nDiv/2; // für korrektes Runden
692     }
693     if(nDiv)
694     {
695         aVal/=nDiv;
696         return long(aVal);
697     }
698     return 0x7fffffff;
699 }
700 
701 void Kuerzen(Fraction& rF, unsigned nDigits)
702 {
703     sal_Int32 nMul=rF.GetNumerator();
704     sal_Int32 nDiv=rF.GetDenominator();
705     FASTBOOL bNeg=sal_False;
706     if (nMul<0) { nMul=-nMul; bNeg=!bNeg; }
707     if (nDiv<0) { nDiv=-nDiv; bNeg=!bNeg; }
708     if (nMul==0 || nDiv==0) return;
709     sal_uInt32 a;
710     a=sal_uInt32(nMul); unsigned nMulZ=0; // Führende Nullen zählen
711     while (a<0x00800000) { nMulZ+=8; a<<=8; }
712     while (a<0x80000000) { nMulZ++; a<<=1; }
713     a=sal_uInt32(nDiv); unsigned nDivZ=0; // Führende Nullen zählen
714     while (a<0x00800000) { nDivZ+=8; a<<=8; }
715     while (a<0x80000000) { nDivZ++; a<<=1; }
716     // Anzahl der verwendeten Digits bestimmen
717     int nMulDigits=32-nMulZ;
718     int nDivDigits=32-nDivZ;
719     // Nun bestimmen, wieviele Stellen hinten weg können
720     int nMulWeg=nMulDigits-nDigits; if (nMulWeg<0) nMulWeg=0;
721     int nDivWeg=nDivDigits-nDigits; if (nDivWeg<0) nDivWeg=0;
722     int nWeg=Min(nMulWeg,nDivWeg);
723     nMul>>=nWeg;
724     nDiv>>=nWeg;
725     if (nMul==0 || nDiv==0) {
726         DBG_WARNING("Oups, beim kürzen einer Fraction hat sich Joe verrechnet.");
727         return;
728     }
729     if (bNeg) nMul=-nMul;
730     rF=Fraction(nMul,nDiv);
731 }
732 
733 ////////////////////////////////////////////////////////////////////////////////////////////////////
734 // Wieviele eU-Einheiten passen in einen mm bzw. Inch?
735 // Oder wie groß ist ein eU in mm bzw. Inch, und davon der Kehrwert
736 
737 FrPair GetInchOrMM(MapUnit eU)
738 {
739     switch (eU) {
740         case MAP_1000TH_INCH: return FrPair(1000,1);
741         case MAP_100TH_INCH : return FrPair( 100,1);
742         case MAP_10TH_INCH  : return FrPair(  10,1);
743         case MAP_INCH       : return FrPair(   1,1);
744         case MAP_POINT      : return FrPair(  72,1);
745         case MAP_TWIP       : return FrPair(1440,1);
746         case MAP_100TH_MM   : return FrPair( 100,1);
747         case MAP_10TH_MM    : return FrPair(  10,1);
748         case MAP_MM         : return FrPair(   1,1);
749         case MAP_CM         : return FrPair(   1,10);
750         case MAP_PIXEL      : {
751             VirtualDevice aVD;
752             aVD.SetMapMode(MapMode(MAP_100TH_MM));
753             Point aP(aVD.PixelToLogic(Point(64,64))); // 64 Pixel für bessere Genauigkeit
754             return FrPair(6400,aP.X(),6400,aP.Y());
755         }
756         case MAP_APPFONT: case MAP_SYSFONT: {
757             VirtualDevice aVD;
758             aVD.SetMapMode(MapMode(eU));
759             Point aP(aVD.LogicToPixel(Point(32,32))); // 32 Einheiten für bessere Genauigkeit
760             aVD.SetMapMode(MapMode(MAP_100TH_MM));
761             aP=aVD.PixelToLogic(aP);
762             return FrPair(3200,aP.X(),3200,aP.Y());
763         }
764         default: break;
765     }
766     return Fraction(1,1);
767 }
768 
769 FrPair GetInchOrMM(FieldUnit eU)
770 {
771     switch (eU) {
772         case FUNIT_INCH       : return FrPair(   1,1);
773         case FUNIT_POINT      : return FrPair(  72,1);
774         case FUNIT_TWIP       : return FrPair(1440,1);
775         case FUNIT_100TH_MM   : return FrPair( 100,1);
776         case FUNIT_MM         : return FrPair(   1,1);
777         case FUNIT_CM         : return FrPair(   1,10);
778         case FUNIT_M          : return FrPair(   1,1000);
779         case FUNIT_KM         : return FrPair(   1,1000000);
780         case FUNIT_PICA       : return FrPair(   6,1);
781         case FUNIT_FOOT       : return FrPair(   1,12);
782         case FUNIT_MILE       : return FrPair(   1,63360);
783         default: break;
784     }
785     return Fraction(1,1);
786 }
787 
788 // Den Faktor berechnen, der anzuwenden ist um n Einheiten von eS nach
789 // eD umzurechnen. Z.B. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
790 
791 FrPair GetMapFactor(MapUnit eS, MapUnit eD)
792 {
793     if (eS==eD) return FrPair(1,1,1,1);
794     FrPair aS(GetInchOrMM(eS));
795     FrPair aD(GetInchOrMM(eD));
796     FASTBOOL bSInch=IsInch(eS);
797     FASTBOOL bDInch=IsInch(eD);
798     FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
799     if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
800     if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
801     return aRet;
802 };
803 
804 FrPair GetMapFactor(MapUnit eS, FieldUnit eD)
805 {
806     FrPair aS(GetInchOrMM(eS));
807     FrPair aD(GetInchOrMM(eD));
808     FASTBOOL bSInch=IsInch(eS);
809     FASTBOOL bDInch=IsInch(eD);
810     FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
811     if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
812     if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
813     return aRet;
814 };
815 
816 FrPair GetMapFactor(FieldUnit eS, MapUnit eD)
817 {
818     FrPair aS(GetInchOrMM(eS));
819     FrPair aD(GetInchOrMM(eD));
820     FASTBOOL bSInch=IsInch(eS);
821     FASTBOOL bDInch=IsInch(eD);
822     FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
823     if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
824     if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
825     return aRet;
826 };
827 
828 FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
829 {
830     if (eS==eD) return FrPair(1,1,1,1);
831     FrPair aS(GetInchOrMM(eS));
832     FrPair aD(GetInchOrMM(eD));
833     FASTBOOL bSInch=IsInch(eS);
834     FASTBOOL bDInch=IsInch(eD);
835     FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
836     if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
837     if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
838     return aRet;
839 };
840 
841 ////////////////////////////////////////////////////////////////////////////////////////////////////
842 
843     // 1 mile    =  8 furlong = 63.360" = 1.609.344,0mm
844     // 1 furlong = 10 chains  =  7.920" =   201.168,0mm
845     // 1 chain   =  4 poles   =    792" =    20.116,8mm
846     // 1 pole    =  5 1/2 yd  =    198" =     5.029,2mm
847     // 1 yd      =  3 ft      =     36" =       914,4mm
848     // 1 ft      = 12 "       =      1" =       304,8mm
849 
850 void GetMeterOrInch(MapUnit eMU, short& rnComma, long& rnMul, long& rnDiv, int& rbMetr, int& rbInch)
851 {
852     rnMul=1; rnDiv=1;
853     short nComma=0;
854     FASTBOOL bMetr=sal_False,bInch=sal_False;
855     switch (eMU) {
856         // Metrisch
857         case MAP_100TH_MM   : bMetr=sal_True; nComma=5; break;
858         case MAP_10TH_MM    : bMetr=sal_True; nComma=4; break;
859         case MAP_MM         : bMetr=sal_True; nComma=3; break;
860         case MAP_CM         : bMetr=sal_True; nComma=2; break;
861         // Inch
862         case MAP_1000TH_INCH: bInch=sal_True; nComma=3; break;
863         case MAP_100TH_INCH : bInch=sal_True; nComma=2; break;
864         case MAP_10TH_INCH  : bInch=sal_True; nComma=1; break;
865         case MAP_INCH       : bInch=sal_True; nComma=0; break;
866         case MAP_POINT      : bInch=sal_True; rnDiv=72; break; // 1Pt = 1/72"
867         case MAP_TWIP       : bInch=sal_True; rnDiv=144; nComma=1; break; // 1Twip = 1/1440"
868         // Sonstiges
869         case MAP_PIXEL      : break;
870         case MAP_SYSFONT    : break;
871         case MAP_APPFONT    : break;
872         case MAP_RELATIVE   : break;
873         default: break;
874     } // switch
875     rnComma=nComma;
876     rbMetr=bMetr;
877     rbInch=bInch;
878 }
879 
880 void GetMeterOrInch(FieldUnit eFU, short& rnComma, long& rnMul, long& rnDiv, int& rbMetr, int& rbInch)
881 {
882     rnMul=1; rnDiv=1;
883     short nComma=0;
884     FASTBOOL bMetr=sal_False,bInch=sal_False;
885     switch (eFU) {
886         case FUNIT_NONE     : break;
887         // Metrisch
888         case FUNIT_100TH_MM : bMetr=sal_True; nComma=5; break;
889         case FUNIT_MM       : bMetr=sal_True; nComma=3; break;
890         case FUNIT_CM       : bMetr=sal_True; nComma=2; break;
891         case FUNIT_M        : bMetr=sal_True; nComma=0; break;
892         case FUNIT_KM       : bMetr=sal_True; nComma=-3; break;
893         // Inch
894         case FUNIT_TWIP     : bInch=sal_True; rnDiv=144; nComma=1; break; // 1Twip = 1/1440"
895         case FUNIT_POINT    : bInch=sal_True; rnDiv=72; break;   // 1Pt = 1/72"
896         case FUNIT_PICA     : bInch=sal_True; rnDiv=6; break;    // 1Pica = 1/6" ?
897         case FUNIT_INCH     : bInch=sal_True; break;             // 1" = 1"
898         case FUNIT_FOOT     : bInch=sal_True; rnMul=12; break;   // 1Ft = 12"
899         case FUNIT_MILE     : bInch=sal_True; rnMul=6336; nComma=-1; break; // 1mile = 63360"
900         // sonstiges
901         case FUNIT_CUSTOM   : break;
902         case FUNIT_PERCENT  : nComma=2; break;
903     } // switch
904     rnComma=nComma;
905     rbMetr=bMetr;
906     rbInch=bInch;
907 }
908 
909 void SdrFormatter::Undirty()
910 {
911     if (aScale.GetNumerator()==0 || aScale.GetDenominator()==0) aScale=Fraction(1,1);
912     FASTBOOL bSrcMetr,bSrcInch,bDstMetr,bDstInch;
913     long nMul1,nDiv1,nMul2,nDiv2;
914     short nComma1,nComma2;
915     // Zunächst normalisieren auf m bzw. "
916     if (!bSrcFU) {
917         GetMeterOrInch(eSrcMU,nComma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
918     } else {
919         GetMeterOrInch(eSrcFU,nComma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
920     }
921     if (!bDstFU) {
922         GetMeterOrInch(eDstMU,nComma2,nMul2,nDiv2,bDstMetr,bDstInch);
923     } else {
924         GetMeterOrInch(eDstFU,nComma2,nMul2,nDiv2,bDstMetr,bDstInch);
925     }
926     nMul1*=nDiv2;
927     nDiv1*=nMul2;
928     nComma1=nComma1-nComma2;
929 
930     if (bSrcInch && bDstMetr) {
931         nComma1+=4;
932         nMul1*=254;
933     }
934     if (bSrcMetr && bDstInch) {
935         nComma1-=4;
936         nDiv1*=254;
937     }
938 
939     // Temporäre Fraction zum Kürzen
940     Fraction aTempFract(nMul1,nDiv1);
941     nMul1=aTempFract.GetNumerator();
942     nDiv1=aTempFract.GetDenominator();
943 
944     nMul_=nMul1;
945     nDiv_=nDiv1;
946     nComma_=nComma1;
947     bDirty=sal_False;
948 }
949 
950 
951 void SdrFormatter::TakeStr(long nVal, XubString& rStr) const
952 {
953     sal_Unicode aNullCode('0');
954 
955     if(!nVal)
956     {
957         rStr = UniString();
958         rStr += aNullCode;
959         return;
960     }
961 
962     // Hier fallen trotzdem evtl. Nachkommastellen weg, wg. MulDiv statt Real
963     sal_Bool bNeg(nVal < 0);
964     SvtSysLocale aSysLoc;
965     const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
966 
967     ForceUndirty();
968 
969     sal_Int16 nK(nComma_);
970     XubString aStr;
971 
972     if(bNeg)
973         nVal = -nVal;
974 
975     while(nK <= -3)
976     {
977         nVal *= 1000;
978         nK += 3;
979     }
980 
981     while(nK <= -1)
982     {
983         nVal *= 10;
984         nK++;
985     }
986 
987     if(nMul_ != nDiv_)
988         nVal = BigMulDiv(nVal, nMul_, nDiv_);
989 
990     aStr = UniString::CreateFromInt32(nVal);
991 
992     if(nK > 0 && aStr.Len() <= nK )
993     {
994         // Komma erforderlich
995         sal_Int16 nAnz(nK - aStr.Len());
996 
997         if(nAnz >= 0 && rLoc.isNumLeadingZero())
998             nAnz++;
999 
1000         for(xub_StrLen i=0; i<nAnz; i++)
1001             aStr.Insert(aNullCode, 0);
1002 
1003         // zu viele Nachkommastellen abhacken
1004         xub_StrLen nNumDigits(rLoc.getNumDigits());
1005         xub_StrLen nWeg(nK - nNumDigits);
1006 
1007         if(nWeg > 0)
1008         {
1009             // hier müsste eigentlich noch gerundet werden!
1010             aStr.Erase(aStr.Len() - nWeg);
1011             nK = nNumDigits;
1012         }
1013     }
1014 
1015     // Vorkommastellen für später merken
1016     xub_StrLen nPreComma(aStr.Len() - nK);
1017 
1018     if(nK > 0)
1019     {
1020         // KommaChar einfügen
1021         // erstmal trailing Zeros abhacken
1022         while(nK > 0 && aStr.GetChar(aStr.Len() - 1) == aNullCode)
1023         {
1024             aStr.Erase(aStr.Len() - 1);
1025             nK--;
1026         }
1027 
1028         if(nK > 0)
1029         {
1030             // na, noch Nachkommastellen da?
1031             sal_Unicode cDec(rLoc.getNumDecimalSep().GetChar(0));
1032             aStr.Insert(cDec, nPreComma);
1033         }
1034     }
1035 
1036     // ggf. Trennpunkte bei jedem Tausender einfügen
1037     if( nPreComma > 3 )
1038     {
1039         String aThoSep( rLoc.getNumThousandSep() );
1040         if ( aThoSep.Len() > 0 )
1041         {
1042             sal_Unicode cTho( aThoSep.GetChar(0) );
1043             sal_Int32 i(nPreComma - 3);
1044 
1045             while(i > 0)
1046             {
1047                 rStr.Insert(cTho, (xub_StrLen)i);
1048                 i -= 3;
1049             }
1050         }
1051     }
1052 
1053     if(!aStr.Len())
1054         aStr += aNullCode;
1055 
1056     if(bNeg && (aStr.Len() > 1 || aStr.GetChar(0) != aNullCode))
1057     {
1058         rStr.Insert(sal_Unicode('-'), 0);
1059     }
1060 
1061     rStr = aStr;
1062 }
1063 
1064 void SdrFormatter::TakeUnitStr(MapUnit eUnit, XubString& rStr)
1065 {
1066     const sal_Char* pText;
1067 
1068     switch(eUnit)
1069     {
1070         // metric units
1071         case MAP_100TH_MM   : pText = "/100mm"; break;
1072         case MAP_10TH_MM    : pText = "/10mm"; break;
1073         case MAP_MM         : pText = "mm"; break;
1074         case MAP_CM         : pText = "cm"; break;
1075 
1076         // imperial units
1077         case MAP_1000TH_INCH: pText = "/1000\""; break;
1078         case MAP_100TH_INCH : pText = "/100\""; break;
1079         case MAP_10TH_INCH  : pText = "/10\""; break;
1080         case MAP_INCH       : pText = "\""; break;
1081         case MAP_POINT      : pText = "pt"; break;
1082         case MAP_TWIP       : pText = "twip"; break;
1083 
1084         // other units
1085         case MAP_PIXEL      : pText = "pixel"; break;
1086         case MAP_SYSFONT    : pText = "sysfont"; break;
1087         case MAP_APPFONT    : pText = "appfont"; break;
1088         case MAP_RELATIVE   : pText = "%"; break;
1089 
1090         default             : pText = ""; break;
1091     }
1092 
1093     rStr = XubString::CreateFromAscii( pText );
1094 }
1095 
1096 void SdrFormatter::TakeUnitStr(FieldUnit eUnit, XubString& rStr)
1097 {
1098     const sal_Char* pText;
1099 
1100     switch(eUnit)
1101     {
1102         // metric units
1103         case FUNIT_100TH_MM : pText = "/100mm"; break;
1104         case FUNIT_MM       : pText = "mm"; break;
1105         case FUNIT_CM       : pText = "cm"; break;
1106         case FUNIT_M        : pText = "m"; break;
1107         case FUNIT_KM       : pText = "km"; break;
1108 
1109         // imperial units
1110         case FUNIT_TWIP     : pText = "twip"; break;
1111         case FUNIT_POINT    : pText = "pt"; break;
1112         case FUNIT_PICA     : pText = "pica"; break;
1113         case FUNIT_INCH     : pText = "\""; break;
1114         case FUNIT_FOOT     : pText = "ft"; break;
1115         case FUNIT_MILE     : pText = "mile(s)"; break;
1116 
1117         // other units
1118         case FUNIT_PERCENT: pText = "%"; break;
1119 
1120 //      case FUNIT_NONE     :
1121 //      case FUNIT_CUSTOM   :
1122         default             : pText = ""; break;
1123     }
1124 
1125     rStr = XubString::CreateFromAscii( pText );
1126 }
1127 
1128 /* vim: set noet sw=4 ts=4: */
1129