1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #ifndef INCLUDED_SVX_SVDTRANS_HXX
21 #define INCLUDED_SVX_SVDTRANS_HXX
22 
23 #include <rtl/ustring.hxx>
24 #include <svx/svxdllapi.h>
25 #include <tools/fldunit.hxx>
26 #include <tools/fract.hxx>
27 #include <tools/gen.hxx>
28 #include <tools/helpers.hxx>
29 #include <tools/mapunit.hxx>
30 #include <tools/poly.hxx>
31 
32 // The DrawingEngine's angles are specified in 1/100th degrees
33 // We need to convert these angles to radians, in order to be able
34 // to process them with trigonometric functions.
35 // This is done, using the constant F_PI18000.
36 //
37 // Example usage:
38 // nAngle ... is an angle in 1/100 Deg
39 //
40 // Which is converted, by this:
41 //   double nSin=sin(nAngle*F_PI18000);
42 //
43 // To convert it back, we use division.
44 
45 // That maximum shear angle
46 #define SDRMAXSHEAR 8900
47 
48 class XPolygon;
49 class XPolyPolygon;
50 
MovePoly(tools::Polygon & rPoly,const Size & S)51 inline void MovePoly(tools::Polygon& rPoly, const Size& S)      { rPoly.Move(S.Width(),S.Height()); }
52 void MoveXPoly(XPolygon& rPoly, const Size& S);
53 
54 SVX_DLLPUBLIC void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
55 inline void ResizePoint(Point& rPnt, const Point& rRef, const Fraction& xFract, const Fraction& yFract);
56 void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
57 void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
58 
59 inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs);
60 SVX_DLLPUBLIC void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs);
61 void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs);
62 void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs);
63 
64 void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2);
65 void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2);
66 
67 inline void ShearPoint(Point& rPnt, const Point& rRef, double tn, bool bVShear = false);
68 SVX_DLLPUBLIC void ShearPoly(tools::Polygon& rPoly, const Point& rRef, double tn);
69 void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear = false);
70 
71 /**
72  * rPnt.X/rPnt.Y is set to rCenter.X or rCenter.Y!
73  * We then only need to rotate rPnt by rCenter.
74  *
75  * @return the returned angle is in rad
76  */
77 inline double GetCrookAngle(Point& rPnt, const Point& rCenter, const Point& rRad, bool bVertical);
78 
79 /**
80  * The following methods accept a point of an XPolygon, whereas the neighbouring
81  * control points of the actual point are passed in pC1/pC2.
82  * Via rSin/rCos, sin(nAngle) and cos(nAngle) are returned.
83  *
84  * @return the returned angle is in rad
85  */
86 double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
87                          const Point& rRad, double& rSin, double& rCos, bool bVert);
88 double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
89                         const Point& rRad, double& rSin, double& rCos, bool bVert);
90 double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
91                           const Point& rRad, double& rSin, double& rCos, bool bVert,
92                           const tools::Rectangle& rRefRect);
93 
94 void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
95 void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
96 void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect);
97 
98 void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
99 void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
100 void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect);
101 
102 /**************************************************************************************************/
103 /*  Inline                                                                                        */
104 /**************************************************************************************************/
105 
ResizePoint(Point & rPnt,const Point & rRef,const Fraction & xFract,const Fraction & yFract)106 inline void ResizePoint(Point& rPnt, const Point& rRef, const Fraction& xFract, const Fraction& yFract)
107 {
108     double nxFract = xFract.IsValid() ? static_cast<double>(xFract) : 1.0;
109     double nyFract = yFract.IsValid() ? static_cast<double>(yFract) : 1.0;
110     rPnt.setX(rRef.X() + FRound( (rPnt.X() - rRef.X()) * nxFract ));
111     rPnt.setY(rRef.Y() + FRound( (rPnt.Y() - rRef.Y()) * nyFract ));
112 }
113 
RotatePoint(Point & rPnt,const Point & rRef,double sn,double cs)114 inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs)
115 {
116     long dx=rPnt.X()-rRef.X();
117     long dy=rPnt.Y()-rRef.Y();
118     rPnt.setX(FRound(rRef.X()+dx*cs+dy*sn));
119     rPnt.setY(FRound(rRef.Y()+dy*cs-dx*sn));
120 }
121 
ShearPoint(Point & rPnt,const Point & rRef,double tn,bool bVShear)122 inline void ShearPoint(Point& rPnt, const Point& rRef, double tn, bool bVShear)
123 {
124     if (!bVShear) { // Horizontal
125         if (rPnt.Y()!=rRef.Y()) { // else not needed
126             rPnt.AdjustX(-FRound((rPnt.Y()-rRef.Y())*tn));
127         }
128     } else { // or else vertical
129         if (rPnt.X()!=rRef.X()) { // else not needed
130             rPnt.AdjustY(-FRound((rPnt.X()-rRef.X())*tn));
131         }
132     }
133 }
134 
GetCrookAngle(Point & rPnt,const Point & rCenter,const Point & rRad,bool bVertical)135 inline double GetCrookAngle(Point& rPnt, const Point& rCenter, const Point& rRad, bool bVertical)
136 {
137     double nAngle;
138     if (bVertical) {
139         long dy=rPnt.Y()-rCenter.Y();
140         nAngle=static_cast<double>(dy)/static_cast<double>(rRad.Y());
141         rPnt.setY(rCenter.Y());
142     } else {
143         long dx=rCenter.X()-rPnt.X();
144         nAngle=static_cast<double>(dx)/static_cast<double>(rRad.X());
145         rPnt.setX(rCenter.X());
146     }
147     return nAngle;
148 }
149 
150 /**************************************************************************************************/
151 /**************************************************************************************************/
152 
153 /**
154  * The Y axis points down!
155  * The function negates the Y axis, when calculating the angle, such
156  * that GetAngle(Point(0,-1))=90 deg.
157  * GetAngle(Point(0,0)) returns 0.
158  *
159  * @return the returned value is in the range of -180.00..179.99 deg
160  * and is in 1/100 deg units
161  */
162 SVX_DLLPUBLIC long GetAngle(const Point& rPnt);
163 
164 long NormAngle18000(long a); /// Normalize angle to -180.00..179.99
165 
166 SVX_DLLPUBLIC long NormAngle36000(long a); /// Normalize angle to 0.00..359.99
167 
168 sal_uInt16 GetAngleSector(long nAngle); /// Determine sector within the cartesian coordinate system
169 
170 /**
171  * Calculates the length of (0,0) via a^2 + b^2 = c^2
172  * In order to avoid overflows, we ignore some decimal places.
173  */
174 long GetLen(const Point& rPnt);
175 
176 /**
177  * The transformation of a rectangle into a polygon, by
178  * using angle parameters from GeoStat.                          ------------
179  * The point of reference is always the Point 0, meaning        /1        2/
180  * the upper left corner of the initial rectangle.             /          /
181  * When calculating the polygon, the order is first           /          /
182  * shear and then the rotation.                              /          /
183  *                                                          /          / \
184  *                                                         /          /   |
185  * A) Initial rectangle aRect  B) After applying Shear     /0        3/ Rot|
186  * +------------------+       --------------------        ------------------
187  * |0                1|        \0                1\       C) After applying Rotate
188  * |                  |         \                  \
189  * |                  |       |  \                  \
190  * |3                2|       |   \3                2\
191  * +------------------+       |    --------------------
192  *                            |Shr
193  *
194  * When converting the polygon back into a rect, the order is necessarily the
195  * other way around:
196  *  - Calculating the rotation angle: angle of the line 0-1 in figure C) to the horizontal
197  *  - Turning the sheared rect back (we get figure B)
198  *  - Determining the width of the rect = length of the line 0-1 in figure B)
199  *  - Determining the height of the rect = vertical distance between the points 0 and 3
200  *    of figure B)
201  *  - Determining the shear angle from the line 0-3 to the perpendicular line.
202  *
203  * We need to keep in mind that the polygon can be mirrored when it was
204  * transformed in the meantime (e.g. mirror or resize with negative factor).
205  * In that case, we first need to normalize, by swapping points (0 with 3 and 1
206  * with 2), so that it has the right orientation.
207  *
208  * Note: a positive shear angle means a shear with a positive visible curvature
209  * on the screen. Mathematically, that would be a negative curvature, as the
210  * Y axis runs from top to bottom on the screen.
211  * Rotation angle: positive means a visible left rotation.
212  */
213 
214 class GeoStat { // Geometric state for a rect
215 public:
216     long     nRotationAngle;
217     long     nShearAngle;
218     double   nTan;      // tan(nShearAngle)
219     double   nSin;      // sin(nRotationAngle)
220     double   nCos;      // cos(nRotationAngle)
221 
GeoStat()222     GeoStat(): nRotationAngle(0),nShearAngle(0),nTan(0.0),nSin(0.0),nCos(1.0) {}
223     void RecalcSinCos();
224     void RecalcTan();
225 };
226 
227 tools::Polygon Rect2Poly(const tools::Rectangle& rRect, const GeoStat& rGeo);
228 void Poly2Rect(const tools::Polygon& rPol, tools::Rectangle& rRect, GeoStat& rGeo);
229 
230 void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho);
231 void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho);
232 
233 // Multiplication and subsequent division
234 // Calculation and intermediate values are in BigInt
235 SVX_DLLPUBLIC long BigMulDiv(long nVal, long nMul, long nDiv);
236 
237 class FrPair {
238     Fraction aX;
239     Fraction aY;
240 public:
FrPair(const Fraction & rBoth)241     FrPair(const Fraction& rBoth)                     : aX(rBoth),aY(rBoth)         {}
FrPair(const Fraction & rX,const Fraction & rY)242     FrPair(const Fraction& rX, const Fraction& rY)    : aX(rX),aY(rY)               {}
FrPair(long nMul,long nDiv)243     FrPair(long nMul, long nDiv)                      : aX(nMul,nDiv),aY(nMul,nDiv) {}
FrPair(long xMul,long xDiv,long yMul,long yDiv)244     FrPair(long xMul, long xDiv, long yMul, long yDiv): aX(xMul,xDiv),aY(yMul,yDiv) {}
X() const245     const Fraction& X() const { return aX; }
Y() const246     const Fraction& Y() const { return aY; }
X()247     Fraction& X()             { return aX; }
Y()248     Fraction& Y()             { return aY; }
249 };
250 
251 // To convert units of measurement
252 SVX_DLLPUBLIC FrPair GetMapFactor(MapUnit eS, MapUnit eD);
253 FrPair GetMapFactor(FieldUnit eS, FieldUnit eD);
254 
IsMetric(MapUnit eU)255 inline bool IsMetric(MapUnit eU) {
256     return (eU==MapUnit::Map100thMM || eU==MapUnit::Map10thMM || eU==MapUnit::MapMM || eU==MapUnit::MapCM);
257 }
258 
IsInch(MapUnit eU)259 inline bool IsInch(MapUnit eU) {
260     return (eU==MapUnit::Map1000thInch || eU==MapUnit::Map100thInch || eU==MapUnit::Map10thInch || eU==MapUnit::MapInch ||
261             eU==MapUnit::MapPoint       || eU==MapUnit::MapTwip);
262 }
263 
IsMetric(FieldUnit eU)264 inline bool IsMetric(FieldUnit eU) {
265     return (eU == FieldUnit::MM || eU == FieldUnit::CM || eU == FieldUnit::M
266             || eU == FieldUnit::KM || eU == FieldUnit::MM_100TH);
267 }
268 
IsInch(FieldUnit eU)269 inline bool IsInch(FieldUnit eU) {
270     return (eU == FieldUnit::TWIP || eU == FieldUnit::POINT
271             || eU == FieldUnit::PICA || eU == FieldUnit::INCH
272             || eU == FieldUnit::FOOT || eU == FieldUnit::MILE);
273 }
274 
275 class SVX_DLLPUBLIC SdrFormatter {
276     long      nMul_;
277     long      nDiv_;
278     short     nComma_;
279     bool      bDirty;
280     MapUnit const   eSrcMU;
281     MapUnit const   eDstMU;
282 private:
283     SVX_DLLPRIVATE void Undirty();
284 public:
SdrFormatter(MapUnit eSrc,MapUnit eDst)285     SdrFormatter(MapUnit eSrc, MapUnit eDst)
286         : nMul_(0)
287         , nDiv_(0)
288         , nComma_(0)
289         , bDirty(true)
290         , eSrcMU(eSrc)
291         , eDstMU(eDst)
292     {
293     }
294     OUString GetStr(long nVal) const;
295     static OUString GetUnitStr(MapUnit eUnit);
296     static OUString GetUnitStr(FieldUnit eUnit);
297 };
298 
299 
300 #endif // INCLUDED_SVX_SVDTRANS_HXX
301 
302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
303