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