Branch data Line data Source code
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 : :
29 : : /** Osnola:
30 : : IMPORTANT NOTE: some Quickdraw lines/frames can not be "quickly" drawn exactly:
31 : : for instance, when PenSize=(1,1), the line from (0,0) to (8,0)
32 : : corresponds to the rectangle (0,0)(0,1)(9,1)(9,0), which can only be drawn
33 : : by drawing a rectangle. Drawing a non horizontal/vertical will imply to draw
34 : : a polygon, ...
35 : : Similarly, drawing the frame of a rectangle (0,0)(0,1)(9,1)(9,0) when PenSize=(1,1),
36 : : will imply to draw a rectangle (0.5,0.5)(0.5,8.5)(8.5,8.5)(8.5,0.5) with linewidth=1...
37 : :
38 : : Here, we choose:
39 : : - for horizontal/vertical lines and line with length less than five to draw the real line,
40 : : - in the other case, we keep the same shape (even if this means some "bad" coordinates)
41 : : */
42 : :
43 : : #include <basegfx/polygon/b2dpolygon.hxx>
44 : : #include <basegfx/polygon/b2dpolygontools.hxx>
45 : : #include "shape.hxx"
46 : :
47 : : namespace PictReaderShapePrivate {
48 : : /** returns an inside rectangle knowing the penSize in order to obtain the ``correct'' position
49 : : when we draw a frame in wide length*/
50 : 0 : Rectangle contractRectangle(bool drawFrame, Rectangle const &rect, Size const &pSize) {
51 [ # # ]: 0 : if (!drawFrame) return rect;
52 : 0 : long penSize=(pSize.Width()+pSize.Height())/2;
53 [ # # ]: 0 : if (2*penSize > rect.Right()-rect.Left()) penSize = (rect.Right()-rect.Left()+1)/2;
54 [ # # ]: 0 : if (2*penSize > rect.Bottom()-rect.Top()) penSize = (rect.Bottom()-rect.Top()+1)/2;
55 : 0 : long const X[2] = { rect.Left()+penSize/2, rect.Right()-(penSize+1)/2 };
56 : 0 : long const Y[2] = { rect.Top()+penSize/2, rect.Bottom()-(penSize+1)/2 };
57 [ # # ]: 0 : return Rectangle(Point(X[0],Y[0]), Point(X[1], Y[1]));
58 : : }
59 : : }
60 : :
61 : : namespace PictReaderShape {
62 : : //--------- draws a horizontal/vertical/small line (by creating a "rectangle/polygon") ---------
63 : 159 : bool drawLineHQ(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) {
64 : 159 : long dir[2] = { dest.X()-orig.X(), dest.Y()-orig.Y() };
65 : 159 : bool vertic = dir[0] == 0;
66 : 159 : bool horiz = dir[1] == 0;
67 [ + + ][ + - ]: 159 : if (!horiz && !vertic && dir[0]*dir[0]+dir[1]*dir[1] > 25) return false;
[ + + ]
68 : :
69 : 99 : long X[2]={ orig.X(), dest.X() }, Y[2] = { orig.Y(), dest.Y() };
70 : : using namespace basegfx;
71 [ + - ]: 99 : B2DPolygon poly;
72 [ + + ][ + - ]: 99 : if (horiz || vertic) {
73 [ + + ]: 99 : if (horiz) {
74 [ + + ]: 69 : if (X[0] < X[1]) X[1]+=pSize.Width();
75 : 36 : else X[0]+=pSize.Width();
76 : 69 : Y[1] += pSize.Height();
77 : : }
78 : : else {
79 [ + + ]: 30 : if (Y[0] < Y[1]) Y[1]+=pSize.Height();
80 : 15 : else Y[0]+=pSize.Height();
81 : 30 : X[1] += pSize.Width();
82 : : }
83 [ + - ][ + - ]: 99 : poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0]));
84 [ + - ][ + - ]: 99 : poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1]));
85 [ + - ]: 99 : poly.append(B2DPoint(X[0], Y[0]));
86 : : }
87 : : else {
88 : 0 : long origPt[4][2] = { { orig.X(), orig.Y() }, { orig.X()+pSize.Width(), orig.Y() },
89 : 0 : { orig.X()+pSize.Width(), orig.Y()+pSize.Height() },
90 : 0 : { orig.X(), orig.Y()+pSize.Height() }};
91 [ # # ][ # # ]: 0 : long origAvoid = dir[0] > 0 ? (dir[1] > 0 ? 2 : 1) : (dir[1] > 0 ? 3 : 0);
[ # # ]
92 : 0 : long destPt[4][2] = { { dest.X(), dest.Y() }, { dest.X()+pSize.Width(), dest.Y() },
93 : 0 : { dest.X()+pSize.Width(), dest.Y()+pSize.Height() },
94 : 0 : { dest.X(), dest.Y()+pSize.Height() }};
95 [ # # ]: 0 : for (int w = origAvoid+1; w < origAvoid+4; w++) {
96 : 0 : int wh = (w%4);
97 [ # # ]: 0 : poly.append(B2DPoint(origPt[wh][0], origPt[wh][1]));
98 : : }
99 [ # # ]: 0 : for (int w = origAvoid+3; w < origAvoid+6; w++) {
100 : 0 : int wh = (w%4);
101 [ # # ]: 0 : poly.append(B2DPoint(destPt[wh][0], destPt[wh][1]));
102 : : }
103 : 0 : int wh = (origAvoid+1)%4;
104 [ # # ]: 0 : poly.append(B2DPoint(origPt[wh][0], origPt[wh][1]));
105 : : }
106 : :
107 : : // HACK: here we use the line coloring when drawing the shape
108 : : // must be changed if other parameter are changed to draw
109 : : // a line/fill shape
110 : 99 : Color oldFColor = dev->GetFillColor(), oldLColor = dev->GetLineColor();
111 [ + - ][ + - ]: 99 : dev->SetFillColor(oldLColor); dev->SetLineColor(Color(COL_TRANSPARENT));
112 [ + - ]: 99 : dev->DrawPolygon(poly);
113 [ + - ][ + - ]: 99 : dev->SetLineColor(oldLColor); dev->SetFillColor(oldFColor);
114 [ + - ]: 159 : return true;
115 : : }
116 : :
117 : : //
118 : : //-------------------- draws a line --------------------
119 : : //
120 : 159 : void drawLine(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) {
121 [ + - ][ + + ]: 318 : if (drawLineHQ(dev,orig,dest,pSize)) return;
122 : :
123 : 60 : long penSize=(pSize.Width()+pSize.Height())/2;
124 : 60 : long decal[2] = { pSize.Width()/2, pSize.Height()/2};
125 : :
126 : : using namespace basegfx;
127 [ + - ]: 60 : B2DPolygon poly;
128 [ + - ]: 60 : poly.append(B2DPoint(double(orig.X()+decal[0]), double(orig.Y()+decal[1])));
129 [ + - ]: 60 : poly.append(B2DPoint(double(dest.X()+decal[0]), double(dest.Y()+decal[1])));
130 [ + - ][ + - ]: 159 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
131 : : }
132 : :
133 : : //-------------------- draws a rectangle --------------------
134 : : /* Note(checkme): contradically with the QuickDraw's reference 3-23, it seems better to consider
135 : : that the frame/content of a rectangle appears inside the given rectangle. Does a conversion
136 : : appear between the pascal functions and the data stored in the file ? */
137 : 0 : void drawRectangle(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &pSize) {
138 : 0 : int penSize=(pSize.Width()+pSize.Height())/2;
139 [ # # ]: 0 : Rectangle rect = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
140 : 0 : long const X[2] = { rect.Left(), rect.Right() };
141 : 0 : long const Y[2] = { rect.Top(), rect.Bottom() };
142 : :
143 : : using namespace basegfx;
144 [ # # ]: 0 : B2DPolygon poly;
145 [ # # ][ # # ]: 0 : poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0]));
146 [ # # ][ # # ]: 0 : poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1]));
147 [ # # ]: 0 : poly.append(B2DPoint(X[0], Y[0]));
148 : :
149 [ # # ]: 0 : if (drawFrame)
150 [ # # ]: 0 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
151 : : else
152 [ # # ][ # # ]: 0 : dev->DrawPolygon(poly);
153 : 0 : }
154 : :
155 : : //-------------------- draws an ellipse --------------------
156 : 0 : void drawEllipse(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &pSize) {
157 : 0 : int penSize=(pSize.Width()+pSize.Height())/2;
158 [ # # ]: 0 : Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
159 : : using namespace basegfx;
160 : 0 : long const X[2] = { oval.Left(), oval.Right() };
161 : 0 : long const Y[2] = { oval.Top(), oval.Bottom() };
162 : 0 : B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0]));
163 [ # # ]: 0 : B2DPolygon poly = tools::createPolygonFromEllipse(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0]));
164 [ # # ]: 0 : if (drawFrame)
165 [ # # ]: 0 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
166 : : else
167 [ # # ][ # # ]: 0 : dev->DrawPolygon(poly);
168 : 0 : }
169 : :
170 : : //-------------------- draws an arc/pie --------------------
171 : 0 : void drawArc(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, const double& angle1, const double& angle2, Size const &pSize) {
172 : 0 : int penSize=(pSize.Width()+pSize.Height())/2;
173 [ # # ]: 0 : Rectangle arc = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
174 : : using namespace basegfx;
175 : :
176 : 0 : double const PI2 = M_PI/2.0;
177 : : // pict angle are CW with 0 at twelve oclock ( with Y-axis inverted)...
178 : 0 : double angl1 = angle1-PI2;
179 : 0 : double angl2 = angle2-PI2;
180 : 0 : long const X[2] = { arc.Left(), arc.Right() };
181 : 0 : long const Y[2] = { arc.Top(), arc.Bottom() };
182 : 0 : B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0]));
183 : :
184 : : // We must have angl1 between 0 and F_2PI
185 [ # # ]: 0 : while (angl1 < 0.0) { angl1 += F_2PI; angl2 += F_2PI; }
186 [ # # ]: 0 : while (angl1 >= F_2PI) { angl1 -= F_2PI; angl2 -= F_2PI; }
187 : :
188 : : // if this happen, we want a complete circle
189 : : // so we set angl2 slightly less than angl1
190 [ # # ]: 0 : if (angl2 >= angl1+F_2PI) angl2 = angl1-0.001;
191 : :
192 : : // We must have angl2 between 0 and F_2PI
193 [ # # ]: 0 : while (angl2 < 0.0) angl2 += F_2PI;
194 [ # # ]: 0 : while (angl2 >= F_2PI) angl2 -= F_2PI;
195 : :
196 [ # # ]: 0 : B2DPolygon poly = tools::createPolygonFromEllipseSegment(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0]), angl1, angl2);
197 [ # # ]: 0 : if (drawFrame)
198 [ # # ]: 0 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
199 : : else {
200 : : // adds circle's center
201 [ # # ]: 0 : poly.append(center);
202 [ # # ]: 0 : dev->DrawPolygon(poly);
203 [ # # ]: 0 : }
204 : 0 : }
205 : : //-------------------- draws a rectangle with round corner --------------------
206 : 0 : void drawRoundRectangle(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &ovalSize, Size const &pSize) {
207 : 0 : int penSize=(pSize.Width()+pSize.Height())/2;
208 [ # # ]: 0 : Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
209 : 0 : int ovalW=ovalSize.Width(), ovalH=ovalSize.Height();
210 : : using namespace basegfx;
211 : 0 : long const X[2] = { oval.Left(), oval.Right() };
212 : 0 : long const Y[2] = { oval.Top(), oval.Bottom() };
213 : 0 : long width = X[1] - X[0];
214 : 0 : long height = Y[1] - Y[0];
215 [ # # ]: 0 : if (ovalW > width) ovalW = static_cast< int >( width );
216 [ # # ]: 0 : if (ovalH > height) ovalH = static_cast< int >( height );
217 : :
218 [ # # ]: 0 : B2DRectangle rect(B2DPoint(X[0],Y[0]), B2DPoint(X[1],Y[1]));
219 [ # # ][ # # ]: 0 : B2DPolygon poly = tools::createPolygonFromRect(rect, (width != 0.0) ? ovalW/width : 0.0, (height != 0.0) ? ovalH/height : 0.0);
[ # # ]
220 : :
221 [ # # ]: 0 : if (drawFrame)
222 [ # # ]: 0 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
223 : : else
224 [ # # ][ # # ]: 0 : dev->DrawPolygon(poly);
225 : 0 : }
226 : :
227 : : //-------------------- draws a polygon --------------------
228 : 87 : void drawPolygon(VirtualDevice *dev, bool drawFrame, Polygon const &orig, Size const &pSize) {
229 : 87 : int penSize=(pSize.Width()+pSize.Height())/2;
230 : 87 : long decalTL[2] = {0, 0}, decalBR[2] = { pSize.Width(), pSize.Height()};
231 [ - + ]: 87 : if (drawFrame) {
232 : 0 : decalTL[0] += penSize/2; decalTL[1] += penSize/2;
233 : 0 : decalBR[0] -= (penSize+1)/2; decalBR[1] -= (penSize+1)/2;
234 : : }
235 : : // Quickdraw Drawing Reference 3-82: the pen size is only used for frame
236 : 87 : else decalBR[0] = decalBR[1] = 0;
237 : :
238 : :
239 [ + - ]: 87 : int numPt = orig.GetSize();
240 [ + - ]: 174 : if (numPt <= 1) return;
241 : :
242 : : // we compute a barycenter of the point to define the extended direction of each point
243 : 87 : double bary[2] = { 0.0, 0.0 };
244 [ + + ]: 3990 : for (int i = 0; i < numPt; i++) {
245 [ + - ]: 3903 : Point const &pt = orig.GetPoint(i);
246 : 3903 : bary[0] += double(pt.X()); bary[1] += double(pt.Y());
247 : : }
248 : 87 : bary[0]/=double(numPt); bary[1]/=double(numPt);
249 : :
250 : : using namespace basegfx;
251 [ + - ]: 87 : B2DPolygon poly;
252 : : // Note: a polygon can be open, so we must not close it when we draw the frame
253 [ + + ]: 3990 : for (int i = 0; i < numPt; i++) {
254 [ + - ]: 3903 : Point const &pt = orig.GetPoint(i);
255 [ + + ]: 3903 : double x = (double(pt.X()) < bary[0]) ? pt.X()+decalTL[0] : pt.X()+decalBR[0];
256 [ + + ]: 3903 : double y = (double(pt.Y()) < bary[1]) ? pt.Y()+decalTL[1] : pt.Y()+decalBR[1];
257 [ + - ]: 3903 : poly.append(B2DPoint(x, y));
258 : : }
259 [ - + ]: 87 : if (drawFrame)
260 [ # # ]: 0 : dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
261 : : else
262 [ + - ][ + - ]: 87 : dev->DrawPolygon(poly);
263 : : }
264 : :
265 : :
266 : : }
267 : :
268 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|