Branch data Line data Source code
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 : : #include <drawinglayer/primitive2d/gridprimitive2d.hxx>
21 : : #include <basegfx/tools/canvastools.hxx>
22 : : #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
23 : : #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
24 : : #include <drawinglayer/geometry/viewinformation2d.hxx>
25 : : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
26 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 : :
28 : : //////////////////////////////////////////////////////////////////////////////
29 : :
30 : : using namespace com::sun::star;
31 : :
32 : : //////////////////////////////////////////////////////////////////////////////
33 : :
34 : : namespace drawinglayer
35 : : {
36 : : namespace primitive2d
37 : : {
38 : 90 : Primitive2DSequence GridPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
39 : : {
40 : 90 : Primitive2DSequence aRetval;
41 : :
42 [ + - ][ - + ]: 90 : if(!rViewInformation.getViewport().isEmpty() && getWidth() > 0.0 && getHeight() > 0.0)
[ # # ][ # # ]
[ - + ][ + - ]
43 : : {
44 : : // decompose grid matrix to get logic size
45 : 0 : basegfx::B2DVector aScale, aTranslate;
46 : : double fRotate, fShearX;
47 [ # # ]: 0 : getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
48 : :
49 : : // create grid matrix which transforms from scaled logic to view
50 : : basegfx::B2DHomMatrix aRST(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
51 [ # # ]: 0 : fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
52 [ # # ][ # # ]: 0 : aRST *= rViewInformation.getObjectToViewTransformation();
53 : :
54 : : // get step widths
55 : 0 : double fStepX(getWidth());
56 : 0 : double fStepY(getHeight());
57 : 0 : const double fMinimalStep(10.0);
58 : :
59 : : // guarantee a step width of 10.0
60 [ # # ]: 0 : if(basegfx::fTools::less(fStepX, fMinimalStep))
61 : : {
62 : 0 : fStepX = fMinimalStep;
63 : : }
64 : :
65 [ # # ]: 0 : if(basegfx::fTools::less(fStepY, fMinimalStep))
66 : : {
67 : 0 : fStepY = fMinimalStep;
68 : : }
69 : :
70 : : // get relative distances in view coordinates
71 [ # # ][ # # ]: 0 : double fViewStepX((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(fStepX, 0.0)).getLength());
[ # # ]
72 [ # # ][ # # ]: 0 : double fViewStepY((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fStepY)).getLength());
[ # # ]
73 : 0 : double fSmallStepX(1.0), fViewSmallStepX(1.0), fSmallStepY(1.0), fViewSmallStepY(1.0);
74 : 0 : sal_uInt32 nSmallStepsX(0L), nSmallStepsY(0L);
75 : :
76 : : // setup subdivisions
77 [ # # ]: 0 : if(getSubdivisionsX())
78 : : {
79 : 0 : fSmallStepX = fStepX / getSubdivisionsX();
80 : 0 : fViewSmallStepX = fViewStepX / getSubdivisionsX();
81 : : }
82 : :
83 [ # # ]: 0 : if(getSubdivisionsY())
84 : : {
85 : 0 : fSmallStepY = fStepY / getSubdivisionsY();
86 : 0 : fViewSmallStepY = fViewStepY / getSubdivisionsY();
87 : : }
88 : :
89 : : // correct step width
90 [ # # ]: 0 : while(fViewStepX < getSmallestViewDistance())
91 : : {
92 : 0 : fViewStepX *= 2.0;
93 : 0 : fStepX *= 2.0;
94 : : }
95 : :
96 [ # # ]: 0 : while(fViewStepY < getSmallestViewDistance())
97 : : {
98 : 0 : fViewStepY *= 2.0;
99 : 0 : fStepY *= 2.0;
100 : : }
101 : :
102 : : // correct small step width
103 [ # # ]: 0 : if(getSubdivisionsX())
104 : : {
105 [ # # ]: 0 : while(fViewSmallStepX < getSmallestSubdivisionViewDistance())
106 : : {
107 : 0 : fViewSmallStepX *= 2.0;
108 : 0 : fSmallStepX *= 2.0;
109 : : }
110 : :
111 : 0 : nSmallStepsX = (sal_uInt32)(fStepX / fSmallStepX);
112 : : }
113 : :
114 [ # # ]: 0 : if(getSubdivisionsY())
115 : : {
116 [ # # ]: 0 : while(fViewSmallStepY < getSmallestSubdivisionViewDistance())
117 : : {
118 : 0 : fViewSmallStepY *= 2.0;
119 : 0 : fSmallStepY *= 2.0;
120 : : }
121 : :
122 : 0 : nSmallStepsY = (sal_uInt32)(fStepY / fSmallStepY);
123 : : }
124 : :
125 : : // prepare point vectors for point and cross markers
126 [ # # ]: 0 : std::vector< basegfx::B2DPoint > aPositionsPoint;
127 [ # # ]: 0 : std::vector< basegfx::B2DPoint > aPositionsCross;
128 : :
129 [ # # ]: 0 : for(double fX(0.0); fX < aScale.getX(); fX += fStepX)
130 : : {
131 : 0 : const bool bXZero(basegfx::fTools::equalZero(fX));
132 : :
133 [ # # ]: 0 : for(double fY(0.0); fY < aScale.getY(); fY += fStepY)
134 : : {
135 : 0 : const bool bYZero(basegfx::fTools::equalZero(fY));
136 : :
137 [ # # ][ # # ]: 0 : if(!bXZero && !bYZero)
138 : : {
139 : : // get discrete position and test against 3x3 area surrounding it
140 : : // since it's a cross
141 : 0 : const double fHalfCrossSize(3.0 * 0.5);
142 [ # # ]: 0 : const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY));
143 : : const basegfx::B2DRange aDiscreteRangeCross(
144 : 0 : aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize,
145 [ # # ]: 0 : aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize);
146 : :
147 [ # # ][ # # ]: 0 : if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross))
[ # # ]
148 : : {
149 [ # # ][ # # ]: 0 : const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
150 [ # # ]: 0 : aPositionsCross.push_back(aLogicPos);
151 : 0 : }
152 : : }
153 : :
154 [ # # ][ # # ]: 0 : if(getSubdivisionsX() && !bYZero)
[ # # ]
155 : : {
156 : 0 : double fF(fX + fSmallStepX);
157 : :
158 [ # # ][ # # ]: 0 : for(sal_uInt32 a(1L); a < nSmallStepsX && fF < aScale.getX(); a++, fF += fSmallStepX)
[ # # ]
159 : : {
160 [ # # ]: 0 : const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY));
161 : :
162 [ # # ][ # # ]: 0 : if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
[ # # ]
163 : : {
164 [ # # ][ # # ]: 0 : const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
165 [ # # ]: 0 : aPositionsPoint.push_back(aLogicPos);
166 : : }
167 : 0 : }
168 : : }
169 : :
170 [ # # ][ # # ]: 0 : if(getSubdivisionsY() && !bXZero)
[ # # ]
171 : : {
172 : 0 : double fF(fY + fSmallStepY);
173 : :
174 [ # # ][ # # ]: 0 : for(sal_uInt32 a(1L); a < nSmallStepsY && fF < aScale.getY(); a++, fF += fSmallStepY)
[ # # ]
175 : : {
176 [ # # ]: 0 : const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF));
177 : :
178 [ # # ][ # # ]: 0 : if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
[ # # ]
179 : : {
180 [ # # ][ # # ]: 0 : const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
181 [ # # ]: 0 : aPositionsPoint.push_back(aLogicPos);
182 : : }
183 : 0 : }
184 : : }
185 : : }
186 : : }
187 : :
188 : : // prepare return value
189 : 0 : const sal_uInt32 nCountPoint(aPositionsPoint.size());
190 : 0 : const sal_uInt32 nCountCross(aPositionsCross.size());
191 [ # # ][ # # ]: 0 : const sal_uInt32 nRetvalCount((nCountPoint ? 1 : 0) + (nCountCross ? 1 : 0));
192 : 0 : sal_uInt32 nInsertCounter(0);
193 : :
194 [ # # ]: 0 : aRetval.realloc(nRetvalCount);
195 : :
196 : : // add PointArrayPrimitive2D if point markers were added
197 [ # # ]: 0 : if(nCountPoint)
198 : : {
199 [ # # ][ # # ]: 0 : aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsPoint, getBColor()));
[ # # ][ # # ]
[ # # ]
200 : : }
201 : :
202 : : // add MarkerArrayPrimitive2D if cross markers were added
203 [ # # ]: 0 : if(nCountCross)
204 : : {
205 [ # # ][ # # ]: 0 : if(!getSubdivisionsX() && !getSubdivisionsY())
[ # # ]
206 : : {
207 : : // no subdivisions, so fall back to points at grid positions, no need to
208 : : // visualize a difference between divisions and sub-divisions
209 [ # # ][ # # ]: 0 : aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsCross, getBColor()));
[ # # ][ # # ]
[ # # ]
210 : : }
211 : : else
212 : : {
213 [ # # ][ # # ]: 0 : aRetval[nInsertCounter++] = Primitive2DReference(new MarkerArrayPrimitive2D(aPositionsCross, getCrossMarker()));
[ # # ][ # # ]
[ # # ]
214 : : }
215 [ # # ]: 0 : }
216 : : }
217 : :
218 : 90 : return aRetval;
219 : : }
220 : :
221 : 1120 : GridPrimitive2D::GridPrimitive2D(
222 : : const basegfx::B2DHomMatrix& rTransform,
223 : : double fWidth,
224 : : double fHeight,
225 : : double fSmallestViewDistance,
226 : : double fSmallestSubdivisionViewDistance,
227 : : sal_uInt32 nSubdivisionsX,
228 : : sal_uInt32 nSubdivisionsY,
229 : : const basegfx::BColor& rBColor,
230 : : const BitmapEx& rCrossMarker)
231 : : : BufferedDecompositionPrimitive2D(),
232 : : maTransform(rTransform),
233 : : mfWidth(fWidth),
234 : : mfHeight(fHeight),
235 : : mfSmallestViewDistance(fSmallestViewDistance),
236 : : mfSmallestSubdivisionViewDistance(fSmallestSubdivisionViewDistance),
237 : : mnSubdivisionsX(nSubdivisionsX),
238 : : mnSubdivisionsY(nSubdivisionsY),
239 : : maBColor(rBColor),
240 : : maCrossMarker(rCrossMarker),
241 : : maLastObjectToViewTransformation(),
242 [ + - ][ + - ]: 1120 : maLastViewport()
[ + - ][ + - ]
243 : : {
244 : 1120 : }
245 : :
246 : 754 : bool GridPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
247 : : {
248 [ + - ]: 754 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
249 : : {
250 : 754 : const GridPrimitive2D& rCompare = (GridPrimitive2D&)rPrimitive;
251 : :
252 : 754 : return (getTransform() == rCompare.getTransform()
253 : 270 : && getWidth() == rCompare.getWidth()
254 : 270 : && getHeight() == rCompare.getHeight()
255 : 270 : && getSmallestViewDistance() == rCompare.getSmallestViewDistance()
256 : 270 : && getSmallestSubdivisionViewDistance() == rCompare.getSmallestSubdivisionViewDistance()
257 : 270 : && getSubdivisionsX() == rCompare.getSubdivisionsX()
258 : 270 : && getSubdivisionsY() == rCompare.getSubdivisionsY()
259 : 270 : && getBColor() == rCompare.getBColor()
260 [ + - ][ + + : 2644 : && getCrossMarker() == rCompare.getCrossMarker());
+ - + - +
- + - + -
+ - + - ]
261 : : }
262 : :
263 : 754 : return false;
264 : : }
265 : :
266 : 2060 : basegfx::B2DRange GridPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
267 : : {
268 : : // get object's range
269 : 2060 : basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
270 : 2060 : aUnitRange.transform(getTransform());
271 : :
272 : : // intersect with visible part
273 : 2060 : aUnitRange.intersect(rViewInformation.getViewport());
274 : :
275 : 2060 : return aUnitRange;
276 : : }
277 : :
278 : 90 : Primitive2DSequence GridPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
279 : : {
280 [ + - ]: 90 : ::osl::MutexGuard aGuard( m_aMutex );
281 : :
282 [ - + ]: 90 : if(getBuffered2DDecomposition().hasElements())
283 : : {
284 [ # # ][ # # ]: 0 : if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
285 : : {
286 : : // conditions of last local decomposition have changed, delete
287 [ # # ][ # # ]: 0 : const_cast< GridPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
[ # # ]
288 : : }
289 : : }
290 : :
291 [ + - ]: 90 : if(!getBuffered2DDecomposition().hasElements())
292 : : {
293 : : // remember ViewRange and ViewTransformation
294 [ + - ][ + - ]: 90 : const_cast< GridPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
295 [ + - ]: 90 : const_cast< GridPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
296 : : }
297 : :
298 : : // use parent implementation
299 [ + - ][ + - ]: 90 : return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
300 : : }
301 : :
302 : : // provide unique ID
303 : 2448 : ImplPrimitrive2DIDBlock(GridPrimitive2D, PRIMITIVE2D_ID_GRIDPRIMITIVE2D)
304 : :
305 : : } // end of namespace primitive2d
306 : : } // end of namespace drawinglayer
307 : :
308 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|