PageRenderTime 75ms CodeModel.GetById 40ms RepoModel.GetById 0ms 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
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, AGPL-1.0, BSD-3-Clause-No-Nuclear-License-2014, GPL-3.0, LGPL-3.0
  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. #include <svx/svdtrans.hxx>
  29. #include <math.h>
  30. #include <svx/xpoly.hxx>
  31. #include <vcl/virdev.hxx>
  32. #include <tools/bigint.hxx>
  33. #include <tools/debug.hxx>
  34. #include <unotools/syslocale.hxx>
  35. void MoveXPoly(XPolygon& rPoly, const Size& S)
  36. {
  37. rPoly.Move(S.Width(),S.Height());
  38. }
  39. void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact, bool bNoJustify)
  40. {
  41. Fraction xFact(rxFact);
  42. Fraction yFact(ryFact);
  43. {
  44. if (xFact.GetDenominator()==0) {
  45. long nWdt=rRect.Right()-rRect.Left();
  46. if (xFact.GetNumerator()>=0) { // catch divisions by zero
  47. xFact=Fraction(xFact.GetNumerator(),1);
  48. if (nWdt==0) rRect.Right()++;
  49. } else {
  50. xFact=Fraction(xFact.GetNumerator(),-1);
  51. if (nWdt==0) rRect.Left()--;
  52. }
  53. }
  54. rRect.Left() =rRef.X()+Round(((double)(rRect.Left() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
  55. rRect.Right() =rRef.X()+Round(((double)(rRect.Right() -rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
  56. }
  57. {
  58. if (yFact.GetDenominator()==0) {
  59. long nHgt=rRect.Bottom()-rRect.Top();
  60. if (yFact.GetNumerator()>=0) { // catch divisions by zero
  61. yFact=Fraction(yFact.GetNumerator(),1);
  62. if (nHgt==0) rRect.Bottom()++;
  63. } else {
  64. yFact=Fraction(yFact.GetNumerator(),-1);
  65. if (nHgt==0) rRect.Top()--;
  66. }
  67. yFact=Fraction(yFact.GetNumerator(),1); // catch divisions by zero
  68. }
  69. rRect.Top() =rRef.Y()+Round(((double)(rRect.Top() -rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
  70. rRect.Bottom()=rRef.Y()+Round(((double)(rRect.Bottom()-rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
  71. }
  72. if (!bNoJustify) rRect.Justify();
  73. }
  74. void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
  75. {
  76. sal_uInt16 nAnz=rPoly.GetSize();
  77. for (sal_uInt16 i=0; i<nAnz; i++) {
  78. ResizePoint(rPoly[i],rRef,xFact,yFact);
  79. }
  80. }
  81. void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
  82. {
  83. sal_uInt16 nAnz=rPoly.GetPointCount();
  84. for (sal_uInt16 i=0; i<nAnz; i++) {
  85. ResizePoint(rPoly[i],rRef,xFact,yFact);
  86. }
  87. }
  88. void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs)
  89. {
  90. sal_uInt16 nAnz=rPoly.GetSize();
  91. for (sal_uInt16 i=0; i<nAnz; i++) {
  92. RotatePoint(rPoly[i],rRef,sn,cs);
  93. }
  94. }
  95. void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
  96. {
  97. sal_uInt16 nAnz=rPoly.GetPointCount();
  98. for (sal_uInt16 i=0; i<nAnz; i++) {
  99. RotatePoint(rPoly[i],rRef,sn,cs);
  100. }
  101. }
  102. void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
  103. {
  104. sal_uInt16 nAnz=rPoly.Count();
  105. for (sal_uInt16 i=0; i<nAnz; i++) {
  106. RotateXPoly(rPoly[i],rRef,sn,cs);
  107. }
  108. }
  109. void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
  110. {
  111. long mx=rRef2.X()-rRef1.X();
  112. long my=rRef2.Y()-rRef1.Y();
  113. if (mx==0) { // vertical axis
  114. long dx=rRef1.X()-rPnt.X();
  115. rPnt.X()+=2*dx;
  116. } else if (my==0) { // horizontal axis
  117. long dy=rRef1.Y()-rPnt.Y();
  118. rPnt.Y()+=2*dy;
  119. } else if (mx==my) { // diagonal axis '\'
  120. long dx1=rPnt.X()-rRef1.X();
  121. long dy1=rPnt.Y()-rRef1.Y();
  122. rPnt.X()=rRef1.X()+dy1;
  123. rPnt.Y()=rRef1.Y()+dx1;
  124. } else if (mx==-my) { // diagonal axis '/'
  125. long dx1=rPnt.X()-rRef1.X();
  126. long dy1=rPnt.Y()-rRef1.Y();
  127. rPnt.X()=rRef1.X()-dy1;
  128. rPnt.Y()=rRef1.Y()-dx1;
  129. } else { // arbitrary axis
  130. // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
  131. long nRefWink=GetAngle(rRef2-rRef1);
  132. rPnt-=rRef1;
  133. long nPntWink=GetAngle(rPnt);
  134. long nWink=2*(nRefWink-nPntWink);
  135. double a=nWink*nPi180;
  136. double nSin=sin(a);
  137. double nCos=cos(a);
  138. RotatePoint(rPnt,Point(),nSin,nCos);
  139. rPnt+=rRef1;
  140. }
  141. }
  142. void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2)
  143. {
  144. sal_uInt16 nAnz=rPoly.GetSize();
  145. for (sal_uInt16 i=0; i<nAnz; i++) {
  146. MirrorPoint(rPoly[i],rRef1,rRef2);
  147. }
  148. }
  149. void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
  150. {
  151. sal_uInt16 nAnz=rPoly.GetPointCount();
  152. for (sal_uInt16 i=0; i<nAnz; i++) {
  153. MirrorPoint(rPoly[i],rRef1,rRef2);
  154. }
  155. }
  156. void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear)
  157. {
  158. sal_uInt16 nAnz=rPoly.GetSize();
  159. for (sal_uInt16 i=0; i<nAnz; i++) {
  160. ShearPoint(rPoly[i],rRef,tn,bVShear);
  161. }
  162. }
  163. void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
  164. {
  165. sal_uInt16 nAnz=rPoly.GetPointCount();
  166. for (sal_uInt16 i=0; i<nAnz; i++) {
  167. ShearPoint(rPoly[i],rRef,tn,bVShear);
  168. }
  169. }
  170. double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
  171. const Point& rRad, double& rSin, double& rCos, bool bVert)
  172. {
  173. bool bC1=pC1!=NULL;
  174. bool bC2=pC2!=NULL;
  175. long x0=rPnt.X();
  176. long y0=rPnt.Y();
  177. long cx=rCenter.X();
  178. long cy=rCenter.Y();
  179. double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
  180. double sn=sin(nWink);
  181. double cs=cos(nWink);
  182. RotatePoint(rPnt,rCenter,sn,cs);
  183. if (bC1) {
  184. if (bVert) {
  185. // move into the direction of the center, as a basic position for the rotation
  186. pC1->Y()-=y0;
  187. // resize, account for the distance from the center
  188. pC1->Y()=Round(((double)pC1->Y()) /rRad.X()*(cx-pC1->X()));
  189. pC1->Y()+=cy;
  190. } else {
  191. // move into the direction of the center, as a basic position for the rotation
  192. pC1->X()-=x0;
  193. // resize, account for the distance from the center
  194. long nPntRad=cy-pC1->Y();
  195. double nFact=(double)nPntRad/(double)rRad.Y();
  196. pC1->X()=Round((double)pC1->X()*nFact);
  197. pC1->X()+=cx;
  198. }
  199. RotatePoint(*pC1,rCenter,sn,cs);
  200. }
  201. if (bC2) {
  202. if (bVert) {
  203. // move into the direction of the center, as a basic position for the rotation
  204. pC2->Y()-=y0;
  205. // resize, account for the distance from the center
  206. pC2->Y()=Round(((double)pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X()));
  207. pC2->Y()+=cy;
  208. } else {
  209. // move into the direction of the center, as a basic position for the rotation
  210. pC2->X()-=x0;
  211. // resize, account for the distance from the center
  212. long nPntRad=rCenter.Y()-pC2->Y();
  213. double nFact=(double)nPntRad/(double)rRad.Y();
  214. pC2->X()=Round((double)pC2->X()*nFact);
  215. pC2->X()+=cx;
  216. }
  217. RotatePoint(*pC2,rCenter,sn,cs);
  218. }
  219. rSin=sn;
  220. rCos=cs;
  221. return nWink;
  222. }
  223. double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
  224. const Point& rRad, double& rSin, double& rCos, bool bVert)
  225. {
  226. bool bC1=pC1!=NULL;
  227. bool bC2=pC2!=NULL;
  228. long x0=rPnt.X();
  229. long y0=rPnt.Y();
  230. long dx1=0,dy1=0;
  231. long dxC1=0,dyC1=0;
  232. long dxC2=0,dyC2=0;
  233. if (bVert) {
  234. long nStart=rCenter.X()-rRad.X();
  235. dx1=rPnt.X()-nStart;
  236. rPnt.X()=nStart;
  237. if (bC1) {
  238. dxC1=pC1->X()-nStart;
  239. pC1->X()=nStart;
  240. }
  241. if (bC2) {
  242. dxC2=pC2->X()-nStart;
  243. pC2->X()=nStart;
  244. }
  245. } else {
  246. long nStart=rCenter.Y()-rRad.Y();
  247. dy1=rPnt.Y()-nStart;
  248. rPnt.Y()=nStart;
  249. if (bC1) {
  250. dyC1=pC1->Y()-nStart;
  251. pC1->Y()=nStart;
  252. }
  253. if (bC2) {
  254. dyC2=pC2->Y()-nStart;
  255. pC2->Y()=nStart;
  256. }
  257. }
  258. double nWink=GetCrookAngle(rPnt,rCenter,rRad,bVert);
  259. double sn=sin(nWink);
  260. double cs=cos(nWink);
  261. RotatePoint(rPnt,rCenter,sn,cs);
  262. if (bC1) { if (bVert) pC1->Y()-=y0-rCenter.Y(); else pC1->X()-=x0-rCenter.X(); RotatePoint(*pC1,rCenter,sn,cs); }
  263. if (bC2) { if (bVert) pC2->Y()-=y0-rCenter.Y(); else pC2->X()-=x0-rCenter.X(); RotatePoint(*pC2,rCenter,sn,cs); }
  264. if (bVert) {
  265. rPnt.X()+=dx1;
  266. if (bC1) pC1->X()+=dxC1;
  267. if (bC2) pC2->X()+=dxC2;
  268. } else {
  269. rPnt.Y()+=dy1;
  270. if (bC1) pC1->Y()+=dyC1;
  271. if (bC2) pC2->Y()+=dyC2;
  272. }
  273. rSin=sn;
  274. rCos=cs;
  275. return nWink;
  276. }
  277. double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
  278. const Point& rRad, double& rSin, double& rCos, bool bVert,
  279. const Rectangle rRefRect)
  280. {
  281. long y0=rPnt.Y();
  282. CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
  283. if (bVert) {
  284. } else {
  285. long nTop=rRefRect.Top();
  286. long nBtm=rRefRect.Bottom();
  287. long nHgt=nBtm-nTop;
  288. long dy=rPnt.Y()-y0;
  289. double a=((double)(y0-nTop))/nHgt;
  290. a*=dy;
  291. rPnt.Y()=y0+Round(a);
  292. } return 0.0;
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////////////////////////
  295. void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
  296. {
  297. double nSin,nCos;
  298. sal_uInt16 nPointAnz=rPoly.GetPointCount();
  299. sal_uInt16 i=0;
  300. while (i<nPointAnz) {
  301. Point* pPnt=&rPoly[i];
  302. Point* pC1=NULL;
  303. Point* pC2=NULL;
  304. if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
  305. pC1=pPnt;
  306. i++;
  307. pPnt=&rPoly[i];
  308. }
  309. i++;
  310. if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
  311. pC2=&rPoly[i];
  312. i++;
  313. }
  314. CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
  315. }
  316. }
  317. void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
  318. {
  319. double nSin,nCos;
  320. sal_uInt16 nPointAnz=rPoly.GetPointCount();
  321. sal_uInt16 i=0;
  322. while (i<nPointAnz) {
  323. Point* pPnt=&rPoly[i];
  324. Point* pC1=NULL;
  325. Point* pC2=NULL;
  326. if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
  327. pC1=pPnt;
  328. i++;
  329. pPnt=&rPoly[i];
  330. }
  331. i++;
  332. if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
  333. pC2=&rPoly[i];
  334. i++;
  335. }
  336. CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
  337. }
  338. }
  339. void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
  340. {
  341. double nSin,nCos;
  342. sal_uInt16 nPointAnz=rPoly.GetPointCount();
  343. sal_uInt16 i=0;
  344. while (i<nPointAnz) {
  345. Point* pPnt=&rPoly[i];
  346. Point* pC1=NULL;
  347. Point* pC2=NULL;
  348. if (i+1<nPointAnz && rPoly.IsControl(i)) { // control point to the left
  349. pC1=pPnt;
  350. i++;
  351. pPnt=&rPoly[i];
  352. }
  353. i++;
  354. if (i<nPointAnz && rPoly.IsControl(i)) { // control point to the right
  355. pC2=&rPoly[i];
  356. i++;
  357. }
  358. CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
  359. }
  360. }
  361. ////////////////////////////////////////////////////////////////////////////////////////////////////
  362. void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
  363. {
  364. sal_uInt16 nPolyAnz=rPoly.Count();
  365. for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
  366. CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
  367. }
  368. }
  369. void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
  370. {
  371. sal_uInt16 nPolyAnz=rPoly.Count();
  372. for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
  373. CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
  374. }
  375. }
  376. void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect)
  377. {
  378. sal_uInt16 nPolyAnz=rPoly.Count();
  379. for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyAnz; nPolyNum++) {
  380. CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
  381. }
  382. }
  383. ////////////////////////////////////////////////////////////////////////////////////////////////////
  384. long GetAngle(const Point& rPnt)
  385. {
  386. long a=0;
  387. if (rPnt.Y()==0) {
  388. if (rPnt.X()<0) a=-18000;
  389. } else if (rPnt.X()==0) {
  390. if (rPnt.Y()>0) a=-9000;
  391. else a=9000;
  392. } else {
  393. a=Round((atan2((double)-rPnt.Y(),(double)rPnt.X())/nPi180));
  394. }
  395. return a;
  396. }
  397. long NormAngle180(long a)
  398. {
  399. while (a<18000) a+=36000;
  400. while (a>=18000) a-=36000;
  401. return a;
  402. }
  403. long NormAngle360(long a)
  404. {
  405. while (a<0) a+=36000;
  406. while (a>=36000) a-=36000;
  407. return a;
  408. }
  409. sal_uInt16 GetAngleSector(long nWink)
  410. {
  411. while (nWink<0) nWink+=36000;
  412. while (nWink>=36000) nWink-=36000;
  413. if (nWink< 9000) return 0;
  414. if (nWink<18000) return 1;
  415. if (nWink<27000) return 2;
  416. return 3;
  417. }
  418. long GetLen(const Point& rPnt)
  419. {
  420. long x=Abs(rPnt.X());
  421. long y=Abs(rPnt.Y());
  422. if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
  423. x*=x;
  424. y*=y;
  425. x+=y;
  426. x=Round(sqrt((double)x));
  427. return x;
  428. } else {
  429. double nx=x;
  430. double ny=y;
  431. nx*=nx;
  432. ny*=ny;
  433. nx+=ny;
  434. nx=sqrt(nx);
  435. if (nx>0x7FFFFFFF) {
  436. return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
  437. } else {
  438. return Round(nx);
  439. }
  440. }
  441. }
  442. ////////////////////////////////////////////////////////////////////////////////////////////////////
  443. void GeoStat::RecalcSinCos()
  444. {
  445. if (nDrehWink==0) {
  446. nSin=0.0;
  447. nCos=1.0;
  448. } else {
  449. double a=nDrehWink*nPi180;
  450. nSin=sin(a);
  451. nCos=cos(a);
  452. }
  453. }
  454. void GeoStat::RecalcTan()
  455. {
  456. if (nShearWink==0) {
  457. nTan=0.0;
  458. } else {
  459. double a=nShearWink*nPi180;
  460. nTan=tan(a);
  461. }
  462. }
  463. ////////////////////////////////////////////////////////////////////////////////////////////////////
  464. Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo)
  465. {
  466. Polygon aPol(5);
  467. aPol[0]=rRect.TopLeft();
  468. aPol[1]=rRect.TopRight();
  469. aPol[2]=rRect.BottomRight();
  470. aPol[3]=rRect.BottomLeft();
  471. aPol[4]=rRect.TopLeft();
  472. if (rGeo.nShearWink!=0) ShearPoly(aPol,rRect.TopLeft(),rGeo.nTan);
  473. if (rGeo.nDrehWink!=0) RotatePoly(aPol,rRect.TopLeft(),rGeo.nSin,rGeo.nCos);
  474. return aPol;
  475. }
  476. void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo)
  477. {
  478. rGeo.nDrehWink=GetAngle(rPol[1]-rPol[0]);
  479. rGeo.nDrehWink=NormAngle360(rGeo.nDrehWink);
  480. // rotation successful
  481. rGeo.RecalcSinCos();
  482. Point aPt1(rPol[1]-rPol[0]);
  483. if (rGeo.nDrehWink!=0) RotatePoint(aPt1,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
  484. long nWdt=aPt1.X();
  485. Point aPt0(rPol[0]);
  486. Point aPt3(rPol[3]-rPol[0]);
  487. if (rGeo.nDrehWink!=0) RotatePoint(aPt3,Point(0,0),-rGeo.nSin,rGeo.nCos); // -Sin to reverse rotation
  488. long nHgt=aPt3.Y();
  489. long nShW=GetAngle(aPt3);
  490. nShW-=27000; // ShearWink is measured against a vertical line
  491. nShW=-nShW; // Negieren, denn '+' ist Rechtskursivierung
  492. bool bMirr=aPt3.Y()<0;
  493. if (bMirr) { // "exchange of points" when mirroring
  494. nHgt=-nHgt;
  495. nShW+=18000;
  496. aPt0=rPol[3];
  497. }
  498. nShW=NormAngle180(nShW);
  499. if (nShW<-9000 || nShW>9000) {
  500. nShW=NormAngle180(nShW+18000);
  501. }
  502. if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
  503. if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
  504. rGeo.nShearWink=nShW;
  505. rGeo.RecalcTan();
  506. Point aRU(aPt0);
  507. aRU.X()+=nWdt;
  508. aRU.Y()+=nHgt;
  509. rRect=Rectangle(aPt0,aRU);
  510. }
  511. ////////////////////////////////////////////////////////////////////////////////////////////////////
  512. void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
  513. {
  514. long dx=rPt.X()-rPt0.X();
  515. long dy=rPt.Y()-rPt0.Y();
  516. long dxa=Abs(dx);
  517. long dya=Abs(dy);
  518. if (dx==0 || dy==0 || dxa==dya) return;
  519. if (dxa>=dya*2) { rPt.Y()=rPt0.Y(); return; }
  520. if (dya>=dxa*2) { rPt.X()=rPt0.X(); return; }
  521. if ((dxa<dya) != bBigOrtho) {
  522. rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
  523. } else {
  524. rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
  525. }
  526. }
  527. void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
  528. {
  529. long dx=rPt.X()-rPt0.X();
  530. long dy=rPt.Y()-rPt0.Y();
  531. long dxa=Abs(dx);
  532. long dya=Abs(dy);
  533. if ((dxa<dya) != bBigOrtho) {
  534. rPt.Y()=rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) );
  535. } else {
  536. rPt.X()=rPt0.X()+(dya* (dx>=0 ? 1 : -1) );
  537. }
  538. }
  539. ////////////////////////////////////////////////////////////////////////////////////////////////////
  540. long BigMulDiv(long nVal, long nMul, long nDiv)
  541. {
  542. BigInt aVal(nVal);
  543. aVal*=nMul;
  544. if (aVal.IsNeg()!=(nDiv<0)) {
  545. aVal-=nDiv/2; // to round correctly
  546. } else {
  547. aVal+=nDiv/2; // to round correctly
  548. }
  549. if(nDiv)
  550. {
  551. aVal/=nDiv;
  552. return long(aVal);
  553. }
  554. return 0x7fffffff;
  555. }
  556. void Kuerzen(Fraction& rF, unsigned nDigits)
  557. {
  558. sal_Int32 nMul=rF.GetNumerator();
  559. sal_Int32 nDiv=rF.GetDenominator();
  560. bool bNeg = false;
  561. if (nMul<0) { nMul=-nMul; bNeg=!bNeg; }
  562. if (nDiv<0) { nDiv=-nDiv; bNeg=!bNeg; }
  563. if (nMul==0 || nDiv==0) return;
  564. sal_uInt32 a;
  565. a=sal_uInt32(nMul); unsigned nMulZ=0; // count leading zeros
  566. while (a<0x00800000) { nMulZ+=8; a<<=8; }
  567. while (a<0x80000000) { nMulZ++; a<<=1; }
  568. a=sal_uInt32(nDiv); unsigned nDivZ=0; // count leading zeros
  569. while (a<0x00800000) { nDivZ+=8; a<<=8; }
  570. while (a<0x80000000) { nDivZ++; a<<=1; }
  571. // count the number of digits
  572. int nMulDigits=32-nMulZ;
  573. int nDivDigits=32-nDivZ;
  574. // count how many decimal places can be removed
  575. int nMulWeg=nMulDigits-nDigits; if (nMulWeg<0) nMulWeg=0;
  576. int nDivWeg=nDivDigits-nDigits; if (nDivWeg<0) nDivWeg=0;
  577. int nWeg=Min(nMulWeg,nDivWeg);
  578. nMul>>=nWeg;
  579. nDiv>>=nWeg;
  580. if (nMul==0 || nDiv==0) {
  581. DBG_WARNING("Math error after canceling decimal places.");
  582. return;
  583. }
  584. if (bNeg) nMul=-nMul;
  585. rF=Fraction(nMul,nDiv);
  586. }
  587. ////////////////////////////////////////////////////////////////////////////////////////////////////
  588. // How many eU units fit into a mm, respectively an inch?
  589. // Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
  590. FrPair GetInchOrMM(MapUnit eU)
  591. {
  592. switch (eU) {
  593. case MAP_1000TH_INCH: return FrPair(1000,1);
  594. case MAP_100TH_INCH : return FrPair( 100,1);
  595. case MAP_10TH_INCH : return FrPair( 10,1);
  596. case MAP_INCH : return FrPair( 1,1);
  597. case MAP_POINT : return FrPair( 72,1);
  598. case MAP_TWIP : return FrPair(1440,1);
  599. case MAP_100TH_MM : return FrPair( 100,1);
  600. case MAP_10TH_MM : return FrPair( 10,1);
  601. case MAP_MM : return FrPair( 1,1);
  602. case MAP_CM : return FrPair( 1,10);
  603. case MAP_PIXEL : {
  604. VirtualDevice aVD;
  605. aVD.SetMapMode(MapMode(MAP_100TH_MM));
  606. Point aP(aVD.PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
  607. return FrPair(6400,aP.X(),6400,aP.Y());
  608. }
  609. case MAP_APPFONT: case MAP_SYSFONT: {
  610. VirtualDevice aVD;
  611. aVD.SetMapMode(MapMode(eU));
  612. Point aP(aVD.LogicToPixel(Point(32,32))); // 32 units for more accuracy
  613. aVD.SetMapMode(MapMode(MAP_100TH_MM));
  614. aP=aVD.PixelToLogic(aP);
  615. return FrPair(3200,aP.X(),3200,aP.Y());
  616. }
  617. default: break;
  618. }
  619. return Fraction(1,1);
  620. }
  621. FrPair GetInchOrMM(FieldUnit eU)
  622. {
  623. switch (eU) {
  624. case FUNIT_INCH : return FrPair( 1,1);
  625. case FUNIT_POINT : return FrPair( 72,1);
  626. case FUNIT_TWIP : return FrPair(1440,1);
  627. case FUNIT_100TH_MM : return FrPair( 100,1);
  628. case FUNIT_MM : return FrPair( 1,1);
  629. case FUNIT_CM : return FrPair( 1,10);
  630. case FUNIT_M : return FrPair( 1,1000);
  631. case FUNIT_KM : return FrPair( 1,1000000);
  632. case FUNIT_PICA : return FrPair( 6,1);
  633. case FUNIT_FOOT : return FrPair( 1,12);
  634. case FUNIT_MILE : return FrPair( 1,63360);
  635. default: break;
  636. }
  637. return Fraction(1,1);
  638. }
  639. // Calculate the factor that we need to convert units from eS to eD.
  640. // e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
  641. FrPair GetMapFactor(MapUnit eS, MapUnit eD)
  642. {
  643. if (eS==eD) return FrPair(1,1,1,1);
  644. FrPair aS(GetInchOrMM(eS));
  645. FrPair aD(GetInchOrMM(eD));
  646. bool bSInch=IsInch(eS);
  647. bool bDInch=IsInch(eD);
  648. FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
  649. if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
  650. if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
  651. return aRet;
  652. };
  653. FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
  654. {
  655. if (eS==eD) return FrPair(1,1,1,1);
  656. FrPair aS(GetInchOrMM(eS));
  657. FrPair aD(GetInchOrMM(eD));
  658. bool bSInch=IsInch(eS);
  659. bool bDInch=IsInch(eD);
  660. FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
  661. if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
  662. if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
  663. return aRet;
  664. };
  665. ////////////////////////////////////////////////////////////////////////////////////////////////////
  666. // 1 mile = 8 furlong = 63.360" = 1.609.344,0mm
  667. // 1 furlong = 10 chains = 7.920" = 201.168,0mm
  668. // 1 chain = 4 poles = 792" = 20.116,8mm
  669. // 1 pole = 5 1/2 yd = 198" = 5.029,2mm
  670. // 1 yd = 3 ft = 36" = 914,4mm
  671. // 1 ft = 12 " = 1" = 304,8mm
  672. void GetMeterOrInch(MapUnit eMU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
  673. {
  674. rnMul=1; rnDiv=1;
  675. short nKomma=0;
  676. bool bMetr = false, bInch = false;
  677. switch (eMU) {
  678. // Metrisch
  679. case MAP_100TH_MM : bMetr = true; nKomma=5; break;
  680. case MAP_10TH_MM : bMetr = true; nKomma=4; break;
  681. case MAP_MM : bMetr = true; nKomma=3; break;
  682. case MAP_CM : bMetr = true; nKomma=2; break;
  683. // Inch
  684. case MAP_1000TH_INCH: bInch = true; nKomma=3; break;
  685. case MAP_100TH_INCH : bInch = true; nKomma=2; break;
  686. case MAP_10TH_INCH : bInch = true; nKomma=1; break;
  687. case MAP_INCH : bInch = true; nKomma=0; break;
  688. case MAP_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
  689. case MAP_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
  690. // Sonstiges
  691. case MAP_PIXEL : break;
  692. case MAP_SYSFONT : break;
  693. case MAP_APPFONT : break;
  694. case MAP_RELATIVE : break;
  695. default: break;
  696. } // switch
  697. rnKomma=nKomma;
  698. rbMetr=bMetr;
  699. rbInch=bInch;
  700. }
  701. void GetMeterOrInch(FieldUnit eFU, short& rnKomma, long& rnMul, long& rnDiv, bool& rbMetr, bool& rbInch)
  702. {
  703. rnMul=1; rnDiv=1;
  704. short nKomma=0;
  705. bool bMetr = false, bInch = false;
  706. switch (eFU) {
  707. case FUNIT_NONE : break;
  708. // metrically
  709. case FUNIT_100TH_MM : bMetr = true; nKomma=5; break;
  710. case FUNIT_MM : bMetr = true; nKomma=3; break;
  711. case FUNIT_CM : bMetr = true; nKomma=2; break;
  712. case FUNIT_M : bMetr = true; nKomma=0; break;
  713. case FUNIT_KM : bMetr = true; nKomma=-3; break;
  714. // Inch
  715. case FUNIT_TWIP : bInch = true; rnDiv=144; nKomma=1; break; // 1Twip = 1/1440"
  716. case FUNIT_POINT : bInch = true; rnDiv=72; break; // 1Pt = 1/72"
  717. case FUNIT_PICA : bInch = true; rnDiv=6; break; // 1Pica = 1/6" ?
  718. case FUNIT_INCH : bInch = true; break; // 1" = 1"
  719. case FUNIT_FOOT : bInch = true; rnMul=12; break; // 1Ft = 12"
  720. case FUNIT_MILE : bInch = true; rnMul=6336; nKomma=-1; break; // 1mile = 63360"
  721. // others
  722. case FUNIT_CUSTOM : break;
  723. case FUNIT_PERCENT : nKomma=2; break;
  724. // TODO: Add code to handle the following (added to remove warning)
  725. case FUNIT_CHAR : break;
  726. case FUNIT_LINE : break;
  727. } // switch
  728. rnKomma=nKomma;
  729. rbMetr=bMetr;
  730. rbInch=bInch;
  731. }
  732. void SdrFormatter::Undirty()
  733. {
  734. if (aScale.GetNumerator()==0 || aScale.GetDenominator()==0) aScale=Fraction(1,1);
  735. bool bSrcMetr,bSrcInch,bDstMetr,bDstInch;
  736. long nMul1,nDiv1,nMul2,nDiv2;
  737. short nKomma1,nKomma2;
  738. // first: normalize to m or in
  739. if (!bSrcFU) {
  740. GetMeterOrInch(eSrcMU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
  741. } else {
  742. GetMeterOrInch(eSrcFU,nKomma1,nMul1,nDiv1,bSrcMetr,bSrcInch);
  743. }
  744. if (!bDstFU) {
  745. GetMeterOrInch(eDstMU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
  746. } else {
  747. GetMeterOrInch(eDstFU,nKomma2,nMul2,nDiv2,bDstMetr,bDstInch);
  748. }
  749. nMul1*=nDiv2;
  750. nDiv1*=nMul2;
  751. nKomma1=nKomma1-nKomma2;
  752. if (bSrcInch && bDstMetr) {
  753. nKomma1+=4;
  754. nMul1*=254;
  755. }
  756. if (bSrcMetr && bDstInch) {
  757. nKomma1-=4;
  758. nDiv1*=254;
  759. }
  760. // temporary fraction for canceling
  761. Fraction aTempFract(nMul1,nDiv1);
  762. nMul1=aTempFract.GetNumerator();
  763. nDiv1=aTempFract.GetDenominator();
  764. nMul_=nMul1;
  765. nDiv_=nDiv1;
  766. nKomma_=nKomma1;
  767. bDirty=sal_False;
  768. }
  769. void SdrFormatter::TakeStr(long nVal, XubString& rStr) const
  770. {
  771. sal_Unicode aNullCode('0');
  772. if(!nVal)
  773. {
  774. rStr = UniString();
  775. rStr += aNullCode;
  776. return;
  777. }
  778. // we may lose some decimal places here, because of MulDiv instead of Real
  779. sal_Bool bNeg(nVal < 0);
  780. SvtSysLocale aSysLoc;
  781. const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
  782. ForceUndirty();
  783. sal_Int16 nK(nKomma_);
  784. XubString aStr;
  785. if(bNeg)
  786. nVal = -nVal;
  787. while(nK <= -3)
  788. {
  789. nVal *= 1000;
  790. nK += 3;
  791. }
  792. while(nK <= -1)
  793. {
  794. nVal *= 10;
  795. nK++;
  796. }
  797. if(nMul_ != nDiv_)
  798. nVal = BigMulDiv(nVal, nMul_, nDiv_);
  799. aStr = UniString::CreateFromInt32(nVal);
  800. if(nK > 0 && aStr.Len() <= nK )
  801. {
  802. // decimal separator necessary
  803. sal_Int16 nAnz(nK - aStr.Len());
  804. if(nAnz >= 0 && rLoc.isNumLeadingZero())
  805. nAnz++;
  806. for(xub_StrLen i=0; i<nAnz; i++)
  807. aStr.Insert(aNullCode, 0);
  808. // remove superfluous decimal points
  809. xub_StrLen nNumDigits(rLoc.getNumDigits());
  810. xub_StrLen nWeg(nK - nNumDigits);
  811. if(nWeg > 0)
  812. {
  813. // TODO: we should round here
  814. aStr.Erase(aStr.Len() - nWeg);
  815. nK = nNumDigits;
  816. }
  817. }
  818. // remember everything before the decimal separator for later
  819. xub_StrLen nVorKomma(aStr.Len() - nK);
  820. if(nK > 0)
  821. {
  822. // insert KommaChar (decimal separator)
  823. // remove trailing zeros
  824. while(nK > 0 && aStr.GetChar(aStr.Len() - 1) == aNullCode)
  825. {
  826. aStr.Erase(aStr.Len() - 1);
  827. nK--;
  828. }
  829. if(nK > 0)
  830. {
  831. // do we still have decimal places?
  832. sal_Unicode cDec(rLoc.getNumDecimalSep().GetChar(0));
  833. aStr.Insert(cDec, nVorKomma);
  834. }
  835. }
  836. // add in thousands separator (if necessary)
  837. if( nVorKomma > 3 )
  838. {
  839. String aThoSep( rLoc.getNumThousandSep() );
  840. if ( aThoSep.Len() > 0 )
  841. {
  842. sal_Unicode cTho( aThoSep.GetChar(0) );
  843. sal_Int32 i(nVorKomma - 3);
  844. while(i > 0)
  845. {
  846. rStr.Insert(cTho, (xub_StrLen)i);
  847. i -= 3;
  848. }
  849. }
  850. }
  851. if(!aStr.Len())
  852. aStr += aNullCode;
  853. if(bNeg && (aStr.Len() > 1 || aStr.GetChar(0) != aNullCode))
  854. {
  855. rStr.Insert(sal_Unicode('-'), 0);
  856. }
  857. rStr = aStr;
  858. }
  859. void SdrFormatter::TakeUnitStr(MapUnit eUnit, XubString& rStr)
  860. {
  861. switch(eUnit)
  862. {
  863. // metrically
  864. case MAP_100TH_MM :
  865. {
  866. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
  867. break;
  868. }
  869. case MAP_10TH_MM :
  870. {
  871. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10mm"));
  872. break;
  873. }
  874. case MAP_MM :
  875. {
  876. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
  877. break;
  878. }
  879. case MAP_CM :
  880. {
  881. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
  882. break;
  883. }
  884. // Inch
  885. case MAP_1000TH_INCH:
  886. {
  887. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/1000\""));
  888. break;
  889. }
  890. case MAP_100TH_INCH :
  891. {
  892. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100\""));
  893. break;
  894. }
  895. case MAP_10TH_INCH :
  896. {
  897. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/10\""));
  898. break;
  899. }
  900. case MAP_INCH :
  901. {
  902. rStr = UniString();
  903. rStr += sal_Unicode('"');
  904. break;
  905. }
  906. case MAP_POINT :
  907. {
  908. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
  909. break;
  910. }
  911. case MAP_TWIP :
  912. {
  913. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
  914. break;
  915. }
  916. // others
  917. case MAP_PIXEL :
  918. {
  919. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pixel"));
  920. break;
  921. }
  922. case MAP_SYSFONT :
  923. {
  924. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("sysfont"));
  925. break;
  926. }
  927. case MAP_APPFONT :
  928. {
  929. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("appfont"));
  930. break;
  931. }
  932. case MAP_RELATIVE :
  933. {
  934. rStr = UniString();
  935. rStr += sal_Unicode('%');
  936. break;
  937. }
  938. default: break;
  939. }
  940. }
  941. void SdrFormatter::TakeUnitStr(FieldUnit eUnit, XubString& rStr)
  942. {
  943. switch(eUnit)
  944. {
  945. default :
  946. case FUNIT_NONE :
  947. case FUNIT_CUSTOM :
  948. {
  949. rStr = UniString();
  950. break;
  951. }
  952. // metrically
  953. case FUNIT_100TH_MM:
  954. {
  955. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("/100mm"));
  956. break;
  957. }
  958. case FUNIT_MM :
  959. {
  960. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mm"));
  961. break;
  962. }
  963. case FUNIT_CM :
  964. {
  965. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("cm"));
  966. break;
  967. }
  968. case FUNIT_M :
  969. {
  970. rStr = UniString();
  971. rStr += sal_Unicode('m');
  972. break;
  973. }
  974. case FUNIT_KM :
  975. {
  976. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("km"));
  977. break;
  978. }
  979. // Inch
  980. case FUNIT_TWIP :
  981. {
  982. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("twip"));
  983. break;
  984. }
  985. case FUNIT_POINT :
  986. {
  987. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pt"));
  988. break;
  989. }
  990. case FUNIT_PICA :
  991. {
  992. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("pica"));
  993. break;
  994. }
  995. case FUNIT_INCH :
  996. {
  997. rStr = UniString();
  998. rStr += sal_Unicode('"');
  999. break;
  1000. }
  1001. case FUNIT_FOOT :
  1002. {
  1003. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("ft"));
  1004. break;
  1005. }
  1006. case FUNIT_MILE :
  1007. {
  1008. rStr = UniString(RTL_CONSTASCII_USTRINGPARAM("mile(s)"));
  1009. break;
  1010. }
  1011. // others
  1012. case FUNIT_PERCENT:
  1013. {
  1014. rStr = UniString();
  1015. rStr += sal_Unicode('%');
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1021. /* vim:set shiftwidth=4 softtabstop=4 expandtab: */