1464702f4SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3464702f4SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4464702f4SAndrew Rist * or more contributor license agreements. See the NOTICE file 5464702f4SAndrew Rist * distributed with this work for additional information 6464702f4SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7464702f4SAndrew Rist * to you under the Apache License, Version 2.0 (the 8464702f4SAndrew Rist * "License"); you may not use this file except in compliance 9464702f4SAndrew Rist * with the License. You may obtain a copy of the License at 10464702f4SAndrew Rist * 11464702f4SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12464702f4SAndrew Rist * 13464702f4SAndrew Rist * Unless required by applicable law or agreed to in writing, 14464702f4SAndrew Rist * software distributed under the License is distributed on an 15464702f4SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16464702f4SAndrew Rist * KIND, either express or implied. See the License for the 17464702f4SAndrew Rist * specific language governing permissions and limitations 18464702f4SAndrew Rist * under the License. 19464702f4SAndrew Rist * 20464702f4SAndrew Rist *************************************************************/ 21464702f4SAndrew Rist 22464702f4SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <drawinglayer/primitive2d/sceneprimitive2d.hxx> 28cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 29cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 30cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 31cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx> 32cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 33cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 34cdf0e10cSrcweir #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 35cdf0e10cSrcweir #include <drawinglayer/processor3d/zbufferprocessor3d.hxx> 36cdf0e10cSrcweir #include <drawinglayer/processor3d/shadow3dextractor.hxx> 37cdf0e10cSrcweir #include <drawinglayer/geometry/viewinformation2d.hxx> 38cdf0e10cSrcweir #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 39cdf0e10cSrcweir #include <svtools/optionsdrawinglayer.hxx> 40cdf0e10cSrcweir #include <drawinglayer/processor3d/geometry2dextractor.hxx> 41cdf0e10cSrcweir #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 42cdf0e10cSrcweir 43cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 44cdf0e10cSrcweir 45cdf0e10cSrcweir using namespace com::sun::star; 46cdf0e10cSrcweir 47cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 48cdf0e10cSrcweir 49cdf0e10cSrcweir namespace drawinglayer 50cdf0e10cSrcweir { 51cdf0e10cSrcweir namespace primitive2d 52cdf0e10cSrcweir { impGetShadow3D(const geometry::ViewInformation2D &) const53cdf0e10cSrcweir bool ScenePrimitive2D::impGetShadow3D(const geometry::ViewInformation2D& /*rViewInformation*/) const 54cdf0e10cSrcweir { 55cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 56cdf0e10cSrcweir 57cdf0e10cSrcweir // create on demand 58cdf0e10cSrcweir if(!mbShadow3DChecked && getChildren3D().hasElements()) 59cdf0e10cSrcweir { 60cdf0e10cSrcweir basegfx::B3DVector aLightNormal; 61cdf0e10cSrcweir const double fShadowSlant(getSdrSceneAttribute().getShadowSlant()); 62cdf0e10cSrcweir const basegfx::B3DRange aScene3DRange(primitive3d::getB3DRangeFromPrimitive3DSequence(getChildren3D(), getViewInformation3D())); 63cdf0e10cSrcweir 64cdf0e10cSrcweir if(maSdrLightingAttribute.getLightVector().size()) 65cdf0e10cSrcweir { 66cdf0e10cSrcweir // get light normal from first light and normalize 67cdf0e10cSrcweir aLightNormal = maSdrLightingAttribute.getLightVector()[0].getDirection(); 68cdf0e10cSrcweir aLightNormal.normalize(); 69cdf0e10cSrcweir } 70cdf0e10cSrcweir 71cdf0e10cSrcweir // create shadow extraction processor 72cdf0e10cSrcweir processor3d::Shadow3DExtractingProcessor aShadowProcessor( 73cdf0e10cSrcweir getViewInformation3D(), 74cdf0e10cSrcweir getObjectTransformation(), 75cdf0e10cSrcweir aLightNormal, 76cdf0e10cSrcweir fShadowSlant, 77cdf0e10cSrcweir aScene3DRange); 78cdf0e10cSrcweir 79cdf0e10cSrcweir // process local primitives 80cdf0e10cSrcweir aShadowProcessor.process(getChildren3D()); 81cdf0e10cSrcweir 82cdf0e10cSrcweir // fetch result and set checked flag 83cdf0e10cSrcweir const_cast< ScenePrimitive2D* >(this)->maShadowPrimitives = aShadowProcessor.getPrimitive2DSequence(); 84cdf0e10cSrcweir const_cast< ScenePrimitive2D* >(this)->mbShadow3DChecked = true; 85cdf0e10cSrcweir } 86cdf0e10cSrcweir 87cdf0e10cSrcweir // return if there are shadow primitives 88cdf0e10cSrcweir return maShadowPrimitives.hasElements(); 89cdf0e10cSrcweir } 90cdf0e10cSrcweir calculateDiscreteSizes(const geometry::ViewInformation2D & rViewInformation,basegfx::B2DRange & rDiscreteRange,basegfx::B2DRange & rVisibleDiscreteRange,basegfx::B2DRange & rUnitVisibleRange) const91cdf0e10cSrcweir void ScenePrimitive2D::calculateDiscreteSizes( 92cdf0e10cSrcweir const geometry::ViewInformation2D& rViewInformation, 93cdf0e10cSrcweir basegfx::B2DRange& rDiscreteRange, 94cdf0e10cSrcweir basegfx::B2DRange& rVisibleDiscreteRange, 95cdf0e10cSrcweir basegfx::B2DRange& rUnitVisibleRange) const 96cdf0e10cSrcweir { 97cdf0e10cSrcweir // use unit range and transform to discrete coordinates 98cdf0e10cSrcweir rDiscreteRange = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); 99cdf0e10cSrcweir rDiscreteRange.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation()); 100cdf0e10cSrcweir 101cdf0e10cSrcweir // clip it against discrete Viewport (if set) 102cdf0e10cSrcweir rVisibleDiscreteRange = rDiscreteRange; 103cdf0e10cSrcweir 104cdf0e10cSrcweir if(!rViewInformation.getViewport().isEmpty()) 105cdf0e10cSrcweir { 106cdf0e10cSrcweir rVisibleDiscreteRange.intersect(rViewInformation.getDiscreteViewport()); 107cdf0e10cSrcweir } 108cdf0e10cSrcweir 109cdf0e10cSrcweir if(rVisibleDiscreteRange.isEmpty()) 110cdf0e10cSrcweir { 111cdf0e10cSrcweir rUnitVisibleRange = rVisibleDiscreteRange; 112cdf0e10cSrcweir } 113cdf0e10cSrcweir else 114cdf0e10cSrcweir { 115cdf0e10cSrcweir // create UnitVisibleRange containing unit range values [0.0 .. 1.0] describing 116cdf0e10cSrcweir // the relative position of rVisibleDiscreteRange inside rDiscreteRange 117cdf0e10cSrcweir const double fDiscreteScaleFactorX(basegfx::fTools::equalZero(rDiscreteRange.getWidth()) ? 1.0 : 1.0 / rDiscreteRange.getWidth()); 118cdf0e10cSrcweir const double fDiscreteScaleFactorY(basegfx::fTools::equalZero(rDiscreteRange.getHeight()) ? 1.0 : 1.0 / rDiscreteRange.getHeight()); 119cdf0e10cSrcweir 120cdf0e10cSrcweir const double fMinX(basegfx::fTools::equal(rVisibleDiscreteRange.getMinX(), rDiscreteRange.getMinX()) 121cdf0e10cSrcweir ? 0.0 122cdf0e10cSrcweir : (rVisibleDiscreteRange.getMinX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX); 123cdf0e10cSrcweir const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange.getMinY(), rDiscreteRange.getMinY()) 124cdf0e10cSrcweir ? 0.0 125cdf0e10cSrcweir : (rVisibleDiscreteRange.getMinY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY); 126cdf0e10cSrcweir 127cdf0e10cSrcweir const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxX(), rDiscreteRange.getMaxX()) 128cdf0e10cSrcweir ? 1.0 129cdf0e10cSrcweir : (rVisibleDiscreteRange.getMaxX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX); 130cdf0e10cSrcweir const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxY(), rDiscreteRange.getMaxY()) 131cdf0e10cSrcweir ? 1.0 132cdf0e10cSrcweir : (rVisibleDiscreteRange.getMaxY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY); 133cdf0e10cSrcweir 134cdf0e10cSrcweir rUnitVisibleRange = basegfx::B2DRange(fMinX, fMinY, fMaxX, fMaxY); 135cdf0e10cSrcweir } 136cdf0e10cSrcweir } 137cdf0e10cSrcweir create2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const138cdf0e10cSrcweir Primitive2DSequence ScenePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 139cdf0e10cSrcweir { 140cdf0e10cSrcweir Primitive2DSequence aRetval; 141cdf0e10cSrcweir 142cdf0e10cSrcweir // create 2D shadows from contained 3D primitives. This creates the shadow primitives on demand and tells if 143cdf0e10cSrcweir // there are some or not. Do this at start, the shadow might still be visible even when the scene is not 144cdf0e10cSrcweir if(impGetShadow3D(rViewInformation)) 145cdf0e10cSrcweir { 146cdf0e10cSrcweir // test visibility 147cdf0e10cSrcweir const basegfx::B2DRange aShadow2DRange( 148cdf0e10cSrcweir getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation)); 149cdf0e10cSrcweir const basegfx::B2DRange aViewRange( 150cdf0e10cSrcweir rViewInformation.getViewport()); 151cdf0e10cSrcweir 152cdf0e10cSrcweir if(aViewRange.isEmpty() || aShadow2DRange.overlaps(aViewRange)) 153cdf0e10cSrcweir { 154cdf0e10cSrcweir // add extracted 2d shadows (before 3d scene creations itself) 155cdf0e10cSrcweir aRetval = maShadowPrimitives; 156cdf0e10cSrcweir } 157cdf0e10cSrcweir } 158cdf0e10cSrcweir 159cdf0e10cSrcweir // get the involved ranges (see helper method calculateDiscreteSizes for details) 160cdf0e10cSrcweir basegfx::B2DRange aDiscreteRange; 161cdf0e10cSrcweir basegfx::B2DRange aVisibleDiscreteRange; 162cdf0e10cSrcweir basegfx::B2DRange aUnitVisibleRange; 163cdf0e10cSrcweir 164cdf0e10cSrcweir calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange); 165cdf0e10cSrcweir 166cdf0e10cSrcweir if(!aVisibleDiscreteRange.isEmpty()) 167cdf0e10cSrcweir { 168cdf0e10cSrcweir // test if discrete view size (pixel) maybe too big and limit it 169cdf0e10cSrcweir double fViewSizeX(aVisibleDiscreteRange.getWidth()); 170cdf0e10cSrcweir double fViewSizeY(aVisibleDiscreteRange.getHeight()); 171cdf0e10cSrcweir const double fViewVisibleArea(fViewSizeX * fViewSizeY); 172cdf0e10cSrcweir const SvtOptionsDrawinglayer aDrawinglayerOpt; 173cdf0e10cSrcweir const double fMaximumVisibleArea(aDrawinglayerOpt.GetQuadratic3DRenderLimit()); 174cdf0e10cSrcweir double fReduceFactor(1.0); 175cdf0e10cSrcweir 176cdf0e10cSrcweir if(fViewVisibleArea > fMaximumVisibleArea) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir fReduceFactor = sqrt(fMaximumVisibleArea / fViewVisibleArea); 179cdf0e10cSrcweir fViewSizeX *= fReduceFactor; 180cdf0e10cSrcweir fViewSizeY *= fReduceFactor; 181cdf0e10cSrcweir } 182cdf0e10cSrcweir 183cdf0e10cSrcweir if(rViewInformation.getReducedDisplayQuality()) 184cdf0e10cSrcweir { 185cdf0e10cSrcweir // when reducing the visualisation is allowed (e.g. an OverlayObject 186cdf0e10cSrcweir // only needed for dragging), reduce resolution extra 187cdf0e10cSrcweir // to speed up dragging interactions 188cdf0e10cSrcweir const double fArea(fViewSizeX * fViewSizeY); 189cdf0e10cSrcweir double fReducedVisualisationFactor(1.0 / (sqrt(fArea) * (1.0 / 170.0))); 190cdf0e10cSrcweir 191cdf0e10cSrcweir if(fReducedVisualisationFactor > 1.0) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir fReducedVisualisationFactor = 1.0; 194cdf0e10cSrcweir } 195cdf0e10cSrcweir else if(fReducedVisualisationFactor < 0.20) 196cdf0e10cSrcweir { 197cdf0e10cSrcweir fReducedVisualisationFactor = 0.20; 198cdf0e10cSrcweir } 199cdf0e10cSrcweir 200cdf0e10cSrcweir if(fReducedVisualisationFactor != 1.0) 201cdf0e10cSrcweir { 202cdf0e10cSrcweir fReduceFactor *= fReducedVisualisationFactor; 203cdf0e10cSrcweir fViewSizeX *= fReducedVisualisationFactor; 204cdf0e10cSrcweir fViewSizeY *= fReducedVisualisationFactor; 205cdf0e10cSrcweir } 206cdf0e10cSrcweir } 207cdf0e10cSrcweir 208cdf0e10cSrcweir // determine the oversample value 209cdf0e10cSrcweir static sal_uInt16 nDefaultOversampleValue(3); 210cdf0e10cSrcweir const sal_uInt16 nOversampleValue(aDrawinglayerOpt.IsAntiAliasing() ? nDefaultOversampleValue : 0); 211cdf0e10cSrcweir 212*78d93489SArmin Le Grand geometry::ViewInformation3D aViewInformation3D(getViewInformation3D()); 213*78d93489SArmin Le Grand { 214*78d93489SArmin Le Grand // calculate a transformation from DiscreteRange to evtl. rotated/sheared content. 215*78d93489SArmin Le Grand // Start with full transformation from object to discrete units 216*78d93489SArmin Le Grand basegfx::B2DHomMatrix aObjToUnit(rViewInformation.getObjectToViewTransformation() * getObjectTransformation()); 217*78d93489SArmin Le Grand 218*78d93489SArmin Le Grand // bring to unit coordinates by applying inverse DiscreteRange 219*78d93489SArmin Le Grand aObjToUnit.translate(-aDiscreteRange.getMinX(), -aDiscreteRange.getMinY()); 220*78d93489SArmin Le Grand aObjToUnit.scale(1.0 / aDiscreteRange.getWidth(), 1.0 / aDiscreteRange.getHeight()); 221*78d93489SArmin Le Grand 222*78d93489SArmin Le Grand // calculate transformed user coordinate system 223*78d93489SArmin Le Grand const basegfx::B2DPoint aStandardNull(0.0, 0.0); 224*78d93489SArmin Le Grand const basegfx::B2DPoint aUnitRangeTopLeft(aObjToUnit * aStandardNull); 225*78d93489SArmin Le Grand const basegfx::B2DVector aStandardXAxis(1.0, 0.0); 226*78d93489SArmin Le Grand const basegfx::B2DVector aUnitRangeXAxis(aObjToUnit * aStandardXAxis); 227*78d93489SArmin Le Grand const basegfx::B2DVector aStandardYAxis(0.0, 1.0); 228*78d93489SArmin Le Grand const basegfx::B2DVector aUnitRangeYAxis(aObjToUnit * aStandardYAxis); 229*78d93489SArmin Le Grand 230*78d93489SArmin Le Grand if(!aUnitRangeTopLeft.equal(aStandardNull) || !aUnitRangeXAxis.equal(aStandardXAxis) || !aUnitRangeYAxis.equal(aStandardYAxis)) 231*78d93489SArmin Le Grand { 232*78d93489SArmin Le Grand // build transformation from unit range to user coordinate system; the unit range 233*78d93489SArmin Le Grand // X and Y axes are the column vectors, the null point is the offset 234*78d93489SArmin Le Grand basegfx::B2DHomMatrix aUnitRangeToUser; 235*78d93489SArmin Le Grand 236*78d93489SArmin Le Grand aUnitRangeToUser.set3x2( 237*78d93489SArmin Le Grand aUnitRangeXAxis.getX(), aUnitRangeYAxis.getX(), aUnitRangeTopLeft.getX(), 238*78d93489SArmin Le Grand aUnitRangeXAxis.getY(), aUnitRangeYAxis.getY(), aUnitRangeTopLeft.getY()); 239*78d93489SArmin Le Grand 240*78d93489SArmin Le Grand // decompose to allow to apply this to the 3D transformation 241*78d93489SArmin Le Grand basegfx::B2DVector aScale, aTranslate; 242*78d93489SArmin Le Grand double fRotate, fShearX; 243*78d93489SArmin Le Grand aUnitRangeToUser.decompose(aScale, aTranslate, fRotate, fShearX); 244*78d93489SArmin Le Grand 245*78d93489SArmin Le Grand // apply before DeviceToView and after Projection, 3D is in range [-1.0 .. 1.0] in X,Y and Z 246*78d93489SArmin Le Grand // and not yet flipped in Y 247*78d93489SArmin Le Grand basegfx::B3DHomMatrix aExtendedProjection(aViewInformation3D.getProjection()); 248*78d93489SArmin Le Grand 249*78d93489SArmin Le Grand // bring to unit coordiantes, flip Y, leave Z unchanged 250*78d93489SArmin Le Grand aExtendedProjection.scale(0.5, -0.5, 1.0); 251*78d93489SArmin Le Grand aExtendedProjection.translate(0.5, 0.5, 0.0); 252*78d93489SArmin Le Grand 253*78d93489SArmin Le Grand // apply extra; Y is flipped now, go with positive shear and rotate values 254*78d93489SArmin Le Grand aExtendedProjection.scale(aScale.getX(), aScale.getY(), 1.0); 255*78d93489SArmin Le Grand aExtendedProjection.shearXZ(fShearX, 0.0); 256*78d93489SArmin Le Grand aExtendedProjection.rotate(0.0, 0.0, fRotate); 257*78d93489SArmin Le Grand aExtendedProjection.translate(aTranslate.getX(), aTranslate.getY(), 0.0); 258*78d93489SArmin Le Grand 259*78d93489SArmin Le Grand // back to state after projection 260*78d93489SArmin Le Grand aExtendedProjection.translate(-0.5, -0.5, 0.0); 261*78d93489SArmin Le Grand aExtendedProjection.scale(2.0, -2.0, 1.0); 262*78d93489SArmin Le Grand 263*78d93489SArmin Le Grand aViewInformation3D = geometry::ViewInformation3D( 264*78d93489SArmin Le Grand aViewInformation3D.getObjectTransformation(), 265*78d93489SArmin Le Grand aViewInformation3D.getOrientation(), 266*78d93489SArmin Le Grand aExtendedProjection, 267*78d93489SArmin Le Grand aViewInformation3D.getDeviceToView(), 268*78d93489SArmin Le Grand aViewInformation3D.getViewTime(), 269*78d93489SArmin Le Grand aViewInformation3D.getExtendedInformationSequence()); 270*78d93489SArmin Le Grand } 271*78d93489SArmin Le Grand } 272*78d93489SArmin Le Grand 273*78d93489SArmin Le Grand // calculate logic render size in world coordinates for usage in renderer 274*78d93489SArmin Le Grand const basegfx::B2DHomMatrix aInverseOToV(rViewInformation.getInverseObjectToViewTransformation()); 275*78d93489SArmin Le Grand const double fLogicX((aInverseOToV * basegfx::B2DVector(aDiscreteRange.getWidth() * fReduceFactor, 0.0)).getLength()); 276*78d93489SArmin Le Grand const double fLogicY((aInverseOToV * basegfx::B2DVector(0.0, aDiscreteRange.getHeight() * fReduceFactor)).getLength()); 277*78d93489SArmin Le Grand 278cdf0e10cSrcweir // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process 279cdf0e10cSrcweir processor3d::ZBufferProcessor3D aZBufferProcessor3D( 280*78d93489SArmin Le Grand aViewInformation3D, 281cdf0e10cSrcweir rViewInformation, 282cdf0e10cSrcweir getSdrSceneAttribute(), 283cdf0e10cSrcweir getSdrLightingAttribute(), 284*78d93489SArmin Le Grand fLogicX, 285*78d93489SArmin Le Grand fLogicY, 286cdf0e10cSrcweir aUnitVisibleRange, 287cdf0e10cSrcweir nOversampleValue); 288cdf0e10cSrcweir 289cdf0e10cSrcweir aZBufferProcessor3D.process(getChildren3D()); 290cdf0e10cSrcweir aZBufferProcessor3D.finish(); 291cdf0e10cSrcweir 292cdf0e10cSrcweir const_cast< ScenePrimitive2D* >(this)->maOldRenderedBitmap = aZBufferProcessor3D.getBitmapEx(); 293cdf0e10cSrcweir const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel()); 294cdf0e10cSrcweir 295cdf0e10cSrcweir if(aBitmapSizePixel.getWidth() && aBitmapSizePixel.getHeight()) 296cdf0e10cSrcweir { 297cdf0e10cSrcweir // create transform for the created bitmap in discrete coordinates first. 298cdf0e10cSrcweir basegfx::B2DHomMatrix aNew2DTransform; 299cdf0e10cSrcweir 300cdf0e10cSrcweir aNew2DTransform.set(0, 0, aVisibleDiscreteRange.getWidth()); 301cdf0e10cSrcweir aNew2DTransform.set(1, 1, aVisibleDiscreteRange.getHeight()); 302cdf0e10cSrcweir aNew2DTransform.set(0, 2, aVisibleDiscreteRange.getMinX()); 303cdf0e10cSrcweir aNew2DTransform.set(1, 2, aVisibleDiscreteRange.getMinY()); 304cdf0e10cSrcweir 305cdf0e10cSrcweir // transform back to world coordinates for usage in primitive creation 306*78d93489SArmin Le Grand aNew2DTransform *= aInverseOToV; 307cdf0e10cSrcweir 308cdf0e10cSrcweir // create bitmap primitive and add 309cdf0e10cSrcweir const Primitive2DReference xRef(new BitmapPrimitive2D(maOldRenderedBitmap, aNew2DTransform)); 310cdf0e10cSrcweir appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef); 311cdf0e10cSrcweir 312cdf0e10cSrcweir // test: Allow to add an outline in the debugger when tests are needed 313cdf0e10cSrcweir static bool bAddOutlineToCreated3DSceneRepresentation(false); 314cdf0e10cSrcweir 315cdf0e10cSrcweir if(bAddOutlineToCreated3DSceneRepresentation) 316cdf0e10cSrcweir { 317cdf0e10cSrcweir basegfx::B2DPolygon aOutline(basegfx::tools::createUnitPolygon()); 318cdf0e10cSrcweir aOutline.transform(aNew2DTransform); 319cdf0e10cSrcweir const Primitive2DReference xRef2(new PolygonHairlinePrimitive2D(aOutline, basegfx::BColor(1.0, 0.0, 0.0))); 320cdf0e10cSrcweir appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef2); 321cdf0e10cSrcweir } 322cdf0e10cSrcweir } 323cdf0e10cSrcweir } 324cdf0e10cSrcweir 325cdf0e10cSrcweir return aRetval; 326cdf0e10cSrcweir } 327cdf0e10cSrcweir getGeometry2D() const328cdf0e10cSrcweir Primitive2DSequence ScenePrimitive2D::getGeometry2D() const 329cdf0e10cSrcweir { 330cdf0e10cSrcweir Primitive2DSequence aRetval; 331cdf0e10cSrcweir 332cdf0e10cSrcweir // create 2D projected geometry from 3D geometry 333cdf0e10cSrcweir if(getChildren3D().hasElements()) 334cdf0e10cSrcweir { 335cdf0e10cSrcweir // create 2D geometry extraction processor 336cdf0e10cSrcweir processor3d::Geometry2DExtractingProcessor aGeometryProcessor( 337cdf0e10cSrcweir getViewInformation3D(), 338cdf0e10cSrcweir getObjectTransformation()); 339cdf0e10cSrcweir 340cdf0e10cSrcweir // process local primitives 341cdf0e10cSrcweir aGeometryProcessor.process(getChildren3D()); 342cdf0e10cSrcweir 343cdf0e10cSrcweir // fetch result 344cdf0e10cSrcweir aRetval = aGeometryProcessor.getPrimitive2DSequence(); 345cdf0e10cSrcweir } 346cdf0e10cSrcweir 347cdf0e10cSrcweir return aRetval; 348cdf0e10cSrcweir } 349cdf0e10cSrcweir getShadow2D(const geometry::ViewInformation2D & rViewInformation) const350cdf0e10cSrcweir Primitive2DSequence ScenePrimitive2D::getShadow2D(const geometry::ViewInformation2D& rViewInformation) const 351cdf0e10cSrcweir { 352cdf0e10cSrcweir Primitive2DSequence aRetval; 353cdf0e10cSrcweir 354cdf0e10cSrcweir // create 2D shadows from contained 3D primitives 355cdf0e10cSrcweir if(impGetShadow3D(rViewInformation)) 356cdf0e10cSrcweir { 357cdf0e10cSrcweir // add extracted 2d shadows (before 3d scene creations itself) 358cdf0e10cSrcweir aRetval = maShadowPrimitives; 359cdf0e10cSrcweir } 360cdf0e10cSrcweir 361cdf0e10cSrcweir return aRetval; 362cdf0e10cSrcweir } 363cdf0e10cSrcweir tryToCheckLastVisualisationDirectHit(const basegfx::B2DPoint & rLogicHitPoint,bool & o_rResult) const364cdf0e10cSrcweir bool ScenePrimitive2D::tryToCheckLastVisualisationDirectHit(const basegfx::B2DPoint& rLogicHitPoint, bool& o_rResult) const 365cdf0e10cSrcweir { 366cdf0e10cSrcweir if(!maOldRenderedBitmap.IsEmpty() && !maOldUnitVisiblePart.isEmpty()) 367cdf0e10cSrcweir { 368cdf0e10cSrcweir basegfx::B2DHomMatrix aInverseSceneTransform(getObjectTransformation()); 369cdf0e10cSrcweir aInverseSceneTransform.invert(); 370cdf0e10cSrcweir const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rLogicHitPoint); 371cdf0e10cSrcweir 372cdf0e10cSrcweir if(maOldUnitVisiblePart.isInside(aRelativePoint)) 373cdf0e10cSrcweir { 374cdf0e10cSrcweir // calculate coordinates relative to visualized part 375cdf0e10cSrcweir double fDivisorX(maOldUnitVisiblePart.getWidth()); 376cdf0e10cSrcweir double fDivisorY(maOldUnitVisiblePart.getHeight()); 377cdf0e10cSrcweir 378cdf0e10cSrcweir if(basegfx::fTools::equalZero(fDivisorX)) 379cdf0e10cSrcweir { 380cdf0e10cSrcweir fDivisorX = 1.0; 381cdf0e10cSrcweir } 382cdf0e10cSrcweir 383cdf0e10cSrcweir if(basegfx::fTools::equalZero(fDivisorY)) 384cdf0e10cSrcweir { 385cdf0e10cSrcweir fDivisorY = 1.0; 386cdf0e10cSrcweir } 387cdf0e10cSrcweir 388cdf0e10cSrcweir const double fRelativeX((aRelativePoint.getX() - maOldUnitVisiblePart.getMinX()) / fDivisorX); 389cdf0e10cSrcweir const double fRelativeY((aRelativePoint.getY() - maOldUnitVisiblePart.getMinY()) / fDivisorY); 390cdf0e10cSrcweir 391cdf0e10cSrcweir // combine with real BitmapSizePixel to get bitmap coordinates 392cdf0e10cSrcweir const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel()); 393cdf0e10cSrcweir const sal_Int32 nX(basegfx::fround(fRelativeX * aBitmapSizePixel.Width())); 394cdf0e10cSrcweir const sal_Int32 nY(basegfx::fround(fRelativeY * aBitmapSizePixel.Height())); 395cdf0e10cSrcweir 396cdf0e10cSrcweir // try to get a statement about transparency in that pixel 397cdf0e10cSrcweir o_rResult = (0xff != maOldRenderedBitmap.GetTransparency(nX, nY)); 398cdf0e10cSrcweir return true; 399cdf0e10cSrcweir } 400cdf0e10cSrcweir } 401cdf0e10cSrcweir 402cdf0e10cSrcweir return false; 403cdf0e10cSrcweir } 404cdf0e10cSrcweir ScenePrimitive2D(const primitive3d::Primitive3DSequence & rxChildren3D,const attribute::SdrSceneAttribute & rSdrSceneAttribute,const attribute::SdrLightingAttribute & rSdrLightingAttribute,const basegfx::B2DHomMatrix & rObjectTransformation,const geometry::ViewInformation3D & rViewInformation3D)405cdf0e10cSrcweir ScenePrimitive2D::ScenePrimitive2D( 406cdf0e10cSrcweir const primitive3d::Primitive3DSequence& rxChildren3D, 407cdf0e10cSrcweir const attribute::SdrSceneAttribute& rSdrSceneAttribute, 408cdf0e10cSrcweir const attribute::SdrLightingAttribute& rSdrLightingAttribute, 409cdf0e10cSrcweir const basegfx::B2DHomMatrix& rObjectTransformation, 410cdf0e10cSrcweir const geometry::ViewInformation3D& rViewInformation3D) 411cdf0e10cSrcweir : BufferedDecompositionPrimitive2D(), 412cdf0e10cSrcweir mxChildren3D(rxChildren3D), 413cdf0e10cSrcweir maSdrSceneAttribute(rSdrSceneAttribute), 414cdf0e10cSrcweir maSdrLightingAttribute(rSdrLightingAttribute), 415cdf0e10cSrcweir maObjectTransformation(rObjectTransformation), 416cdf0e10cSrcweir maViewInformation3D(rViewInformation3D), 417cdf0e10cSrcweir maShadowPrimitives(), 418cdf0e10cSrcweir mbShadow3DChecked(false), 419cdf0e10cSrcweir mfOldDiscreteSizeX(0.0), 420cdf0e10cSrcweir mfOldDiscreteSizeY(0.0), 421cdf0e10cSrcweir maOldUnitVisiblePart(), 422cdf0e10cSrcweir maOldRenderedBitmap() 423cdf0e10cSrcweir { 424cdf0e10cSrcweir } 425cdf0e10cSrcweir operator ==(const BasePrimitive2D & rPrimitive) const426cdf0e10cSrcweir bool ScenePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 427cdf0e10cSrcweir { 428cdf0e10cSrcweir if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 429cdf0e10cSrcweir { 430cdf0e10cSrcweir const ScenePrimitive2D& rCompare = (ScenePrimitive2D&)rPrimitive; 431cdf0e10cSrcweir 432cdf0e10cSrcweir return (primitive3d::arePrimitive3DSequencesEqual(getChildren3D(), rCompare.getChildren3D()) 433cdf0e10cSrcweir && getSdrSceneAttribute() == rCompare.getSdrSceneAttribute() 434cdf0e10cSrcweir && getSdrLightingAttribute() == rCompare.getSdrLightingAttribute() 435cdf0e10cSrcweir && getObjectTransformation() == rCompare.getObjectTransformation() 436cdf0e10cSrcweir && getViewInformation3D() == rCompare.getViewInformation3D()); 437cdf0e10cSrcweir } 438cdf0e10cSrcweir 439cdf0e10cSrcweir return false; 440cdf0e10cSrcweir } 441cdf0e10cSrcweir getB2DRange(const geometry::ViewInformation2D & rViewInformation) const442cdf0e10cSrcweir basegfx::B2DRange ScenePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 443cdf0e10cSrcweir { 444cdf0e10cSrcweir // transform unit range to discrete coordinate range 445cdf0e10cSrcweir basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0); 446cdf0e10cSrcweir aRetval.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation()); 447cdf0e10cSrcweir 448cdf0e10cSrcweir // force to discrete expanded bounds (it grows, so expanding works perfectly well) 449cdf0e10cSrcweir aRetval.expand(basegfx::B2DTuple(floor(aRetval.getMinX()), floor(aRetval.getMinY()))); 450cdf0e10cSrcweir aRetval.expand(basegfx::B2DTuple(ceil(aRetval.getMaxX()), ceil(aRetval.getMaxY()))); 451cdf0e10cSrcweir 452cdf0e10cSrcweir // transform back from discrete (view) to world coordinates 453cdf0e10cSrcweir aRetval.transform(rViewInformation.getInverseObjectToViewTransformation()); 454cdf0e10cSrcweir 455cdf0e10cSrcweir // expand by evtl. existing shadow primitives 456cdf0e10cSrcweir if(impGetShadow3D(rViewInformation)) 457cdf0e10cSrcweir { 458cdf0e10cSrcweir const basegfx::B2DRange aShadow2DRange(getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation)); 459cdf0e10cSrcweir 460cdf0e10cSrcweir if(!aShadow2DRange.isEmpty()) 461cdf0e10cSrcweir { 462cdf0e10cSrcweir aRetval.expand(aShadow2DRange); 463cdf0e10cSrcweir } 464cdf0e10cSrcweir } 465cdf0e10cSrcweir 466cdf0e10cSrcweir return aRetval; 467cdf0e10cSrcweir } 468cdf0e10cSrcweir get2DDecomposition(const geometry::ViewInformation2D & rViewInformation) const469cdf0e10cSrcweir Primitive2DSequence ScenePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 470cdf0e10cSrcweir { 471cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 472cdf0e10cSrcweir 473cdf0e10cSrcweir // get the involved ranges (see helper method calculateDiscreteSizes for details) 474cdf0e10cSrcweir basegfx::B2DRange aDiscreteRange; 475cdf0e10cSrcweir basegfx::B2DRange aUnitVisibleRange; 476cdf0e10cSrcweir bool bNeedNewDecomposition(false); 477cdf0e10cSrcweir bool bDiscreteSizesAreCalculated(false); 478cdf0e10cSrcweir 479cdf0e10cSrcweir if(getBuffered2DDecomposition().hasElements()) 480cdf0e10cSrcweir { 481cdf0e10cSrcweir basegfx::B2DRange aVisibleDiscreteRange; 482cdf0e10cSrcweir calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange); 483cdf0e10cSrcweir bDiscreteSizesAreCalculated = true; 484cdf0e10cSrcweir 485cdf0e10cSrcweir // needs to be painted when the new part is not part of the last 486cdf0e10cSrcweir // decomposition 487cdf0e10cSrcweir if(!maOldUnitVisiblePart.isInside(aUnitVisibleRange)) 488cdf0e10cSrcweir { 489cdf0e10cSrcweir bNeedNewDecomposition = true; 490cdf0e10cSrcweir } 491cdf0e10cSrcweir 492cdf0e10cSrcweir // display has changed and cannot be reused when resolution got bigger. It 493cdf0e10cSrcweir // can be reused when resolution got smaller, though. 494cdf0e10cSrcweir if(!bNeedNewDecomposition) 495cdf0e10cSrcweir { 496cdf0e10cSrcweir if(basegfx::fTools::more(aDiscreteRange.getWidth(), mfOldDiscreteSizeX) || 497cdf0e10cSrcweir basegfx::fTools::more(aDiscreteRange.getHeight(), mfOldDiscreteSizeY)) 498cdf0e10cSrcweir { 499cdf0e10cSrcweir bNeedNewDecomposition = true; 500cdf0e10cSrcweir } 501cdf0e10cSrcweir } 502cdf0e10cSrcweir } 503cdf0e10cSrcweir 504cdf0e10cSrcweir if(bNeedNewDecomposition) 505cdf0e10cSrcweir { 506cdf0e10cSrcweir // conditions of last local decomposition have changed, delete 507cdf0e10cSrcweir const_cast< ScenePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence()); 508cdf0e10cSrcweir } 509cdf0e10cSrcweir 510cdf0e10cSrcweir if(!getBuffered2DDecomposition().hasElements()) 511cdf0e10cSrcweir { 512cdf0e10cSrcweir if(!bDiscreteSizesAreCalculated) 513cdf0e10cSrcweir { 514cdf0e10cSrcweir basegfx::B2DRange aVisibleDiscreteRange; 515cdf0e10cSrcweir calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange); 516cdf0e10cSrcweir } 517cdf0e10cSrcweir 518cdf0e10cSrcweir // remember last used NewDiscreteSize and NewUnitVisiblePart 519cdf0e10cSrcweir ScenePrimitive2D* pThat = const_cast< ScenePrimitive2D* >(this); 520cdf0e10cSrcweir pThat->mfOldDiscreteSizeX = aDiscreteRange.getWidth(); 521cdf0e10cSrcweir pThat->mfOldDiscreteSizeY = aDiscreteRange.getHeight(); 522cdf0e10cSrcweir pThat->maOldUnitVisiblePart = aUnitVisibleRange; 523cdf0e10cSrcweir } 524cdf0e10cSrcweir 525cdf0e10cSrcweir // use parent implementation 526cdf0e10cSrcweir return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation); 527cdf0e10cSrcweir } 528cdf0e10cSrcweir 529cdf0e10cSrcweir // provide unique ID 530cdf0e10cSrcweir ImplPrimitrive2DIDBlock(ScenePrimitive2D, PRIMITIVE2D_ID_SCENEPRIMITIVE2D) 531cdf0e10cSrcweir 532cdf0e10cSrcweir } // end of namespace primitive2d 533cdf0e10cSrcweir } // end of namespace drawinglayer 534cdf0e10cSrcweir 535cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 536cdf0e10cSrcweir // eof 537