xref: /trunk/main/drawinglayer/source/primitive2d/gridprimitive2d.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_drawinglayer.hxx"
30 
31 #include <drawinglayer/primitive2d/gridprimitive2d.hxx>
32 #include <basegfx/tools/canvastools.hxx>
33 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
35 #include <drawinglayer/geometry/viewinformation2d.hxx>
36 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
37 #include <basegfx/matrix/b2dhommatrixtools.hxx>
38 
39 //////////////////////////////////////////////////////////////////////////////
40 
41 using namespace com::sun::star;
42 
43 //////////////////////////////////////////////////////////////////////////////
44 
45 namespace drawinglayer
46 {
47     namespace primitive2d
48     {
49         Primitive2DSequence GridPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
50         {
51             Primitive2DSequence aRetval;
52 
53             if(!rViewInformation.getViewport().isEmpty() && getWidth() > 0.0 && getHeight() > 0.0)
54             {
55                 // decompose grid matrix to get logic size
56                 basegfx::B2DVector aScale, aTranslate;
57                 double fRotate, fShearX;
58                 getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
59 
60                 // create grid matrix which transforms from scaled logic to view
61                 basegfx::B2DHomMatrix aRST(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
62                     fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
63                 aRST *= rViewInformation.getObjectToViewTransformation();
64 
65                 // get step widths
66                 double fStepX(getWidth());
67                 double fStepY(getHeight());
68                 const double fMinimalStep(10.0);
69 
70                 // guarantee a step width of 10.0
71                 if(basegfx::fTools::less(fStepX, fMinimalStep))
72                 {
73                     fStepX = fMinimalStep;
74                 }
75 
76                 if(basegfx::fTools::less(fStepY, fMinimalStep))
77                 {
78                     fStepY = fMinimalStep;
79                 }
80 
81                 // get relative distances in view coordinates
82                 double fViewStepX((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(fStepX, 0.0)).getLength());
83                 double fViewStepY((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fStepY)).getLength());
84                 double fSmallStepX(1.0), fViewSmallStepX(1.0), fSmallStepY(1.0), fViewSmallStepY(1.0);
85                 sal_uInt32 nSmallStepsX(0L), nSmallStepsY(0L);
86 
87                 // setup subdivisions
88                 if(getSubdivisionsX())
89                 {
90                     fSmallStepX = fStepX / getSubdivisionsX();
91                     fViewSmallStepX = fViewStepX / getSubdivisionsX();
92                 }
93 
94                 if(getSubdivisionsY())
95                 {
96                     fSmallStepY = fStepY / getSubdivisionsY();
97                     fViewSmallStepY = fViewStepY / getSubdivisionsY();
98                 }
99 
100                 // correct step width
101                 while(fViewStepX < getSmallestViewDistance())
102                 {
103                     fViewStepX *= 2.0;
104                     fStepX *= 2.0;
105                 }
106 
107                 while(fViewStepY < getSmallestViewDistance())
108                 {
109                     fViewStepY *= 2.0;
110                     fStepY *= 2.0;
111                 }
112 
113                 // correct small step width
114                 if(getSubdivisionsX())
115                 {
116                     while(fViewSmallStepX < getSmallestSubdivisionViewDistance())
117                     {
118                         fViewSmallStepX *= 2.0;
119                         fSmallStepX *= 2.0;
120                     }
121 
122                     nSmallStepsX = (sal_uInt32)(fStepX / fSmallStepX);
123                 }
124 
125                 if(getSubdivisionsY())
126                 {
127                     while(fViewSmallStepY < getSmallestSubdivisionViewDistance())
128                     {
129                         fViewSmallStepY *= 2.0;
130                         fSmallStepY *= 2.0;
131                     }
132 
133                     nSmallStepsY = (sal_uInt32)(fStepY / fSmallStepY);
134                 }
135 
136                 // prepare point vectors for point and cross markers
137                 std::vector< basegfx::B2DPoint > aPositionsPoint;
138                 std::vector< basegfx::B2DPoint > aPositionsCross;
139 
140                 for(double fX(0.0); fX < aScale.getX(); fX += fStepX)
141                 {
142                     const bool bXZero(basegfx::fTools::equalZero(fX));
143 
144                     for(double fY(0.0); fY < aScale.getY(); fY += fStepY)
145                     {
146                         const bool bYZero(basegfx::fTools::equalZero(fY));
147 
148                         if(!bXZero && !bYZero)
149                         {
150                             // get discrete position and test against 3x3 area surrounding it
151                             // since it's a cross
152                             const double fHalfCrossSize(3.0 * 0.5);
153                             const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY));
154                             const basegfx::B2DRange aDiscreteRangeCross(
155                                 aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize,
156                                 aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize);
157 
158                             if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross))
159                             {
160                                 const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
161                                 aPositionsCross.push_back(aLogicPos);
162                             }
163                         }
164 
165                         if(getSubdivisionsX() && !bYZero)
166                         {
167                             double fF(fX + fSmallStepX);
168 
169                             for(sal_uInt32 a(1L); a < nSmallStepsX && fF < aScale.getX(); a++, fF += fSmallStepX)
170                             {
171                                 const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY));
172 
173                                 if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
174                                 {
175                                     const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
176                                     aPositionsPoint.push_back(aLogicPos);
177                                 }
178                             }
179                         }
180 
181                         if(getSubdivisionsY() && !bXZero)
182                         {
183                             double fF(fY + fSmallStepY);
184 
185                             for(sal_uInt32 a(1L); a < nSmallStepsY && fF < aScale.getY(); a++, fF += fSmallStepY)
186                             {
187                                 const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF));
188 
189                                 if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
190                                 {
191                                     const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
192                                     aPositionsPoint.push_back(aLogicPos);
193                                 }
194                             }
195                         }
196                     }
197                 }
198 
199                 // prepare return value
200                 const sal_uInt32 nCountPoint(aPositionsPoint.size());
201                 const sal_uInt32 nCountCross(aPositionsCross.size());
202                 const sal_uInt32 nRetvalCount((nCountPoint ? 1 : 0) + (nCountCross ? 1 : 0));
203                 sal_uInt32 nInsertCounter(0);
204 
205                 aRetval.realloc(nRetvalCount);
206 
207                 // add PointArrayPrimitive2D if point markers were added
208                 if(nCountPoint)
209                 {
210                     aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsPoint, getBColor()));
211                 }
212 
213                 // add MarkerArrayPrimitive2D if cross markers were added
214                 if(nCountCross)
215                 {
216                     if(!getSubdivisionsX() && !getSubdivisionsY())
217                     {
218                         // no subdivisions, so fall back to points at grid positions, no need to
219                         // visualize a difference between divisions and sub-divisions
220                         aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsCross, getBColor()));
221                     }
222                     else
223                     {
224                         aRetval[nInsertCounter++] = Primitive2DReference(new MarkerArrayPrimitive2D(aPositionsCross, getCrossMarker()));
225                     }
226                 }
227             }
228 
229             return aRetval;
230         }
231 
232         GridPrimitive2D::GridPrimitive2D(
233             const basegfx::B2DHomMatrix& rTransform,
234             double fWidth,
235             double fHeight,
236             double fSmallestViewDistance,
237             double fSmallestSubdivisionViewDistance,
238             sal_uInt32 nSubdivisionsX,
239             sal_uInt32 nSubdivisionsY,
240             const basegfx::BColor& rBColor,
241             const BitmapEx& rCrossMarker)
242         :   BufferedDecompositionPrimitive2D(),
243             maTransform(rTransform),
244             mfWidth(fWidth),
245             mfHeight(fHeight),
246             mfSmallestViewDistance(fSmallestViewDistance),
247             mfSmallestSubdivisionViewDistance(fSmallestSubdivisionViewDistance),
248             mnSubdivisionsX(nSubdivisionsX),
249             mnSubdivisionsY(nSubdivisionsY),
250             maBColor(rBColor),
251             maCrossMarker(rCrossMarker),
252             maLastObjectToViewTransformation(),
253             maLastViewport()
254         {
255         }
256 
257         bool GridPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
258         {
259             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
260             {
261                 const GridPrimitive2D& rCompare = (GridPrimitive2D&)rPrimitive;
262 
263                 return (getTransform() == rCompare.getTransform()
264                     && getWidth() == rCompare.getWidth()
265                     && getHeight() == rCompare.getHeight()
266                     && getSmallestViewDistance() == rCompare.getSmallestViewDistance()
267                     && getSmallestSubdivisionViewDistance() == rCompare.getSmallestSubdivisionViewDistance()
268                     && getSubdivisionsX() == rCompare.getSubdivisionsX()
269                     && getSubdivisionsY() == rCompare.getSubdivisionsY()
270                     && getBColor() == rCompare.getBColor()
271                     && getCrossMarker() == rCompare.getCrossMarker());
272             }
273 
274             return false;
275         }
276 
277         basegfx::B2DRange GridPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
278         {
279             // get object's range
280             basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
281             aUnitRange.transform(getTransform());
282 
283             // intersect with visible part
284             aUnitRange.intersect(rViewInformation.getViewport());
285 
286             return aUnitRange;
287         }
288 
289         Primitive2DSequence GridPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
290         {
291             ::osl::MutexGuard aGuard( m_aMutex );
292 
293             if(getBuffered2DDecomposition().hasElements())
294             {
295                 if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
296                 {
297                     // conditions of last local decomposition have changed, delete
298                     const_cast< GridPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
299                 }
300             }
301 
302             if(!getBuffered2DDecomposition().hasElements())
303             {
304                 // remember ViewRange and ViewTransformation
305                 const_cast< GridPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
306                 const_cast< GridPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
307             }
308 
309             // use parent implementation
310             return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
311         }
312 
313         // provide unique ID
314         ImplPrimitrive2DIDBlock(GridPrimitive2D, PRIMITIVE2D_ID_GRIDPRIMITIVE2D)
315 
316     } // end of namespace primitive2d
317 } // end of namespace drawinglayer
318 
319 //////////////////////////////////////////////////////////////////////////////
320 // eof
321