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