PageRenderTime 294ms CodeModel.GetById 81ms app.highlight 161ms RepoModel.GetById 40ms app.codeStats 0ms

/libreoffice-3.6.0.2/svx/source/svdraw/svdtrans.cxx

#
C++ | 1121 lines | 944 code | 96 blank | 81 comment | 177 complexity | 3e414a2961884c6be629c3f36f8166e8 MD5 | raw file
   1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
   2/*************************************************************************
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * Copyright 2000, 2010 Oracle and/or its affiliates.
   7 *
   8 * OpenOffice.org - a multi-platform office productivity suite
   9 *
  10 * This file is part of OpenOffice.org.
  11 *
  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.
  15 *
  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).
  21 *
  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.
  26 *
  27 ************************************************************************/
  28
  29
  30#include <svx/svdtrans.hxx>
  31#include <math.h>
  32#include <svx/xpoly.hxx>
  33
  34#include <vcl/virdev.hxx>
  35#include <tools/bigint.hxx>
  36#include <tools/debug.hxx>
  37#include <unotools/syslocale.hxx>
  38
  39void MoveXPoly(XPolygon& rPoly, const Size& S)
  40{
  41    rPoly.Move(S.Width(),S.Height());
  42}
  43
  44void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact, bool bNoJustify)
  45{
  46    Fraction xFact(rxFact);
  47    Fraction yFact(ryFact);
  48
  49    {
  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()--;
  58            }
  59        }
  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());
  62    }
  63    {
  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()--;
  72            }
  73
  74            yFact=Fraction(yFact.GetNumerator(),1); // catch divisions by zero
  75        }
  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());
  78    }
  79    if (!bNoJustify) rRect.Justify();
  80}
  81
  82
  83void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
  84{
  85    sal_uInt16 nAnz=rPoly.GetSize();
  86    for (sal_uInt16 i=0; i<nAnz; i++) {
  87        ResizePoint(rPoly[i],rRef,xFact,yFact);
  88    }
  89}
  90
  91void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
  92{
  93    sal_uInt16 nAnz=rPoly.GetPointCount();
  94    for (sal_uInt16 i=0; i<nAnz; i++) {
  95        ResizePoint(rPoly[i],rRef,xFact,yFact);
  96    }
  97}
  98
  99void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
 100{
 101    sal_uInt16 nAnz=rPoly.GetSize();
 102    for (sal_uInt16 i=0; i<nAnz; i++) {
 103        RotatePoint(rPoly[i],rRef,sn,cs);
 104    }
 105}
 106
 107void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
 108{
 109    sal_uInt16 nAnz=rPoly.GetPointCount();
 110    for (sal_uInt16 i=0; i<nAnz; i++) {
 111        RotatePoint(rPoly[i],rRef,sn,cs);
 112    }
 113}
 114
 115void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
 116{
 117    sal_uInt16 nAnz=rPoly.Count();
 118    for (sal_uInt16 i=0; i<nAnz; i++) {
 119        RotateXPoly(rPoly[i],rRef,sn,cs);
 120    }
 121}
 122
 123void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
 124{
 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;
 154    }
 155}
 156
 157void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
 158{
 159    sal_uInt16 nAnz=rPoly.GetSize();
 160    for (sal_uInt16 i=0; i<nAnz; i++) {
 161        MirrorPoint(rPoly[i],rRef1,rRef2);
 162    }
 163}
 164
 165void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
 166{
 167    sal_uInt16 nAnz=rPoly.GetPointCount();
 168    for (sal_uInt16 i=0; i<nAnz; i++) {
 169        MirrorPoint(rPoly[i],rRef1,rRef2);
 170    }
 171}
 172
 173void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear)
 174{
 175    sal_uInt16 nAnz=rPoly.GetSize();
 176    for (sal_uInt16 i=0; i<nAnz; i++) {
 177        ShearPoint(rPoly[i],rRef,tn,bVShear);
 178    }
 179}
 180
 181void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
 182{
 183    sal_uInt16 nAnz=rPoly.GetPointCount();
 184    for (sal_uInt16 i=0; i<nAnz; i++) {
 185        ShearPoint(rPoly[i],rRef,tn,bVShear);
 186    }
 187}
 188
 189double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
 190                         const Point& rRad, double& rSin, double& rCos, bool bVert)
 191{
 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;
 217        }
 218        RotatePoint(*pC1,rCenter,sn,cs);
 219    }
 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;
 235        }
 236        RotatePoint(*pC2,rCenter,sn,cs);
 237    }
 238    rSin=sn;
 239    rCos=cs;
 240    return nWink;
 241}
 242
 243double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
 244                        const Point& rRad, double& rSin, double& rCos, bool bVert)
 245{
 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;
 260        }
 261        if (bC2) {
 262            dxC2=pC2->X()-nStart;
 263            pC2->X()=nStart;
 264        }
 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;
 272        }
 273        if (bC2) {
 274            dyC2=pC2->Y()-nStart;
 275            pC2->Y()=nStart;
 276        }
 277    }
 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;
 292    }
 293    rSin=sn;
 294    rCos=cs;
 295    return nWink;
 296}
 297
 298double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
 299                          const Point& rRad, double& rSin, double& rCos, bool bVert,
 300                          const Rectangle rRefRect)
 301{
 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;
 314}
 315
 316////////////////////////////////////////////////////////////////////////////////////////////////////
 317
 318void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
 319{
 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];
 331        }
 332        i++;
 333        if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
 334            pC2=&rPoly[i];
 335            i++;
 336        }
 337        CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
 338    }
 339}
 340
 341void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
 342{
 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];
 354        }
 355        i++;
 356        if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
 357            pC2=&rPoly[i];
 358            i++;
 359        }
 360        CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
 361    }
 362}
 363
 364void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
 365{
 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];
 377        }
 378        i++;
 379        if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
 380            pC2=&rPoly[i];
 381            i++;
 382        }
 383        CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
 384    }
 385}
 386
 387////////////////////////////////////////////////////////////////////////////////////////////////////
 388
 389void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
 390{
 391    sal_uInt16 nPolyAnz=rPoly.Count();
 392    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
 393        CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
 394    }
 395}
 396
 397void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
 398{
 399    sal_uInt16 nPolyAnz=rPoly.Count();
 400    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
 401        CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
 402    }
 403}
 404
 405void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
 406{
 407    sal_uInt16 nPolyAnz=rPoly.Count();
 408    for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
 409        CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
 410    }
 411}
 412
 413////////////////////////////////////////////////////////////////////////////////////////////////////
 414
 415long GetAngle(const Point& rPnt)
 416{
 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));
 425    }
 426    return a;
 427}
 428
 429long NormAngle180(long a)
 430{
 431    while (a<18000) a+=36000;
 432    while (a>=18000) a-=36000;
 433    return a;
 434}
 435
 436long NormAngle360(long a)
 437{
 438    while (a<0) a+=36000;
 439    while (a>=36000) a-=36000;
 440    return a;
 441}
 442
 443sal_uInt16 GetAngleSector(long nWink)
 444{
 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;
 451}
 452
 453long GetLen(const Point& rPnt)
 454{
 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);
 474        }
 475    }
 476}
 477
 478////////////////////////////////////////////////////////////////////////////////////////////////////
 479
 480void GeoStat::RecalcSinCos()
 481{
 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);
 489    }
 490}
 491
 492void GeoStat::RecalcTan()
 493{
 494    if (nShearWink==0) {
 495        nTan=0.0;
 496    } else {
 497        double a=nShearWink*nPi180;
 498        nTan=tan(a);
 499    }
 500}
 501
 502////////////////////////////////////////////////////////////////////////////////////////////////////
 503
 504Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
 505{
 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;
 515}
 516
 517void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
 518{
 519    rGeo.nDrehWink=GetAngle(rPol[1]-rPol[0]);
 520    rGeo.nDrehWink=NormAngle360(rGeo.nDrehWink);
 521    // rotation successful
 522    rGeo.RecalcSinCos();
 523
 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();
 527
 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();
 532
 533
 534    long nShW=GetAngle(aPt3);
 535    nShW-=27000; // ShearWink is measured against a vertical line
 536    nShW=-nShW;  // Negieren, denn '+' ist Rechtskursivierung
 537
 538    bool bMirr=aPt3.Y()<0;
 539    if (bMirr) { // "exchange of points" when mirroring
 540        nHgt=-nHgt;
 541        nShW+=18000;
 542        aPt0=rPol[3];
 543    }
 544    nShW=NormAngle180(nShW);
 545    if (nShW<-9000 || nShW>9000) {
 546        nShW=NormAngle180(nShW+18000);
 547    }
 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);
 556}
 557
 558////////////////////////////////////////////////////////////////////////////////////////////////////
 559
 560void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
 561{
 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) );
 573    }
 574}
 575
 576void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
 577{
 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) );
 586    }
 587}
 588
 589////////////////////////////////////////////////////////////////////////////////////////////////////
 590
 591long BigMulDiv(long nVal, long nMul, long nDiv)
 592{
 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
 599    }
 600    if(nDiv)
 601    {
 602        aVal/=nDiv;
 603        return long(aVal);
 604    }
 605    return 0x7fffffff;
 606}
 607
 608void Kuerzen(Fraction& rF, unsigned nDigits)
 609{
 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;
 635    }
 636    if (bNeg) nMul=-nMul;
 637    rF=Fraction(nMul,nDiv);
 638}
 639
 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)
 643
 644FrPair GetInchOrMM(MapUnit eU)
 645{
 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());
 662        }
 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());
 670        }
 671        default: break;
 672    }
 673    return Fraction(1,1);
 674}
 675
 676FrPair GetInchOrMM(FieldUnit eU)
 677{
 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;
 691    }
 692    return Fraction(1,1);
 693}
 694
 695// Calculate the factor that we need to convert units from eS to eD.
 696// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
 697
 698FrPair GetMapFactor(MapUnit eS, MapUnit eD)
 699{
 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;
 709};
 710
 711FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
 712{
 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;
 722};
 723
 724////////////////////////////////////////////////////////////////////////////////////////////////////
 725
 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
 732
 733void GetMeterOrInch(MapUnit eMU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
 734{
 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;
 761}
 762
 763void GetMeterOrInch(FieldUnit eFU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
 764{
 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;
 793}
 794
 795void SdrFormatter::Undirty()
 796{
 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);
 806    }
 807    if (!bDstFU) {
 808        GetMeterOrInch(eDstMU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
 809    } else {
 810        GetMeterOrInch(eDstFU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
 811    }
 812    nMul1*=nDiv2;
 813    nDiv1*=nMul2;
 814    nKomma1=nKomma1-nKomma2;
 815
 816    if (bSrcInch && bDstMetr) {
 817        nKomma1+=4;
 818        nMul1*=254;
 819    }
 820    if (bSrcMetr && bDstInch) {
 821        nKomma1-=4;
 822        nDiv1*=254;
 823    }
 824
 825    // temporary fraction for canceling
 826    Fraction aTempFract(nMul1,nDiv1);
 827    nMul1=aTempFract.GetNumerator();
 828    nDiv1=aTempFract.GetDenominator();
 829
 830    nMul_=nMul1;
 831    nDiv_=nDiv1;
 832    nKomma_=nKomma1;
 833    bDirty=sal_False;
 834}
 835
 836
 837void SdrFormatter::TakeStr(long nVal, XubString& rStr) const
 838{
 839    sal_Unicode aNullCode('0');
 840
 841    if(!nVal)
 842    {
 843        rStr = UniString();
 844        rStr += aNullCode;
 845        return;
 846    }
 847
 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();
 852
 853    ForceUndirty();
 854
 855    sal_Int16 nK(nKomma_);
 856    XubString aStr;
 857
 858    if(bNeg)
 859        nVal = -nVal;
 860
 861    while(nK <= -3)
 862    {
 863        nVal *= 1000;
 864        nK += 3;
 865    }
 866
 867    while(nK <= -1)
 868    {
 869        nVal *= 10;
 870        nK++;
 871    }
 872
 873    if(nMul_ != nDiv_)
 874        nVal = BigMulDiv(nVal, nMul_, nDiv_);
 875
 876    aStr = UniString::CreateFromInt32(nVal);
 877
 878    if(nK > 0 && aStr.Len() <= nK )
 879    {
 880        // decimal separator necessary
 881        sal_Int16 nAnz(nK - aStr.Len());
 882
 883        if(nAnz >= 0 && rLoc.isNumLeadingZero())
 884            nAnz++;
 885
 886        for(xub_StrLen  i=0; i<nAnz; i++)
 887            aStr.Insert(aNullCode, 0);
 888
 889        // remove superfluous decimal points
 890        xub_StrLen nNumDigits(rLoc.getNumDigits());
 891        xub_StrLen nWeg(nK - nNumDigits);
 892
 893        if(nWeg > 0)
 894        {
 895            // TODO: we should round here
 896            aStr.Erase(aStr.Len() - nWeg);
 897            nK = nNumDigits;
 898        }
 899    }
 900
 901    // remember everything before the decimal separator for later
 902    xub_StrLen nVorKomma(aStr.Len() - nK);
 903
 904    if(nK > 0)
 905    {
 906        // insert KommaChar (decimal separator)
 907        // remove trailing zeros
 908        while(nK > 0 && aStr.GetChar(aStr.Len() - 1) == aNullCode)
 909        {
 910            aStr.Erase(aStr.Len() - 1);
 911            nK--;
 912        }
 913
 914        if(nK > 0)
 915        {
 916            // do we still have decimal places?
 917            sal_Unicode cDec(rLoc.getNumDecimalSep().GetChar(0));
 918            aStr.Insert(cDec, nVorKomma);
 919        }
 920    }
 921
 922    // add in thousands separator (if necessary)
 923    if( nVorKomma > 3 )
 924    {
 925        String aThoSep( rLoc.getNumThousandSep() );
 926        if ( aThoSep.Len() > 0 )
 927        {
 928            sal_Unicode cTho( aThoSep.GetChar(0) );
 929            sal_Int32 i(nVorKomma - 3);
 930
 931            while(i > 0)
 932            {
 933                rStr.Insert(cTho, (xub_StrLen)i);
 934                i -= 3;
 935            }
 936        }
 937    }
 938
 939    if(!aStr.Len())
 940        aStr += aNullCode;
 941
 942    if(bNeg && (aStr.Len() > 1 || aStr.GetChar(0) != aNullCode))
 943    {
 944        rStr.Insert(sal_Unicode('-'), 0);
 945    }
 946
 947    rStr = aStr;
 948}
 949
 950void SdrFormatter::TakeUnitStr(MapUnit eUnit, XubString& rStr)
 951{
 952    switch(eUnit)
 953    {
 954        // metrically
 955        case MAP_100TH_MM   :
 956        {
 957            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
 958            break;
 959        }
 960        case MAP_10TH_MM    :
 961        {
 962            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10mm"));
 963            break;
 964        }
 965        case MAP_MM         :
 966        {
 967            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
 968            break;
 969        }
 970        case MAP_CM         :
 971        {
 972            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
 973            break;
 974        }
 975
 976        // Inch
 977        case MAP_1000TH_INCH:
 978        {
 979            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/1000\""));
 980            break;
 981        }
 982        case MAP_100TH_INCH :
 983        {
 984            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100\""));
 985            break;
 986        }
 987        case MAP_10TH_INCH  :
 988        {
 989            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10\""));
 990            break;
 991        }
 992        case MAP_INCH       :
 993        {
 994            rStr = UniString();
 995            rStr += sal_Unicode('"');
 996            break;
 997        }
 998        case MAP_POINT      :
 999        {
1000            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
1001            break;
1002        }
1003        case MAP_TWIP       :
1004        {
1005            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
1006            break;
1007        }
1008
1009        // others
1010        case MAP_PIXEL      :
1011        {
1012            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pixel"));
1013            break;
1014        }
1015        case MAP_SYSFONT    :
1016        {
1017            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("sysfont"));
1018            break;
1019        }
1020        case MAP_APPFONT    :
1021        {
1022            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("appfont"));
1023            break;
1024        }
1025        case MAP_RELATIVE   :
1026        {
1027            rStr = UniString();
1028            rStr += sal_Unicode('%');
1029            break;
1030        }
1031        default: break;
1032    }
1033}
1034
1035void SdrFormatter::TakeUnitStr(FieldUnit eUnit, XubString& rStr)
1036{
1037    switch(eUnit)
1038    {
1039        default             :
1040        case FUNIT_NONE     :
1041        case FUNIT_CUSTOM   :
1042        {
1043            rStr = UniString();
1044            break;
1045        }
1046
1047        // metrically
1048        case FUNIT_100TH_MM:
1049        {
1050            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
1051            break;
1052        }
1053        case FUNIT_MM     :
1054        {
1055            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
1056            break;
1057        }
1058        case FUNIT_CM     :
1059        {
1060            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
1061            break;
1062        }
1063        case FUNIT_M      :
1064        {
1065            rStr = UniString();
1066            rStr += sal_Unicode('m');
1067            break;
1068        }
1069        case FUNIT_KM     :
1070        {
1071            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("km"));
1072            break;
1073        }
1074
1075        // Inch
1076        case FUNIT_TWIP   :
1077        {
1078            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
1079            break;
1080        }
1081        case FUNIT_POINT  :
1082        {
1083            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
1084            break;
1085        }
1086        case FUNIT_PICA   :
1087        {
1088            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pica"));
1089            break;
1090        }
1091        case FUNIT_INCH   :
1092        {
1093            rStr = UniString();
1094            rStr += sal_Unicode('"');
1095            break;
1096        }
1097        case FUNIT_FOOT   :
1098        {
1099            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("ft"));
1100            break;
1101        }
1102        case FUNIT_MILE   :
1103        {
1104            rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mile(s)"));
1105            break;
1106        }
1107
1108        // others
1109        case FUNIT_PERCENT:
1110        {
1111            rStr = UniString();
1112            rStr += sal_Unicode('%');
1113            break;
1114        }
1115    }
1116}
1117
1118////////////////////////////////////////////////////////////////////////////////////////////////////
1119
1120
1121/* vim:set shiftwidth=4 softtabstop=4 expandtab: */