xref: /trunk/main/drawinglayer/source/primitive2d/sceneprimitive2d.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
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
10cdf0e10cSrcweir  *
11464702f4SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
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.
19cdf0e10cSrcweir  *
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 
21278d93489SArmin Le Grand                 geometry::ViewInformation3D aViewInformation3D(getViewInformation3D());
21378d93489SArmin Le Grand                 {
21478d93489SArmin Le Grand                     // calculate a transformation from DiscreteRange to evtl. rotated/sheared content.
21578d93489SArmin Le Grand                     // Start with full transformation from object to discrete units
21678d93489SArmin Le Grand                     basegfx::B2DHomMatrix aObjToUnit(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
21778d93489SArmin Le Grand 
21878d93489SArmin Le Grand                     // bring to unit coordinates by applying inverse DiscreteRange
21978d93489SArmin Le Grand                     aObjToUnit.translate(-aDiscreteRange.getMinX(), -aDiscreteRange.getMinY());
22078d93489SArmin Le Grand                     aObjToUnit.scale(1.0 / aDiscreteRange.getWidth(), 1.0 / aDiscreteRange.getHeight());
22178d93489SArmin Le Grand 
22278d93489SArmin Le Grand                     // calculate transformed user coordinate system
22378d93489SArmin Le Grand                     const basegfx::B2DPoint aStandardNull(0.0, 0.0);
22478d93489SArmin Le Grand                     const basegfx::B2DPoint aUnitRangeTopLeft(aObjToUnit * aStandardNull);
22578d93489SArmin Le Grand                     const basegfx::B2DVector aStandardXAxis(1.0, 0.0);
22678d93489SArmin Le Grand                     const basegfx::B2DVector aUnitRangeXAxis(aObjToUnit * aStandardXAxis);
22778d93489SArmin Le Grand                     const basegfx::B2DVector aStandardYAxis(0.0, 1.0);
22878d93489SArmin Le Grand                     const basegfx::B2DVector aUnitRangeYAxis(aObjToUnit * aStandardYAxis);
22978d93489SArmin Le Grand 
23078d93489SArmin Le Grand                     if(!aUnitRangeTopLeft.equal(aStandardNull) || !aUnitRangeXAxis.equal(aStandardXAxis) || !aUnitRangeYAxis.equal(aStandardYAxis))
23178d93489SArmin Le Grand                     {
23278d93489SArmin Le Grand                         // build transformation from unit range to user coordinate system; the unit range
23378d93489SArmin Le Grand                         // X and Y axes are the column vectors, the null point is the offset
23478d93489SArmin Le Grand                         basegfx::B2DHomMatrix aUnitRangeToUser;
23578d93489SArmin Le Grand 
23678d93489SArmin Le Grand                         aUnitRangeToUser.set3x2(
23778d93489SArmin Le Grand                             aUnitRangeXAxis.getX(), aUnitRangeYAxis.getX(), aUnitRangeTopLeft.getX(),
23878d93489SArmin Le Grand                             aUnitRangeXAxis.getY(), aUnitRangeYAxis.getY(), aUnitRangeTopLeft.getY());
23978d93489SArmin Le Grand 
24078d93489SArmin Le Grand                         // decompose to allow to apply this to the 3D transformation
24178d93489SArmin Le Grand                         basegfx::B2DVector aScale, aTranslate;
24278d93489SArmin Le Grand                         double fRotate, fShearX;
24378d93489SArmin Le Grand                         aUnitRangeToUser.decompose(aScale, aTranslate, fRotate, fShearX);
24478d93489SArmin Le Grand 
24578d93489SArmin Le Grand                         // apply before DeviceToView and after Projection, 3D is in range [-1.0 .. 1.0] in X,Y and Z
24678d93489SArmin Le Grand                         // and not yet flipped in Y
24778d93489SArmin Le Grand                         basegfx::B3DHomMatrix aExtendedProjection(aViewInformation3D.getProjection());
24878d93489SArmin Le Grand 
249*7de601c3SJohn Bampton                         // bring to unit coordinates, flip Y, leave Z unchanged
25078d93489SArmin Le Grand                         aExtendedProjection.scale(0.5, -0.5, 1.0);
25178d93489SArmin Le Grand                         aExtendedProjection.translate(0.5, 0.5, 0.0);
25278d93489SArmin Le Grand 
25378d93489SArmin Le Grand                         // apply extra; Y is flipped now, go with positive shear and rotate values
25478d93489SArmin Le Grand                         aExtendedProjection.scale(aScale.getX(), aScale.getY(), 1.0);
25578d93489SArmin Le Grand                         aExtendedProjection.shearXZ(fShearX, 0.0);
25678d93489SArmin Le Grand                         aExtendedProjection.rotate(0.0, 0.0, fRotate);
25778d93489SArmin Le Grand                         aExtendedProjection.translate(aTranslate.getX(), aTranslate.getY(), 0.0);
25878d93489SArmin Le Grand 
25978d93489SArmin Le Grand                         // back to state after projection
26078d93489SArmin Le Grand                         aExtendedProjection.translate(-0.5, -0.5, 0.0);
26178d93489SArmin Le Grand                         aExtendedProjection.scale(2.0, -2.0, 1.0);
26278d93489SArmin Le Grand 
26378d93489SArmin Le Grand                         aViewInformation3D = geometry::ViewInformation3D(
26478d93489SArmin Le Grand                             aViewInformation3D.getObjectTransformation(),
26578d93489SArmin Le Grand                             aViewInformation3D.getOrientation(),
26678d93489SArmin Le Grand                             aExtendedProjection,
26778d93489SArmin Le Grand                             aViewInformation3D.getDeviceToView(),
26878d93489SArmin Le Grand                             aViewInformation3D.getViewTime(),
26978d93489SArmin Le Grand                             aViewInformation3D.getExtendedInformationSequence());
27078d93489SArmin Le Grand                     }
27178d93489SArmin Le Grand                 }
27278d93489SArmin Le Grand 
27378d93489SArmin Le Grand                 // calculate logic render size in world coordinates for usage in renderer
27478d93489SArmin Le Grand                 const basegfx::B2DHomMatrix aInverseOToV(rViewInformation.getInverseObjectToViewTransformation());
27578d93489SArmin Le Grand                 const double fLogicX((aInverseOToV * basegfx::B2DVector(aDiscreteRange.getWidth() * fReduceFactor, 0.0)).getLength());
27678d93489SArmin Le Grand                 const double fLogicY((aInverseOToV * basegfx::B2DVector(0.0, aDiscreteRange.getHeight() * fReduceFactor)).getLength());
27778d93489SArmin Le Grand 
278cdf0e10cSrcweir                 // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
279cdf0e10cSrcweir                 processor3d::ZBufferProcessor3D aZBufferProcessor3D(
28078d93489SArmin Le Grand                     aViewInformation3D,
281cdf0e10cSrcweir                     rViewInformation,
282cdf0e10cSrcweir                     getSdrSceneAttribute(),
283cdf0e10cSrcweir                     getSdrLightingAttribute(),
28478d93489SArmin Le Grand                     fLogicX,
28578d93489SArmin 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
30678d93489SArmin 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