1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #ifndef INCLUDED_SVX_SVDTRANS_HXX
21 #define INCLUDED_SVX_SVDTRANS_HXX
23 #include <rtl/ustring.hxx>
24 #include <sal/log.hxx>
25 #include <svx/svxdllapi.h>
26 #include <tools/fract.hxx>
27 #include <tools/gen.hxx>
28 #include <tools/poly.hxx>
29 #include <vcl/field.hxx>
30 #include <vcl/mapmod.hxx>
34 // Winkelangaben der DrawingEngine sind 1/100 Degree
35 // #i19054# nowhere used, removed // const int nAngleDiv=100;
36 // Um Winkel der DrawingEngine mit den Trigonometrischen Funktionen
37 // verarbeiten zu koennen, muessen sie zunaest ins Bogenmass umgerechnet
38 // werden. Dies gestaltet sich recht einfach mit der folgenden Konstanten
39 // nPi180. Sei nAngle ein Winkel in 1/100 Deg so schreibt man z.B.:
40 // double nSin=sin(nAngle*nPi180);
41 // Rueckwandlung entsprechend durch Teilen.
42 const double nPi
=3.14159265358979323846;
43 const double nPi180
=0.000174532925199432957692222; // Bei zuweing Stellen ist tan(4500*nPi180)!=1.0
45 // Der maximale Shearwinkel
46 #define SDRMAXSHEAR 8900
51 inline long Round(double a
) { return a
>0.0 ? (long)(a
+0.5) : -(long)((-a
)+0.5); }
53 inline void MoveRect(Rectangle
& rRect
, const Size
& S
) { rRect
.Move(S
.Width(),S
.Height()); }
54 inline void MovePoint(Point
& rPnt
, const Size
& S
) { rPnt
.X()+=S
.Width(); rPnt
.Y()+=S
.Height(); }
55 inline void MovePoly(Polygon
& rPoly
, const Size
& S
) { rPoly
.Move(S
.Width(),S
.Height()); }
56 inline void MovePoly(tools::PolyPolygon
& rPoly
, const Size
& S
) { rPoly
.Move(S
.Width(),S
.Height()); }
57 void MoveXPoly(XPolygon
& rPoly
, const Size
& S
);
59 SVX_DLLPUBLIC
void ResizeRect(Rectangle
& rRect
, const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
, bool bNoJustify
= false);
60 inline void ResizePoint(Point
& rPnt
, const Point
& rRef
, Fraction xFact
, Fraction yFact
);
61 void ResizePoly(Polygon
& rPoly
, const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
);
62 void ResizeXPoly(XPolygon
& rPoly
, const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
);
64 inline void RotatePoint(Point
& rPnt
, const Point
& rRef
, double sn
, double cs
);
65 SVX_DLLPUBLIC
void RotatePoly(Polygon
& rPoly
, const Point
& rRef
, double sn
, double cs
);
66 void RotateXPoly(XPolygon
& rPoly
, const Point
& rRef
, double sn
, double cs
);
67 void RotateXPoly(XPolyPolygon
& rPoly
, const Point
& rRef
, double sn
, double cs
);
69 void MirrorPoint(Point
& rPnt
, const Point
& rRef1
, const Point
& rRef2
);
70 void MirrorPoly(Polygon
& rPoly
, const Point
& rRef1
, const Point
& rRef2
);
71 void MirrorXPoly(XPolygon
& rPoly
, const Point
& rRef1
, const Point
& rRef2
);
73 inline void ShearPoint(Point
& rPnt
, const Point
& rRef
, double tn
, bool bVShear
= false);
74 SVX_DLLPUBLIC
void ShearPoly(Polygon
& rPoly
, const Point
& rRef
, double tn
, bool bVShear
= false);
75 void ShearXPoly(XPolygon
& rPoly
, const Point
& rRef
, double tn
, bool bVShear
= false);
77 // rPnt.X bzw rPnt.Y wird auf rCenter.X bzw. rCenter.Y gesetzt!
78 // anschliessend muss rPnt nur noch um rCenter gedreht werden.
79 // Der Rueckgabewinkel ist ausnahmsweise in Rad.
80 inline double GetCrookAngle(Point
& rPnt
, const Point
& rCenter
, const Point
& rRad
, bool bVertical
);
81 // Die folgenden Methoden behandeln einen Punkt eines XPolygons, wobei die
82 // benachbarten Kontrollpunkte des eigentlichen Punktes ggf. in pC1/pC2
83 // uebergeben werden. Ueber rSin/rCos wird gleichzeitig sin(nAngle) und cos(nAngle)
85 // Der Rueckgabewinkel ist hier ebenfalls in Rad.
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 Rectangle
& rRefRect
);
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 Rectangle
& rRefRect
);
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 Rectangle
& rRefRect
);
102 /**************************************************************************************************/
104 /**************************************************************************************************/
106 inline void ResizePoint(Point
& rPnt
, const Point
& rRef
, Fraction xFact
, Fraction yFact
)
108 if (!xFact
.IsValid()) {
109 SAL_WARN( "svx.svdraw", "invalid fraction xFact, using Fraction(1,1)" );
110 xFact
= Fraction(1,1);
112 if (!yFact
.IsValid()) {
113 SAL_WARN( "svx.svdraw", "invalid fraction yFact, using Fraction(1,1)" );
114 yFact
= Fraction(1,1);
116 rPnt
.X() = rRef
.X() + Round( (rPnt
.X() - rRef
.X()) * double(xFact
) );
117 rPnt
.Y() = rRef
.Y() + Round( (rPnt
.Y() - rRef
.Y()) * double(yFact
) );
120 inline void RotatePoint(Point
& rPnt
, const Point
& rRef
, double sn
, double cs
)
122 long dx
=rPnt
.X()-rRef
.X();
123 long dy
=rPnt
.Y()-rRef
.Y();
124 rPnt
.X()=Round(rRef
.X()+dx
*cs
+dy
*sn
);
125 rPnt
.Y()=Round(rRef
.Y()+dy
*cs
-dx
*sn
);
128 inline void ShearPoint(Point
& rPnt
, const Point
& rRef
, double tn
, bool bVShear
)
130 if (!bVShear
) { // Horizontal
131 if (rPnt
.Y()!=rRef
.Y()) { // sonst nicht noetig
132 rPnt
.X()-=Round((rPnt
.Y()-rRef
.Y())*tn
);
134 } else { // ansonsten vertikal
135 if (rPnt
.X()!=rRef
.X()) { // sonst nicht noetig
136 rPnt
.Y()-=Round((rPnt
.X()-rRef
.X())*tn
);
141 inline double GetCrookAngle(Point
& rPnt
, const Point
& rCenter
, const Point
& rRad
, bool bVertical
)
145 long dy
=rPnt
.Y()-rCenter
.Y();
146 nAngle
=(double)dy
/(double)rRad
.Y();
147 rPnt
.Y()=rCenter
.Y();
149 long dx
=rCenter
.X()-rPnt
.X();
150 nAngle
=(double)dx
/(double)rRad
.X();
151 rPnt
.X()=rCenter
.X();
156 /**************************************************************************************************/
157 /**************************************************************************************************/
159 // Y-Achse zeigt nach unten! Die Funktion negiert bei der
160 // Winkelberechnung die Y-Achse, sodass GetAngle(Point(0,-1))=90.00deg.
161 // GetAngle(Point(0,0)) liefert 0.
162 // Der Rueckgabewert liegt im Bereich -180.00..179.99 Degree und
163 // ist in 1/100 Degree angegeben.
164 SVX_DLLPUBLIC
long GetAngle(const Point
& rPnt
);
165 long NormAngle180(long a
); // Winkel normalisieren auf -180.00..179.99
166 SVX_DLLPUBLIC
long NormAngle360(long a
); // Winkel normalisieren auf 0.00..359.99
167 sal_uInt16
GetAngleSector(long nAngle
); // Sektor im kartesischen Koordinatensystem bestimmen
168 // Berechnet die Laenge von (0,0) via a^2 + b^2 = c^2
169 // Zur Vermeidung von Ueberlaeufen werden ggf. einige Stellen ignoriert.
170 long GetLen(const Point
& rPnt
);
173 Transformation eines Rechtecks in ein Polygon unter ------------
174 Anwendung der Winkelparameter aus GeoStat. /1 2/
175 Referenzpunkt ist stets der Punkt 0, also die linke / /
176 obere Ecke des Ausgangsrects. / /
177 Bei der Berechnung des Polygons ist die Reihenfolge / /
178 (erst Shear, dann Rotation vorgegeben). / / \
180 A) Ausgangsrechteck aRect B) Nach Anwendung von Shear /0 3/ Rot|
181 +------------------+ -------------------- ------------ ------
182 |0 1| \0 1\ C) Nach Anwendung
186 +------------------+ | --------------------
188 Bei Rueckkonvertierung des Polygons in ein Rect ist die Reihenfolge
189 zwangslaeufig umgekehrt:
190 - Berechnung des Drehwinkels: Winkel der Strecke 0-1 aus Abb. C) zum Horizont
191 - Rueckdrehung des geshearten Rects (man erhaelt Abb B))
192 - Bestimmung der Breite des Rects=Laenge der Strecke 0-1 aus Abb. B)
193 - Bestimmung der Hoehe des Rects=vertikaler Abstand zwischen den Punkten
195 - Bestimmung des Shear-Winkels aus der Strecke 0-3 zur Senkrechten.
196 Es ist darauf zu achten, dass das Polygon bei einer zwischenzeitlichen
197 Transformation evtl. gespiegelt wurde (Mirror oder Resize mit neg. Faktor).
198 In diesem Fall muss zunaecht eine Normalisierung durch Vertauschung der
199 Punkte (z.B. 0 mit 3 und 1 mit 2) durchgefuehrt werden, damit der
200 Richtungssinn im Polygon wieder stimmig ist.
201 Hinweis: Positiver Shear-Winkel bedeutet Shear mit auf dem Bildschirm
202 sichtbarer positiver Kursivierung. Mathematisch waere dass eine negative
203 Kursivierung, da die Y-Achse auf dem Bildschirm von oben nach unten verlaeuft.
204 Drehwinkel: Positiv bedeutet auf dem Bildschirm sichtbare Linksdrehung.
207 class GeoStat
{ // Geometrischer Status fuer ein Rect
211 double nTan
; // tan(nShearAngle)
212 double nSin
; // sin(nRotationAngle)
213 double nCos
; // cos(nRotationAngle)
214 bool bMirrored
; // Horizontal gespiegelt? (ni)
216 GeoStat(): nRotationAngle(0),nShearAngle(0),nTan(0.0),nSin(0.0),nCos(1.0),bMirrored(false) {}
221 Polygon
Rect2Poly(const Rectangle
& rRect
, const GeoStat
& rGeo
);
222 void Poly2Rect(const Polygon
& rPol
, Rectangle
& rRect
, GeoStat
& rGeo
);
224 SVX_DLLPUBLIC
void OrthoDistance8(const Point
& rPt0
, Point
& rPt
, bool bBigOrtho
);
225 SVX_DLLPUBLIC
void OrthoDistance4(const Point
& rPt0
, Point
& rPt
, bool bBigOrtho
);
227 // Multiplikation und anschliessende Division.
228 // Rechnung und Zwischenergebnis sind BigInt.
229 SVX_DLLPUBLIC
long BigMulDiv(long nVal
, long nMul
, long nDiv
);
231 // Fehlerbehaftetes Kuerzen einer Fraction.
232 // nDigits gibt an, wieviele signifikante Stellen in
233 // Zaehler/Nenner mindestens erhalten bleiben sollen.
234 void Kuerzen(Fraction
& rF
, unsigned nDigits
);
241 FrPair() : aX(0,1),aY(0,1) {}
242 FrPair(const Fraction
& rBoth
) : aX(rBoth
),aY(rBoth
) {}
243 FrPair(const Fraction
& rX
, const Fraction
& rY
) : aX(rX
),aY(rY
) {}
244 FrPair(long nMul
, long nDiv
) : aX(nMul
,nDiv
),aY(nMul
,nDiv
) {}
245 FrPair(long xMul
, long xDiv
, long yMul
, long yDiv
): aX(xMul
,xDiv
),aY(yMul
,yDiv
) {}
246 const Fraction
& X() const { return aX
; }
247 const Fraction
& Y() const { return aY
; }
248 Fraction
& X() { return aX
; }
249 Fraction
& Y() { return aY
; }
252 // Fuer die Umrechnung von Masseinheiten
253 SVX_DLLPUBLIC FrPair
GetMapFactor(MapUnit eS
, MapUnit eD
);
254 FrPair
GetMapFactor(FieldUnit eS
, FieldUnit eD
);
256 inline bool IsMetric(MapUnit eU
) {
257 return (eU
==MAP_100TH_MM
|| eU
==MAP_10TH_MM
|| eU
==MAP_MM
|| eU
==MAP_CM
);
260 inline bool IsInch(MapUnit eU
) {
261 return (eU
==MAP_1000TH_INCH
|| eU
==MAP_100TH_INCH
|| eU
==MAP_10TH_INCH
|| eU
==MAP_INCH
||
262 eU
==MAP_POINT
|| eU
==MAP_TWIP
);
265 inline bool IsMetric(FieldUnit eU
) {
266 return (eU
==FUNIT_MM
|| eU
==FUNIT_CM
|| eU
==FUNIT_M
|| eU
==FUNIT_KM
|| eU
==FUNIT_100TH_MM
);
269 inline bool IsInch(FieldUnit eU
) {
270 return (eU
==FUNIT_TWIP
|| eU
==FUNIT_POINT
|| eU
==FUNIT_PICA
||
271 eU
==FUNIT_INCH
|| eU
==FUNIT_FOOT
|| eU
==FUNIT_MILE
);
274 class SVX_DLLPUBLIC SdrFormatter
{
286 SVX_DLLPRIVATE
void Undirty();
287 SVX_DLLPRIVATE
void ForceUndirty() const { if (bDirty
) const_cast<SdrFormatter
*>(this)->Undirty(); }
289 SdrFormatter(MapUnit eSrc
, MapUnit eDst
)
302 SdrFormatter(MapUnit eSrc
, FieldUnit eDst
) { eSrcMU
=eSrc
; bSrcFU
=false; eDstFU
=eDst
; bDstFU
=true; bDirty
=true; }
303 SdrFormatter(FieldUnit eSrc
, MapUnit eDst
) { eSrcFU
=eSrc
; bSrcFU
=true; eDstMU
=eDst
; bDstFU
=false; bDirty
=true; }
304 SdrFormatter(FieldUnit eSrc
, FieldUnit eDst
) { eSrcFU
=eSrc
; bSrcFU
=true; eDstFU
=eDst
; bDstFU
=true; bDirty
=true; }
305 void SetSourceUnit(MapUnit eSrc
) { eSrcMU
=eSrc
; bSrcFU
=false; bDirty
=true; }
306 void SetSourceUnit(FieldUnit eSrc
) { eSrcFU
=eSrc
; bSrcFU
=true; bDirty
=true; }
307 void SetDestinationUnit(MapUnit eDst
) { eDstMU
=eDst
; bDstFU
=false; bDirty
=true; }
308 void SetDestinationUnit(FieldUnit eDst
) { eDstFU
=eDst
; bDstFU
=true; bDirty
=true; }
309 void TakeStr(long nVal
, OUString
& rStr
) const;
310 static void TakeUnitStr(MapUnit eUnit
, OUString
& rStr
);
311 static void TakeUnitStr(FieldUnit eUnit
, OUString
& rStr
);
312 static OUString
GetUnitStr(MapUnit eUnit
) { OUString aStr
; TakeUnitStr(eUnit
,aStr
); return aStr
; }
313 static OUString
GetUnitStr(FieldUnit eUnit
) { OUString aStr
; TakeUnitStr(eUnit
,aStr
); return aStr
; }
318 #endif // INCLUDED_SVX_SVDTRANS_HXX
320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */