summaryrefslogtreecommitdiff
path: root/svx/inc/svx/svdtrans.hxx
blob: 568212a2287ebbcdb5589d07e69bc7af60707a06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SVDTRANS_HXX
#define _SVDTRANS_HXX

#include <tools/gen.hxx>
#include <tools/poly.hxx>
#include <tools/fract.hxx>

#include <vcl/mapmod.hxx>
#include <tools/string.hxx>
#include "svx/svxdllapi.h"

#include <vcl/field.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////

// Winkelangaben der DrawingEngine sind 1/100 Degree
// #i19054# nowhere used, removed // const int nWinkDiv=100;
// Um Winkel der DrawingEngine mit den Trigonometrischen Funktionen
// verarbeiten zu koennen, muessen sie zunaest ins Bogenmass umgerechnet
// werden. Dies gestaltet sich recht einfach mit der folgenden Konstanten
// nPi180. Sei nWink ein Winkel in 1/100 Deg so schreibt man z.B.:
//   double nSin=sin(nWink*nPi180);
// Rueckwandlung entsprechend durch Teilen.
const double nPi=3.14159265358979323846;
const double nPi180=0.000174532925199432957692222; // Bei zuweing Stellen ist tan(4500*nPi180)!=1.0

// Der maximale Shearwinkel
#define SDRMAXSHEAR 8900

class XPolygon;
class XPolyPolygon;

inline long Round(double a) { return a>0.0 ? (long)(a+0.5) : -(long)((-a)+0.5); }

inline void MoveRect(Rectangle& rRect, const Size& S)    { rRect.Move(S.Width(),S.Height()); }
inline void MovePoint(Point& rPnt, const Size& S)        { rPnt.X()+=S.Width(); rPnt.Y()+=S.Height(); }
inline void MovePoly(Polygon& rPoly, const Size& S)      { rPoly.Move(S.Width(),S.Height()); }
inline void MovePoly(PolyPolygon& rPoly, const Size& S)  { rPoly.Move(S.Width(),S.Height()); }
void MoveXPoly(XPolygon& rPoly, const Size& S);
void MoveXPoly(XPolyPolygon& rPoly, const Size& S);

SVX_DLLPUBLIC void ResizeRect(Rectangle& rRect, const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bNoJustify = false);
inline void ResizePoint(Point& rPnt, const Point& rRef, Fraction xFact, Fraction yFact);
void ResizePoly(Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
void ResizePoly(PolyPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);
void ResizeXPoly(XPolyPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact);

inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs);
SVX_DLLPUBLIC void RotatePoly(Polygon& rPoly, const Point& rRef, double sn, double cs);
void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs);
void RotatePoly(PolyPolygon& rPoly, const Point& rRef, double sn, double cs);
void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs);

// MirrorRect macht nur Sinn bei Spiegelachsen
// mit einem durch 45 Degree teilbaren Winkel!
void MirrorRect(Rectangle& rRect, const Point& rRef1, const Point& rRef2, bool bNoJustify); // ni.
void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2);
void MirrorPoly(Polygon& rPoly, const Point& rRef1, const Point& rRef2);
void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2);
void MirrorPoly(PolyPolygon& rPoly, const Point& rRef1, const Point& rRef2);
void MirrorXPoly(XPolyPolygon& rPoly, const Point& rRef1, const Point& rRef2);

inline void ShearPoint(Point& rPnt, const Point& rRef, double tn, bool bVShear = false);
SVX_DLLPUBLIC void ShearPoly(Polygon& rPoly, const Point& rRef, double tn, bool bVShear = false);
void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear = false);
void ShearPoly(PolyPolygon& rPoly, const Point& rRef, double tn, bool bVShear = false);
void ShearXPoly(XPolyPolygon& rPoly, const Point& rRef, double tn, bool bVShear = false);

