tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / drawinglayer / source / primitive2d / gridprimitive2d.cxx
blob1a996188f03c273d2921abddfa313dbd4b0244e3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawinglayer/primitive2d/gridprimitive2d.hxx>
21 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
22 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
23 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
24 #include <drawinglayer/geometry/viewinformation2d.hxx>
25 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
26 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 #include <utility>
30 using namespace com::sun::star;
33 namespace drawinglayer::primitive2d
35 Primitive2DReference GridPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
37 if(!(!rViewInformation.getViewport().isEmpty() && getWidth() > 0.0 && getHeight() > 0.0))
38 return nullptr;
40 // decompose grid matrix to get logic size
41 basegfx::B2DVector aScale, aTranslate;
42 double fRotate, fShearX;
43 getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
45 // create grid matrix which transforms from scaled logic to view
46 basegfx::B2DHomMatrix aRST(basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
47 fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
48 aRST *= rViewInformation.getObjectToViewTransformation();
50 // get step widths
51 double fStepX(getWidth());
52 double fStepY(getHeight());
53 const double fMinimalStep(10.0);
55 // guarantee a step width of 10.0
56 if(basegfx::fTools::less(fStepX, fMinimalStep))
58 fStepX = fMinimalStep;
61 if(basegfx::fTools::less(fStepY, fMinimalStep))
63 fStepY = fMinimalStep;
66 // get relative distances in view coordinates
67 double fViewStepX((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(fStepX, 0.0)).getLength());
68 double fViewStepY((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fStepY)).getLength());
69 double fSmallStepX(1.0), fViewSmallStepX(1.0), fSmallStepY(1.0), fViewSmallStepY(1.0);
70 sal_uInt32 nSmallStepsX(0), nSmallStepsY(0);
72 // setup subdivisions
73 if(getSubdivisionsX())
75 fSmallStepX = fStepX / getSubdivisionsX();
76 fViewSmallStepX = fViewStepX / getSubdivisionsX();
79 if(getSubdivisionsY())
81 fSmallStepY = fStepY / getSubdivisionsY();
82 fViewSmallStepY = fViewStepY / getSubdivisionsY();
85 // correct step width
86 while(fViewStepX < getSmallestViewDistance())
88 fViewStepX *= 2.0;
89 fStepX *= 2.0;
92 while(fViewStepY < getSmallestViewDistance())
94 fViewStepY *= 2.0;
95 fStepY *= 2.0;
98 // correct small step width
99 if(getSubdivisionsX())
101 while(fViewSmallStepX < getSmallestSubdivisionViewDistance())
103 fViewSmallStepX *= 2.0;
104 fSmallStepX *= 2.0;
107 nSmallStepsX = static_cast<sal_uInt32>(fStepX / fSmallStepX);
110 if(getSubdivisionsY())
112 while(fViewSmallStepY < getSmallestSubdivisionViewDistance())
114 fViewSmallStepY *= 2.0;
115 fSmallStepY *= 2.0;
118 nSmallStepsY = static_cast<sal_uInt32>(fStepY / fSmallStepY);
121 // calculate extended viewport in which grid points may lie at all
122 basegfx::B2DRange aExtendedViewport;
124 if(rViewInformation.getDiscreteViewport().isEmpty())
126 // not set, use logic size to travel over all potential grid points
127 aExtendedViewport = basegfx::B2DRange(0.0, 0.0, aScale.getX(), aScale.getY());
129 else
131 // transform unit range to discrete view
132 aExtendedViewport = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
133 basegfx::B2DHomMatrix aTrans(rViewInformation.getObjectToViewTransformation() * getTransform());
134 aExtendedViewport.transform(aTrans);
136 // intersect with visible part
137 aExtendedViewport.intersect(rViewInformation.getDiscreteViewport());
139 if(!aExtendedViewport.isEmpty())
141 // convert back and apply scale
142 aTrans.invert();
143 aTrans.scale(aScale.getX(), aScale.getY());
144 aExtendedViewport.transform(aTrans);
146 // crop start/end in X/Y to multiples of logical step width
147 const double fHalfCrossSize((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(3.0, 0.0)).getLength());
148 const double fMinX(floor((aExtendedViewport.getMinX() - fHalfCrossSize) / fStepX) * fStepX);
149 const double fMaxX(ceil((aExtendedViewport.getMaxX() + fHalfCrossSize) / fStepX) * fStepX);
150 const double fMinY(floor((aExtendedViewport.getMinY() - fHalfCrossSize) / fStepY) * fStepY);
151 const double fMaxY(ceil((aExtendedViewport.getMaxY() + fHalfCrossSize) / fStepY) * fStepY);
153 // put to aExtendedViewport and crop on object logic size
154 aExtendedViewport = basegfx::B2DRange(
155 std::max(fMinX, 0.0),
156 std::max(fMinY, 0.0),
157 std::min(fMaxX, aScale.getX()),
158 std::min(fMaxY, aScale.getY()));
162 if(aExtendedViewport.isEmpty())
163 return nullptr;
165 // prepare point vectors for point and cross markers
166 std::vector< basegfx::B2DPoint > aPositionsPoint;
167 std::vector< basegfx::B2DPoint > aPositionsCross;
169 for(double fX(aExtendedViewport.getMinX()); fX < aExtendedViewport.getMaxX(); fX += fStepX)
171 const bool bXZero(basegfx::fTools::equalZero(fX));
173 for(double fY(aExtendedViewport.getMinY()); fY < aExtendedViewport.getMaxY(); fY += fStepY)
175 const bool bYZero(basegfx::fTools::equalZero(fY));
177 if(!bXZero && !bYZero)
179 // get discrete position and test against 3x3 area surrounding it
180 // since it's a cross
181 const double fHalfCrossSize(3.0 * 0.5);
182 const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY));
183 const basegfx::B2DRange aDiscreteRangeCross(
184 aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize,
185 aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize);
187 if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross))
189 const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
190 aPositionsCross.push_back(aLogicPos);
194 if(getSubdivisionsX() && !bYZero)
196 double fF(fX + fSmallStepX);
198 for(sal_uInt32 a(1); a < nSmallStepsX && fF < aExtendedViewport.getMaxX(); a++, fF += fSmallStepX)
200 const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY));
202 if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
204 const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
205 aPositionsPoint.push_back(aLogicPos);
210 if(getSubdivisionsY() && !bXZero)
212 double fF(fY + fSmallStepY);
214 for(sal_uInt32 a(1); a < nSmallStepsY && fF < aExtendedViewport.getMaxY(); a++, fF += fSmallStepY)
216 const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF));
218 if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
220 const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
221 aPositionsPoint.push_back(aLogicPos);
228 // prepare return value
229 const sal_uInt32 nCountPoint(aPositionsPoint.size());
230 const sal_uInt32 nCountCross(aPositionsCross.size());
232 // add PointArrayPrimitive2D if point markers were added
233 Primitive2DContainer aContainer;
234 if(nCountPoint)
236 aContainer.push_back(new PointArrayPrimitive2D(std::move(aPositionsPoint), getBColor()));
239 // add MarkerArrayPrimitive2D if cross markers were added
240 if(!nCountCross)
241 return new GroupPrimitive2D(std::move(aContainer));
243 if(!getSubdivisionsX() && !getSubdivisionsY())
245 // no subdivisions, so fall back to points at grid positions, no need to
246 // visualize a difference between divisions and sub-divisions
247 aContainer.push_back(new PointArrayPrimitive2D(std::move(aPositionsCross), getBColor()));
249 else
251 aContainer.push_back(new MarkerArrayPrimitive2D(std::move(aPositionsCross), getCrossMarker()));
253 return new GroupPrimitive2D(std::move(aContainer));
256 GridPrimitive2D::GridPrimitive2D(
257 basegfx::B2DHomMatrix aTransform,
258 double fWidth,
259 double fHeight,
260 double fSmallestViewDistance,
261 double fSmallestSubdivisionViewDistance,
262 sal_uInt32 nSubdivisionsX,
263 sal_uInt32 nSubdivisionsY,
264 const basegfx::BColor& rBColor,
265 const BitmapEx& rCrossMarker)
266 : maTransform(std::move(aTransform)),
267 mfWidth(fWidth),
268 mfHeight(fHeight),
269 mfSmallestViewDistance(fSmallestViewDistance),
270 mfSmallestSubdivisionViewDistance(fSmallestSubdivisionViewDistance),
271 mnSubdivisionsX(nSubdivisionsX),
272 mnSubdivisionsY(nSubdivisionsY),
273 maBColor(rBColor),
274 maCrossMarker(rCrossMarker)
278 bool GridPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
280 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
282 const GridPrimitive2D& rCompare = static_cast<const GridPrimitive2D&>(rPrimitive);
284 return (getTransform() == rCompare.getTransform()
285 && getWidth() == rCompare.getWidth()
286 && getHeight() == rCompare.getHeight()
287 && getSmallestViewDistance() == rCompare.getSmallestViewDistance()
288 && getSmallestSubdivisionViewDistance() == rCompare.getSmallestSubdivisionViewDistance()
289 && getSubdivisionsX() == rCompare.getSubdivisionsX()
290 && getSubdivisionsY() == rCompare.getSubdivisionsY()
291 && getBColor() == rCompare.getBColor()
292 && getCrossMarker() == rCompare.getCrossMarker());
295 return false;
298 basegfx::B2DRange GridPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
300 // get object's range
301 basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
302 aUnitRange.transform(getTransform());
304 // intersect with visible part
305 aUnitRange.intersect(rViewInformation.getViewport());
307 return aUnitRange;
310 void GridPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
312 if(getBuffered2DDecomposition())
314 if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
316 // conditions of last local decomposition have changed, delete
317 const_cast< GridPrimitive2D* >(this)->setBuffered2DDecomposition(nullptr);
321 if(!getBuffered2DDecomposition())
323 // remember ViewRange and ViewTransformation
324 const_cast< GridPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
325 const_cast< GridPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
328 // use parent implementation
329 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
332 // provide unique ID
333 sal_uInt32 GridPrimitive2D::getPrimitive2DID() const
335 return PRIMITIVE2D_ID_GRIDPRIMITIVE2D;
338 } // end of namespace
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */