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