// rPnt.X bzw rPnt.Y wird auf rCenter.X bzw. rCenter.Y gesetzt!
// anschliessend muss rPnt nur noch um rCenter gedreht werden.
// Der Rueckgabewinkel ist ausnahmsweise in Rad.
inline double GetCrookAngle(Point& rPnt, const Point& rCenter, const Point& rRad, bool bVertical);
// Die folgenden Methoden behandeln einen Punkt eines XPolygons, wobei die
// benachbarten Kontrollpunkte des eigentlichen Punktes ggf. in pC1/pC2
// uebergeben werden. Ueber rSin/rCos wird gleichzeitig sin(nWink) und cos(nWink)
// zurueckgegeben.
// Der Rueckgabewinkel ist hier ebenfalls in Rad.
double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
                         const Point& rRad, double& rSin, double& rCos, bool bVert);
double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
                        const Point& rRad, double& rSin, double& rCos, bool bVert);
double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
                          const Point& rRad, double& rSin, double& rCos, bool bVert,
                          const Rectangle rRefRect);

void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect);

void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert);
void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const Rectangle rRefRect);

/**************************************************************************************************/
/*  Inline                                                                                        */
/**************************************************************************************************/

inline void ResizePoint(Point& rPnt, const Point& rRef, Fraction xFact, Fraction yFact)
{
    if (xFact.GetDenominator()==0) xFact=Fraction(xFact.GetNumerator(),1); // DivZero abfangen
    if (yFact.GetDenominator()==0) yFact=Fraction(yFact.GetNumerator(),1); // DivZero abfangen
    rPnt.X()=rRef.X()+ Round(((double)(rPnt.X()-rRef.X())*xFact.GetNumerator())/xFact.GetDenominator());
    rPnt.Y()=rRef.Y()+ Round(((double)(rPnt.Y()-rRef.Y())*yFact.GetNumerator())/yFact.GetDenominator());
}

inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs)
{
    long dx=rPnt.X()-rRef.X();
    long dy=rPnt.Y()-rRef.Y();
    rPnt.X()=Round(rRef.X()+dx*cs+dy*sn);
    rPnt.Y()=Round(rRef.Y()+dy*cs-dx*sn);
}

inline void ShearPoint(Point& rPnt, const Point& rRef, double tn, bool bVShear)
{
    if (!bVShear) { // Horizontal
        if (rPnt.Y()!=rRef.Y()) { // sonst nicht noetig
            rPnt.X()-=Round((rPnt.Y()-rRef.Y())*tn);
        }
    } else { // ansonsten vertikal
        if (rPnt.X()!=rRef.X()) { // sonst nicht noetig
            rPnt.Y()-=Round((rPnt.X()-rRef.X())*tn);
        }
    }
}

inline double GetCrookAngle(Point& rPnt, const Point& rCenter, const Point& rRad, bool bVertical)
{
    double nWink;
    if (bVertical) {
        long dy=rPnt.Y()-rCenter.Y();
        nWink=(double)dy/(double)rRad.Y();
        rPnt.Y()=rCenter.Y();
    } else {
        long dx=rCenter.X()-rPnt.X();
        nWink=(double)dx/(double)rRad.X();
        rPnt.X()=rCenter.X();
    }
    return nWink;
}

/**************************************************************************************************/
/**************************************************************************************************/

// Y-Achse zeigt nach unten! Die Funktion negiert bei der
// Winkelberechnung die Y-Achse, sodass GetAngle(Point(0,-1))=90.00deg.
// GetAngle(Point(0,0)) liefert 0.
// Der Rueckgabewert liegt im Bereich -180.00..179.99 Degree und
// ist in 1/100 Degree angegeben.
SVX_DLLPUBLIC long GetAngle(const Point& rPnt);
long NormAngle180(long a); // Winkel normalisieren auf -180.00..179.99
SVX_DLLPUBLIC long NormAngle360(long a); // Winkel normalisieren auf    0.00..359.99
sal_uInt16 GetAngleSector(long nWink); // Sektor im kartesischen Koordinatensystem bestimmen
// Berechnet die Laenge von (0,0) via a^2 + b^2 = c^2
// Zur Vermeidung von Ueberlaeufen werden ggf. einige Stellen ignoriert.
long GetLen(const Point& rPnt);

