diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/svdraw/svdtrans.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | svx/source/svdraw/svdtrans.cxx | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdtrans.cxx b/svx/source/svdraw/svdtrans.cxx new file mode 100644 index 000000000..201e9f86d --- /dev/null +++ b/svx/source/svdraw/svdtrans.cxx @@ -0,0 +1,867 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <svx/svdtrans.hxx> +#include <math.h> +#include <svx/xpoly.hxx> +#include <rtl/ustrbuf.hxx> + +#include <vcl/virdev.hxx> +#include <tools/bigint.hxx> +#include <tools/UnitConversion.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/localedatawrapper.hxx> +#include <sal/log.hxx> + +void MoveXPoly(XPolygon& rPoly, const Size& S) +{ + rPoly.Move(S.Width(),S.Height()); +} + +void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact) +{ + Fraction aXFact(rxFact); + Fraction aYFact(ryFact); + + if (!aXFact.IsValid()) { + SAL_WARN( "svx.svdraw", "invalid fraction xFract, using Fraction(1,1)" ); + aXFact = Fraction(1,1); + tools::Long nWdt = rRect.Right() - rRect.Left(); + if (nWdt == 0) rRect.AdjustRight( 1 ); + } + rRect.SetLeft( rRef.X() + FRound( (rRect.Left() - rRef.X()) * double(aXFact) ) ); + rRect.SetRight( rRef.X() + FRound( (rRect.Right() - rRef.X()) * double(aXFact) ) ); + + if (!aYFact.IsValid()) { + SAL_WARN( "svx.svdraw", "invalid fraction yFract, using Fraction(1,1)" ); + aYFact = Fraction(1,1); + tools::Long nHgt = rRect.Bottom() - rRect.Top(); + if (nHgt == 0) rRect.AdjustBottom( 1 ); + } + rRect.SetTop( rRef.Y() + FRound( (rRect.Top() - rRef.Y()) * double(aYFact) ) ); + rRect.SetBottom( rRef.Y() + FRound( (rRect.Bottom() - rRef.Y()) * double(aYFact) ) ); + + rRect.Justify(); +} + + +void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact) +{ + sal_uInt16 nCount=rPoly.GetSize(); + for (sal_uInt16 i=0; i<nCount; i++) { + ResizePoint(rPoly[i],rRef,xFact,yFact); + } +} + +void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact) +{ + sal_uInt16 nCount=rPoly.GetPointCount(); + for (sal_uInt16 i=0; i<nCount; i++) { + ResizePoint(rPoly[i],rRef,xFact,yFact); + } +} + +void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs) +{ + sal_uInt16 nCount=rPoly.GetSize(); + for (sal_uInt16 i=0; i<nCount; i++) { + RotatePoint(rPoly[i],rRef,sn,cs); + } +} + +void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs) +{ + sal_uInt16 nCount=rPoly.GetPointCount(); + for (sal_uInt16 i=0; i<nCount; i++) { + RotatePoint(rPoly[i],rRef,sn,cs); + } +} + +void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs) +{ + sal_uInt16 nCount=rPoly.Count(); + for (sal_uInt16 i=0; i<nCount; i++) { + RotateXPoly(rPoly[i],rRef,sn,cs); + } +} + +void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2) +{ + tools::Long mx=rRef2.X()-rRef1.X(); + tools::Long my=rRef2.Y()-rRef1.Y(); + if (mx==0) { // vertical axis + tools::Long dx=rRef1.X()-rPnt.X(); + rPnt.AdjustX(2*dx ); + } else if (my==0) { // horizontal axis + tools::Long dy=rRef1.Y()-rPnt.Y(); + rPnt.AdjustY(2*dy ); + } else if (mx==my) { // diagonal axis '\' + tools::Long dx1=rPnt.X()-rRef1.X(); + tools::Long dy1=rPnt.Y()-rRef1.Y(); + rPnt.setX(rRef1.X()+dy1 ); + rPnt.setY(rRef1.Y()+dx1 ); + } else if (mx==-my) { // diagonal axis '/' + tools::Long dx1=rPnt.X()-rRef1.X(); + tools::Long dy1=rPnt.Y()-rRef1.Y(); + rPnt.setX(rRef1.X()-dy1 ); + rPnt.setY(rRef1.Y()-dx1 ); + } else { // arbitrary axis + // TODO: Optimize this! Raise perpendicular on the mirroring axis..? + Degree100 nRefAngle=GetAngle(rRef2-rRef1); + rPnt-=rRef1; + Degree100 nPntAngle=GetAngle(rPnt); + Degree100 nAngle=2_deg100*(nRefAngle-nPntAngle); + double a = toRadians(nAngle); + double nSin=sin(a); + double nCos=cos(a); + RotatePoint(rPnt,Point(),nSin,nCos); + rPnt+=rRef1; + } +} + +void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2) +{ + sal_uInt16 nCount=rPoly.GetPointCount(); + for (sal_uInt16 i=0; i<nCount; i++) { + MirrorPoint(rPoly[i],rRef1,rRef2); + } +} + +void ShearPoly(tools::Polygon& rPoly, const Point& rRef, double tn) +{ + sal_uInt16 nCount=rPoly.GetSize(); + for (sal_uInt16 i=0; i<nCount; i++) { + ShearPoint(rPoly[i],rRef,tn); + } +} + +void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear) +{ + sal_uInt16 nCount=rPoly.GetPointCount(); + for (sal_uInt16 i=0; i<nCount; i++) { + ShearPoint(rPoly[i],rRef,tn,bVShear); + } +} + +double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter, + const Point& rRad, double& rSin, double& rCos, bool bVert) +{ + bool bC1=pC1!=nullptr; + bool bC2=pC2!=nullptr; + tools::Long x0=rPnt.X(); + tools::Long y0=rPnt.Y(); + tools::Long cx=rCenter.X(); + tools::Long cy=rCenter.Y(); + double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert); + double sn=sin(nAngle); + double cs=cos(nAngle); + RotatePoint(rPnt,rCenter,sn,cs); + if (bC1) { + if (bVert) { + // move into the direction of the center, as a basic position for the rotation + pC1->AdjustY( -y0 ); + // resize, account for the distance from the center + pC1->setY(FRound(static_cast<double>(pC1->Y()) /rRad.X()*(cx-pC1->X())) ); + pC1->AdjustY(cy ); + } else { + // move into the direction of the center, as a basic position for the rotation + pC1->AdjustX( -x0 ); + // resize, account for the distance from the center + tools::Long nPntRad=cy-pC1->Y(); + double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y()); + pC1->setX(FRound(static_cast<double>(pC1->X())*nFact) ); + pC1->AdjustX(cx ); + } + RotatePoint(*pC1,rCenter,sn,cs); + } + if (bC2) { + if (bVert) { + // move into the direction of the center, as a basic position for the rotation + pC2->AdjustY( -y0 ); + // resize, account for the distance from the center + pC2->setY(FRound(static_cast<double>(pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X())) ); + pC2->AdjustY(cy ); + } else { + // move into the direction of the center, as a basic position for the rotation + pC2->AdjustX( -x0 ); + // resize, account for the distance from the center + tools::Long nPntRad=rCenter.Y()-pC2->Y(); + double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y()); + pC2->setX(FRound(static_cast<double>(pC2->X())*nFact) ); + pC2->AdjustX(cx ); + } + RotatePoint(*pC2,rCenter,sn,cs); + } + rSin=sn; + rCos=cs; + return nAngle; +} + +double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter, + const Point& rRad, double& rSin, double& rCos, bool bVert) +{ + bool bC1=pC1!=nullptr; + bool bC2=pC2!=nullptr; + tools::Long x0=rPnt.X(); + tools::Long y0=rPnt.Y(); + tools::Long dx1=0,dy1=0; + tools::Long dxC1=0,dyC1=0; + tools::Long dxC2=0,dyC2=0; + if (bVert) { + tools::Long nStart=rCenter.X()-rRad.X(); + dx1=rPnt.X()-nStart; + rPnt.setX(nStart ); + if (bC1) { + dxC1=pC1->X()-nStart; + pC1->setX(nStart ); + } + if (bC2) { + dxC2=pC2->X()-nStart; + pC2->setX(nStart ); + } + } else { + tools::Long nStart=rCenter.Y()-rRad.Y(); + dy1=rPnt.Y()-nStart; + rPnt.setY(nStart ); + if (bC1) { + dyC1=pC1->Y()-nStart; + pC1->setY(nStart ); + } + if (bC2) { + dyC2=pC2->Y()-nStart; + pC2->setY(nStart ); + } + } + double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert); + double sn=sin(nAngle); + double cs=cos(nAngle); + RotatePoint(rPnt,rCenter,sn,cs); + if (bC1) { if (bVert) pC1->AdjustY( -(y0-rCenter.Y()) ); else pC1->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC1,rCenter,sn,cs); } + if (bC2) { if (bVert) pC2->AdjustY( -(y0-rCenter.Y()) ); else pC2->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC2,rCenter,sn,cs); } + if (bVert) { + rPnt.AdjustX(dx1 ); + if (bC1) pC1->AdjustX(dxC1 ); + if (bC2) pC2->AdjustX(dxC2 ); + } else { + rPnt.AdjustY(dy1 ); + if (bC1) pC1->AdjustY(dyC1 ); + if (bC2) pC2->AdjustY(dyC2 ); + } + rSin=sn; + rCos=cs; + return nAngle; +} + +double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter, + const Point& rRad, double& rSin, double& rCos, bool bVert, + const tools::Rectangle& rRefRect) +{ + tools::Long y0=rPnt.Y(); + CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert); + if (bVert) { + } else { + tools::Long nTop=rRefRect.Top(); + tools::Long nBtm=rRefRect.Bottom(); + tools::Long nHgt=nBtm-nTop; + tools::Long dy=rPnt.Y()-y0; + double a=static_cast<double>(y0-nTop)/nHgt; + a*=dy; + rPnt.setY(y0+FRound(a) ); + } + return 0.0; +} + + +void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert) +{ + double nSin,nCos; + sal_uInt16 nPointCnt=rPoly.GetPointCount(); + sal_uInt16 i=0; + while (i<nPointCnt) { + Point* pPnt=&rPoly[i]; + Point* pC1=nullptr; + Point* pC2=nullptr; + if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left + pC1=pPnt; + i++; + pPnt=&rPoly[i]; + } + i++; + if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right + pC2=&rPoly[i]; + i++; + } + CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert); + } +} + +void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert) +{ + double nSin,nCos; + sal_uInt16 nPointCnt=rPoly.GetPointCount(); + sal_uInt16 i=0; + while (i<nPointCnt) { + Point* pPnt=&rPoly[i]; + Point* pC1=nullptr; + Point* pC2=nullptr; + if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left + pC1=pPnt; + i++; + pPnt=&rPoly[i]; + } + i++; + if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right + pC2=&rPoly[i]; + i++; + } + CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert); + } +} + +void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect) +{ + double nSin,nCos; + sal_uInt16 nPointCnt=rPoly.GetPointCount(); + sal_uInt16 i=0; + while (i<nPointCnt) { + Point* pPnt=&rPoly[i]; + Point* pC1=nullptr; + Point* pC2=nullptr; + if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left + pC1=pPnt; + i++; + pPnt=&rPoly[i]; + } + i++; + if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right + pC2=&rPoly[i]; + i++; + } + CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect); + } +} + + +void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert) +{ + sal_uInt16 nPolyCount=rPoly.Count(); + for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) { + CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert); + } +} + +void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert) +{ + sal_uInt16 nPolyCount=rPoly.Count(); + for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) { + CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert); + } +} + +void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect) +{ + sal_uInt16 nPolyCount=rPoly.Count(); + for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) { + CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect); + } +} + + +Degree100 GetAngle(const Point& rPnt) +{ + Degree100 a; + if (rPnt.Y()==0) { + if (rPnt.X()<0) a=-18000_deg100; + } else if (rPnt.X()==0) { + if (rPnt.Y()>0) a=-9000_deg100; + else a=9000_deg100; + } else { + a = Degree100(FRound(basegfx::rad2deg<100>(atan2(static_cast<double>(-rPnt.Y()), static_cast<double>(rPnt.X()))))); + } + return a; +} + +Degree100 NormAngle18000(Degree100 a) +{ + while (a<-18000_deg100) a+=36000_deg100; + while (a>=18000_deg100) a-=36000_deg100; + return a; +} + +Degree100 NormAngle36000(Degree100 a) +{ + a %= 36000_deg100; + if (a < 0_deg100) + a += 36000_deg100; + return a; +} + +sal_uInt16 GetAngleSector(Degree100 nAngle) { return (NormAngle36000(nAngle) / 9000_deg100).get(); } + +tools::Long GetLen(const Point& rPnt) +{ + tools::Long x=std::abs(rPnt.X()); + tools::Long y=std::abs(rPnt.Y()); + if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002 + x*=x; + y*=y; + x+=y; + x=FRound(sqrt(static_cast<double>(x))); + return x; + } else { + double nx=x; + double ny=y; + nx*=nx; + ny*=ny; + nx+=ny; + nx=sqrt(nx); + if (nx>0x7FFFFFFF) { + return 0x7FFFFFFF; // we can't go any further, for fear of an overrun! + } else { + return FRound(nx); + } + } +} + + +void GeoStat::RecalcSinCos() +{ + if (nRotationAngle==0_deg100) { + mfSinRotationAngle=0.0; + mfCosRotationAngle=1.0; + } else { + double a = toRadians(nRotationAngle); + mfSinRotationAngle=sin(a); + mfCosRotationAngle=cos(a); + } +} + +void GeoStat::RecalcTan() +{ + if (nShearAngle==0_deg100) { + mfTanShearAngle=0.0; + } else { + double a = toRadians(nShearAngle); + mfTanShearAngle=tan(a); + } +} + + +tools::Polygon Rect2Poly(const tools::Rectangle& rRect, const GeoStat& rGeo) +{ + tools::Polygon aPol(5); + aPol[0]=rRect.TopLeft(); + aPol[1]=rRect.TopRight(); + aPol[2]=rRect.BottomRight(); + aPol[3]=rRect.BottomLeft(); + aPol[4]=rRect.TopLeft(); + if (rGeo.nShearAngle) ShearPoly(aPol,rRect.TopLeft(),rGeo.mfTanShearAngle); + if (rGeo.nRotationAngle) RotatePoly(aPol,rRect.TopLeft(),rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); + return aPol; +} + +void Poly2Rect(const tools::Polygon& rPol, tools::Rectangle& rRect, GeoStat& rGeo) +{ + rGeo.nRotationAngle=GetAngle(rPol[1]-rPol[0]); + rGeo.nRotationAngle=NormAngle36000(rGeo.nRotationAngle); + // rotation successful + rGeo.RecalcSinCos(); + + Point aPt1(rPol[1]-rPol[0]); + if (rGeo.nRotationAngle) RotatePoint(aPt1,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation + tools::Long nWdt=aPt1.X(); + + Point aPt0(rPol[0]); + Point aPt3(rPol[3]-rPol[0]); + if (rGeo.nRotationAngle) RotatePoint(aPt3,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation + tools::Long nHgt=aPt3.Y(); + + + Degree100 nShW=GetAngle(aPt3); + nShW-=27000_deg100; // ShearWink is measured against a vertical line + nShW=-nShW; // negating, because '+' is shearing clock-wise + + bool bMirr=aPt3.Y()<0; + if (bMirr) { // "exchange of points" when mirroring + nHgt=-nHgt; + nShW+=18000_deg100; + aPt0=rPol[3]; + } + nShW=NormAngle18000(nShW); + if (nShW<-9000_deg100 || nShW>9000_deg100) { + nShW=NormAngle18000(nShW+18000_deg100); + } + if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg + if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR; + rGeo.nShearAngle=nShW; + rGeo.RecalcTan(); + Point aRU(aPt0); + aRU.AdjustX(nWdt ); + aRU.AdjustY(nHgt ); + rRect=tools::Rectangle(aPt0,aRU); +} + + +void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho) +{ + tools::Long dx=rPt.X()-rPt0.X(); + tools::Long dy=rPt.Y()-rPt0.Y(); + tools::Long dxa=std::abs(dx); + tools::Long dya=std::abs(dy); + if (dx==0 || dy==0 || dxa==dya) return; + if (dxa>=dya*2) { rPt.setY(rPt0.Y() ); return; } + if (dya>=dxa*2) { rPt.setX(rPt0.X() ); return; } + if ((dxa<dya) != bBigOrtho) { + rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) ); + } else { + rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) ); + } +} + +void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho) +{ + tools::Long dx=rPt.X()-rPt0.X(); + tools::Long dy=rPt.Y()-rPt0.Y(); + tools::Long dxa=std::abs(dx); + tools::Long dya=std::abs(dy); + if ((dxa<dya) != bBigOrtho) { + rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) ); + } else { + rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) ); + } +} + + +tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv) +{ + if (!nDiv) + return 0x7fffffff; + return BigInt::Scale(nVal, nMul, nDiv); +} + +static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo) +{ + const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo); + return FrPair(nNum, nDen); +} + +// How many eU units fit into a mm, respectively an inch? +// Or: How many mm, respectively inches, are there in an eU (and then give me the inverse) + +static FrPair GetInchOrMM(MapUnit eU) +{ + switch (eU) { + case MapUnit::Map1000thInch: return toPair(o3tl::Length::in, o3tl::Length::in1000); + case MapUnit::Map100thInch : return toPair(o3tl::Length::in, o3tl::Length::in100); + case MapUnit::Map10thInch : return toPair(o3tl::Length::in, o3tl::Length::in10); + case MapUnit::MapInch : return toPair(o3tl::Length::in, o3tl::Length::in); + case MapUnit::MapPoint : return toPair(o3tl::Length::in, o3tl::Length::pt); + case MapUnit::MapTwip : return toPair(o3tl::Length::in, o3tl::Length::twip); + case MapUnit::Map100thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm100); + case MapUnit::Map10thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm10); + case MapUnit::MapMM : return toPair(o3tl::Length::mm, o3tl::Length::mm); + case MapUnit::MapCM : return toPair(o3tl::Length::mm, o3tl::Length::cm); + case MapUnit::MapPixel : { + ScopedVclPtrInstance< VirtualDevice > pVD; + pVD->SetMapMode(MapMode(MapUnit::Map100thMM)); + Point aP(pVD->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy + return FrPair(6400,aP.X(),6400,aP.Y()); + } + case MapUnit::MapAppFont: case MapUnit::MapSysFont: { + ScopedVclPtrInstance< VirtualDevice > pVD; + pVD->SetMapMode(MapMode(eU)); + Point aP(pVD->LogicToPixel(Point(32,32))); // 32 units for more accuracy + pVD->SetMapMode(MapMode(MapUnit::Map100thMM)); + aP=pVD->PixelToLogic(aP); + return FrPair(3200,aP.X(),3200,aP.Y()); + } + default: break; + } + return Fraction(1,1); +} + +// Calculate the factor that we need to convert units from eS to eD. +// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100. + +FrPair GetMapFactor(MapUnit eS, MapUnit eD) +{ + if (eS==eD) return FrPair(1,1,1,1); + const auto eFrom = MapToO3tlLength(eS, o3tl::Length::invalid); + const auto eTo = MapToO3tlLength(eD, o3tl::Length::invalid); + if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid) + return toPair(eFrom, eTo); + FrPair aS(GetInchOrMM(eS)); + FrPair aD(GetInchOrMM(eD)); + bool bSInch=IsInch(eS); + bool bDInch=IsInch(eD); + FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y()); + if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); } + if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); } + return aRet; +}; + +FrPair GetMapFactor(FieldUnit eS, FieldUnit eD) +{ + if (eS==eD) return FrPair(1,1,1,1); + auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD); + if (eFrom == o3tl::Length::invalid) + { + if (eTo == o3tl::Length::invalid) + return FrPair(1,1,1,1); + eFrom = IsInch(eD) ? o3tl::Length::in : o3tl::Length::mm; + } + else if (eTo == o3tl::Length::invalid) + eTo = IsInch(eS) ? o3tl::Length::in : o3tl::Length::mm; + return toPair(eFrom, eTo); +}; + +void SdrFormatter::Undirty() +{ + const o3tl::Length eFrom = MapToO3tlLength(eSrcMU, o3tl::Length::invalid); + const o3tl::Length eTo = MapToO3tlLength(eDstMU, o3tl::Length::invalid); + if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid) + { + const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo); + sal_Int64 nMul = mul; + sal_Int64 nDiv = div; + short nComma = 0; + + // shorten trailing zeros for dividend + while (0 == (nMul % 10)) + { + nComma--; + nMul /= 10; + } + + // shorten trailing zeros for divisor + while (0 == (nDiv % 10)) + { + nComma++; + nDiv /= 10; + } + nMul_ = nMul; + nDiv_ = nDiv; + nComma_ = nComma; + } + else + { + nMul_ = nDiv_ = 1; + nComma_ = 0; + } + bDirty=false; +} + + +OUString SdrFormatter::GetStr(tools::Long nVal) const +{ + const OUString aNullCode("0"); + + if(!nVal) + { + return aNullCode; + } + + // we may lose some decimal places here, because of MulDiv instead of Real + bool bNeg(nVal < 0); + SvtSysLocale aSysLoc; + const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData(); + + if (bDirty) + const_cast<SdrFormatter*>(this)->Undirty(); + + sal_Int16 nC(nComma_); + + if(bNeg) + nVal = -nVal; + + while(nC <= -3) + { + nVal *= 1000; + nC += 3; + } + + while(nC <= -1) + { + nVal *= 10; + nC++; + } + + if(nMul_ != nDiv_) + nVal = BigMulDiv(nVal, nMul_, nDiv_); + + OUStringBuffer aStr = OUString::number(nVal); + + if(nC > 0 && aStr.getLength() <= nC ) + { + // decimal separator necessary + sal_Int32 nCount(nC - aStr.getLength()); + + if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero()) + nCount++; + + for(sal_Int32 i=0; i<nCount; i++) + aStr.insert(0, aNullCode); + + // remove superfluous decimal points + sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits()); + sal_Int32 nWeg(nC - nNumDigits); + + if(nWeg > 0) + { + // TODO: we should round here + aStr.remove(aStr.getLength() - nWeg, nWeg); + nC = nNumDigits; + } + } + + // remember everything before the decimal separator for later + sal_Int32 nForComma(aStr.getLength() - nC); + + if(nC > 0) + { + // insert comma char (decimal separator) + // remove trailing zeros + while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode[0]) + { + aStr.remove(aStr.getLength() - 1, 1); + nC--; + } + + if(nC > 0) + { + // do we still have decimal places? + sal_Unicode cDec(rLoc.getNumDecimalSep()[0]); + aStr.insert(nForComma, cDec); + } + } + + // add in thousands separator (if necessary) + if( nForComma > 3 ) + { + const OUString& aThoSep( rLoc.getNumThousandSep() ); + if ( aThoSep.getLength() > 0 ) + { + sal_Unicode cTho( aThoSep[0] ); + sal_Int32 i(nForComma - 3); + + while(i > 0) + { + aStr.insert(i, cTho); + i -= 3; + } + } + } + + if(aStr.isEmpty()) + aStr.append(aNullCode); + + if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode[0])) + { + aStr.insert(0, "-"); + } + + return aStr.makeStringAndClear(); +} + +OUString SdrFormatter::GetUnitStr(MapUnit eUnit) +{ + switch(eUnit) + { + // metrically + case MapUnit::Map100thMM : + return "/100mm"; + case MapUnit::Map10thMM : + return "/10mm"; + case MapUnit::MapMM : + return "mm"; + case MapUnit::MapCM : + return "cm"; + + // Inch + case MapUnit::Map1000thInch: + return "/1000\""; + case MapUnit::Map100thInch : + return "/100\""; + case MapUnit::Map10thInch : + return "/10\""; + case MapUnit::MapInch : + return "\""; + case MapUnit::MapPoint : + return "pt"; + case MapUnit::MapTwip : + return "twip"; + + // others + case MapUnit::MapPixel : + return "pixel"; + case MapUnit::MapSysFont : + return "sysfont"; + case MapUnit::MapAppFont : + return "appfont"; + case MapUnit::MapRelative : + return "%"; + default: + return OUString(); + } +} + +OUString SdrFormatter::GetUnitStr(FieldUnit eUnit) +{ + switch(eUnit) + { + default : + case FieldUnit::NONE : + case FieldUnit::CUSTOM : + return OUString(); + + // metrically + case FieldUnit::MM_100TH: + return "/100mm"; + case FieldUnit::MM : + return "mm"; + case FieldUnit::CM : + return "cm"; + case FieldUnit::M : + return "m"; + case FieldUnit::KM : + return "km"; + + // Inch + case FieldUnit::TWIP : + return "twip"; + case FieldUnit::POINT : + return "pt"; + case FieldUnit::PICA : + return "pica"; + case FieldUnit::INCH : + return "\""; + case FieldUnit::FOOT : + return "ft"; + case FieldUnit::MILE : + return "mile(s)"; + + // others + case FieldUnit::PERCENT: + return "%"; + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |