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