/*
  Transformation eines Rechtecks in ein Polygon unter            ------------
  Anwendung der Winkelparameter aus GeoStat.                    /1        2/
  Referenzpunkt ist stets der Punkt 0, also die linke          /          /
  obere Ecke des Ausgangsrects.                               /          /
  Bei der Berechnung des Polygons ist die Reihenfolge        /          /
  (erst Shear, dann Rotation vorgegeben).                   /          / \
                                                           /          /   |
  A) Ausgangsrechteck aRect  B) Nach Anwendung von Shear  /0        3/  Rot|
  +------------------+       --------------------        ------------  ------
  |0                1|        \0                1\       C) Nach Anwendung
  |                  |         \                  \      von Rotate
  |                  |       |  \                  \
  |3                2|       |   \3                2\
  +------------------+       |    --------------------
                             |Shr |
  Bei Rueckkonvertierung des        Polygons in ein Rect ist die Reihenfolge
  zwangslaeufig umgekehrt:
  - Berechnung des Drehwinkels: Winkel der Strecke 0-1 aus Abb. C) zum Horizont
  - Rueckdrehung des geshearten Rects (man erhaelt Abb B))
  - Bestimmung der Breite des Rects=Laenge der Strecke 0-1 aus Abb. B)
  - Bestimmung der Hoehe des Rects=vertikaler Abstand zwischen den Punkten
    0 und 3 aus Abb. B)
  - Bestimmung des Shear-Winkels aus der Strecke 0-3 zur Senkrechten.
  Es ist darauf zu achten, dass das Polygon bei einer zwischenzeitlichen
  Transformation evtl. gespiegelt wurde (Mirror oder Resize mit neg. Faktor).
  In diesem Fall muss zunaecht eine Normalisierung durch Vertauschung der
  Punkte (z.B. 0 mit 3 und 1 mit 2) durchgefuehrt werden, damit der
  Richtungssinn im Polygon wieder stimmig ist.
  Hinweis: Positiver Shear-Winkel bedeutet Shear mit auf dem Bildschirm
  sichtbarer positiver Kursivierung. Mathematisch waere dass eine negative
  Kursivierung, da die Y-Achse auf dem Bildschirm von oben nach unten verlaeuft.
  Drehwinkel: Positiv bedeutet auf dem Bildschirm sichtbare Linksdrehung.
*/

class GeoStat { // Geometrischer Status fuer ein Rect
public:
    long     nDrehWink;
    long     nShearWink;
    double   nTan;      // tan(nShearWink)
    double   nSin;      // sin(nDrehWink)
    double   nCos;      // cos(nDrehWink)
    bool     bMirrored; // Horizontal gespiegelt? (ni)
public:
    GeoStat(): nDrehWink(0),nShearWink(0),nTan(0.0),nSin(0.0),nCos(1.0),bMirrored(false) {}
    void RecalcSinCos();
    void RecalcTan();
};

Polygon Rect2Poly(const Rectangle& rRect, const GeoStat& rGeo);
void Poly2Rect(const Polygon& rPol, Rectangle& rRect, GeoStat& rGeo);

SVX_DLLPUBLIC void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho);
SVX_DLLPUBLIC void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho);

// Multiplikation und anschliessende Division.
// Rechnung und Zwischenergebnis sind BigInt.
SVX_DLLPUBLIC long BigMulDiv(long nVal, long nMul, long nDiv);

// Fehlerbehaftetes Kuerzen einer Fraction.
// nDigits gibt an, wieviele signifikante Stellen in
// Zaehler/Nenner mindestens erhalten bleiben sollen.
void Kuerzen(Fraction& rF, unsigned nDigits);


class FrPair {
    Fraction aX;
    Fraction aY;
public:
    FrPair()                                          : aX(0,1),aY(0,1)             {}
    FrPair(const Fraction& rBoth)                     : aX(rBoth),aY(rBoth)         {}
    FrPair(const Fraction& rX, const Fraction& rY)    : aX(rX),aY(rY)               {}
    FrPair(long nMul, long nDiv)                      : aX(nMul,nDiv),aY(nMul,nDiv) {}
    FrPair(long xMul, long xDiv, long yMul, long yDiv): aX(xMul,xDiv),aY(yMul,yDiv) {}
    const Fraction& X() const { return aX; }
    const Fraction& Y() const { return aY; }
    Fraction& X()             { return aX; }
    Fraction& Y()             { return aY; }
};

// Fuer die Umrechnung von Masseinheiten
SVX_DLLPUBLIC FrPair GetMapFactor(MapUnit eS, MapUnit eD);
FrPair GetMapFactor(MapUnit eS, FieldUnit eD);
FrPair GetMapFactor(FieldUnit eS, MapUnit eD);
FrPair GetMapFactor(FieldUnit eS, FieldUnit eD);

inline bool IsMetric(MapUnit eU) {
    return (eU==MAP_100TH_MM || eU==MAP_10TH_MM || eU==MAP_MM || eU==MAP_CM);
}

inline bool IsInch(MapUnit eU) {
    return (eU==MAP_1000TH_INCH || eU==MAP_100TH_INCH || eU==MAP_10TH_INCH || eU==MAP_INCH ||
            eU==MAP_POINT       || eU==MAP_TWIP);
}

inline bool IsMetric(FieldUnit eU) {
    return (eU==FUNIT_MM || eU==FUNIT_CM || eU==FUNIT_M || eU==FUNIT_KM || eU==FUNIT_100TH_MM);
}

inline bool IsInch(FieldUnit eU) {
    return (eU==FUNIT_TWIP || eU==FUNIT_POINT || eU==FUNIT_PICA ||
            eU==FUNIT_INCH || eU==FUNIT_FOOT || eU==FUNIT_MILE);
}

class SVX_DLLPUBLIC SdrFormatter {
    Fraction  aScale;
    long      nMul_;
    long      nDiv_;
    short     nKomma_;
    bool      bSrcFU;
    bool      bDstFU;
    bool      bDirty;
    MapUnit   eSrcMU;
    MapUnit   eDstMU;
    FieldUnit eSrcFU;
    FieldUnit eDstFU;
private:
    SVX_DLLPRIVATE void Undirty();
    SVX_DLLPRIVATE void ForceUndirty() const { if (bDirty) ((SdrFormatter*)this)->Undirty(); }
public:
    SdrFormatter(MapUnit eSrc, MapUnit eDst)     { eSrcMU=eSrc; bSrcFU=sal_False; eDstMU=eDst; bDstFU=sal_False; bDirty=sal_True; }
    SdrFormatter(MapUnit eSrc, FieldUnit eDst)   { eSrcMU=eSrc; bSrcFU=sal_False; eDstFU=eDst; bDstFU=sal_True;  bDirty=sal_True; }
    SdrFormatter(FieldUnit eSrc, MapUnit eDst)   { eSrcFU=eSrc; bSrcFU=sal_True;  eDstMU=eDst; bDstFU=sal_False; bDirty=sal_True; }
    SdrFormatter(FieldUnit eSrc, FieldUnit eDst) { eSrcFU=eSrc; bSrcFU=sal_True;  eDstFU=eDst; bDstFU=sal_True;  bDirty=sal_True; }
    void SetSourceUnit(MapUnit eSrc)        { eSrcMU=eSrc; bSrcFU=sal_False; bDirty=sal_True; }
    void SetSourceUnit(FieldUnit eSrc)      { eSrcFU=eSrc; bSrcFU=sal_True;  bDirty=sal_True; }
    void SetDestinationUnit(MapUnit eDst)   { eDstMU=eDst; bDstFU=sal_False; bDirty=sal_True; }
    void SetDestinationUnit(FieldUnit eDst) { eDstFU=eDst; bDstFU=sal_True;  bDirty=sal_True; }
    void TakeStr(long nVal, XubString& rStr) const;
    static void TakeUnitStr(MapUnit eUnit, XubString& rStr);
    static void TakeUnitStr(FieldUnit eUnit, XubString& rStr);
    static XubString GetUnitStr(MapUnit eUnit)   { XubString aStr; TakeUnitStr(eUnit,aStr); return aStr; }
    static XubString GetUnitStr(FieldUnit eUnit) { XubString aStr; TakeUnitStr(eUnit,aStr); return aStr; }
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //_SVDTRANS_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */