tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / drawinglayer / source / primitive2d / sceneprimitive2d.cxx
blob11807e459b7fc36438cb3c7314e3d5713b2bd480
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
21 #include <basegfx/polygon/b2dpolygontools.hxx>
22 #include <basegfx/polygon/b2dpolygon.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <drawinglayer/attribute/sdrlightattribute3d.hxx>
25 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
26 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
27 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
28 #include <processor3d/zbufferprocessor3d.hxx>
29 #include <processor3d/shadow3dextractor.hxx>
30 #include <drawinglayer/geometry/viewinformation2d.hxx>
31 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
32 #include <svtools/optionsdrawinglayer.hxx>
33 #include <processor3d/geometry2dextractor.hxx>
34 #include <basegfx/raster/bzpixelraster.hxx>
35 #include <utility>
36 #include <vcl/BitmapTools.hxx>
37 #include <comphelper/threadpool.hxx>
38 #include <comphelper/lok.hxx>
39 #include <toolkit/helper/vclunohelper.hxx>
40 #include <officecfg/Office/Common.hxx>
42 using namespace com::sun::star;
44 namespace
46 BitmapEx BPixelRasterToBitmapEx(const basegfx::BZPixelRaster& rRaster, sal_uInt16 mnAntiAlialize)
48 BitmapEx aRetval;
49 const sal_uInt32 nWidth(mnAntiAlialize ? rRaster.getWidth()/mnAntiAlialize : rRaster.getWidth());
50 const sal_uInt32 nHeight(mnAntiAlialize ? rRaster.getHeight()/mnAntiAlialize : rRaster.getHeight());
52 if(nWidth && nHeight)
54 const Size aDestSize(nWidth, nHeight);
55 vcl::bitmap::RawBitmap aContent(aDestSize, 32);
57 if(mnAntiAlialize)
59 const sal_uInt16 nDivisor(mnAntiAlialize * mnAntiAlialize);
61 for(sal_uInt32 y(0); y < nHeight; y++)
63 for(sal_uInt32 x(0); x < nWidth; x++)
65 sal_uInt16 nRed(0);
66 sal_uInt16 nGreen(0);
67 sal_uInt16 nBlue(0);
68 sal_uInt16 nAlpha(0);
69 sal_uInt32 nIndex(rRaster.getIndexFromXY(x * mnAntiAlialize, y * mnAntiAlialize));
71 for(sal_uInt32 c(0); c < mnAntiAlialize; c++)
73 for(sal_uInt32 d(0); d < mnAntiAlialize; d++)
75 const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++));
76 nRed += rPixel.getRed();
77 nGreen += rPixel.getGreen();
78 nBlue += rPixel.getBlue();
79 nAlpha += rPixel.getAlpha();
82 nIndex += rRaster.getWidth() - mnAntiAlialize;
85 nAlpha /= nDivisor;
87 if(nAlpha)
89 aContent.SetPixel(y, x, Color(ColorAlpha,
90 static_cast<sal_uInt8>(nAlpha),
91 static_cast<sal_uInt8>(nRed / nDivisor),
92 static_cast<sal_uInt8>(nGreen / nDivisor),
93 static_cast<sal_uInt8>(nBlue / nDivisor) ));
95 else
96 aContent.SetPixel(y, x, Color(ColorAlpha, 0, 0, 0, 0));
100 else
102 sal_uInt32 nIndex(0);
104 for(sal_uInt32 y(0); y < nHeight; y++)
106 for(sal_uInt32 x(0); x < nWidth; x++)
108 const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++));
110 if(rPixel.getAlpha())
112 aContent.SetPixel(y, x, Color(ColorAlpha, rPixel.getAlpha(), rPixel.getRed(), rPixel.getGreen(), rPixel.getBlue()));
114 else
115 aContent.SetPixel(y, x, Color(ColorAlpha, 0, 0, 0, 0));
120 aRetval = vcl::bitmap::CreateFromData(std::move(aContent));
122 // #i101811# set PrefMapMode and PrefSize at newly created Bitmap
123 aRetval.SetPrefMapMode(MapMode(MapUnit::MapPixel));
124 aRetval.SetPrefSize(Size(nWidth, nHeight));
127 return aRetval;
129 } // end of anonymous namespace
131 namespace drawinglayer::primitive2d
133 bool ScenePrimitive2D::impGetShadow3D() const
135 // create on demand
136 if(!mbShadow3DChecked && !getChildren3D().empty())
138 basegfx::B3DVector aLightNormal;
139 const double fShadowSlant(getSdrSceneAttribute().getShadowSlant());
140 const basegfx::B3DRange aScene3DRange(getChildren3D().getB3DRange(getViewInformation3D()));
142 if(!maSdrLightingAttribute.getLightVector().empty())
144 // get light normal from first light and normalize
145 aLightNormal = maSdrLightingAttribute.getLightVector()[0].getDirection();
146 aLightNormal.normalize();
149 // create shadow extraction processor
150 processor3d::Shadow3DExtractingProcessor aShadowProcessor(
151 getViewInformation3D(),
152 getObjectTransformation(),
153 aLightNormal,
154 fShadowSlant,
155 aScene3DRange);
157 // process local primitives
158 aShadowProcessor.process(getChildren3D());
160 // fetch result and set checked flag
161 const_cast< ScenePrimitive2D* >(this)->maShadowPrimitives = aShadowProcessor.getPrimitive2DSequence();
162 const_cast< ScenePrimitive2D* >(this)->mbShadow3DChecked = true;
165 // return if there are shadow primitives
166 return !maShadowPrimitives.empty();
169 void ScenePrimitive2D::calculateDiscreteSizes(
170 const geometry::ViewInformation2D& rViewInformation,
171 basegfx::B2DRange& rDiscreteRange,
172 basegfx::B2DRange& rVisibleDiscreteRange,
173 basegfx::B2DRange& rUnitVisibleRange) const
175 // use unit range and transform to discrete coordinates
176 rDiscreteRange = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
177 rDiscreteRange.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
179 // clip it against discrete Viewport (if set)
180 rVisibleDiscreteRange = rDiscreteRange;
182 if(!rViewInformation.getViewport().isEmpty())
184 rVisibleDiscreteRange.intersect(rViewInformation.getDiscreteViewport());
187 if(rVisibleDiscreteRange.isEmpty())
189 rUnitVisibleRange = rVisibleDiscreteRange;
191 else
193 // create UnitVisibleRange containing unit range values [0.0 .. 1.0] describing
194 // the relative position of rVisibleDiscreteRange inside rDiscreteRange
195 const double fDiscreteScaleFactorX(basegfx::fTools::equalZero(rDiscreteRange.getWidth()) ? 1.0 : 1.0 / rDiscreteRange.getWidth());
196 const double fDiscreteScaleFactorY(basegfx::fTools::equalZero(rDiscreteRange.getHeight()) ? 1.0 : 1.0 / rDiscreteRange.getHeight());
198 const double fMinX(basegfx::fTools::equal(rVisibleDiscreteRange.getMinX(), rDiscreteRange.getMinX())
199 ? 0.0
200 : (rVisibleDiscreteRange.getMinX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
201 const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange.getMinY(), rDiscreteRange.getMinY())
202 ? 0.0
203 : (rVisibleDiscreteRange.getMinY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
205 const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxX(), rDiscreteRange.getMaxX())
206 ? 1.0
207 : (rVisibleDiscreteRange.getMaxX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
208 const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxY(), rDiscreteRange.getMaxY())
209 ? 1.0
210 : (rVisibleDiscreteRange.getMaxY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
212 rUnitVisibleRange = basegfx::B2DRange(fMinX, fMinY, fMaxX, fMaxY);
216 Primitive2DReference ScenePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
218 Primitive2DContainer aContainer;
219 // create 2D shadows from contained 3D primitives. This creates the shadow primitives on demand and tells if
220 // there are some or not. Do this at start, the shadow might still be visible even when the scene is not
221 if(impGetShadow3D())
223 // test visibility
224 const basegfx::B2DRange aShadow2DRange(maShadowPrimitives.getB2DRange(rViewInformation));
225 const basegfx::B2DRange aViewRange(
226 rViewInformation.getViewport());
228 if(aViewRange.isEmpty() || aShadow2DRange.overlaps(aViewRange))
230 // add extracted 2d shadows (before 3d scene creations itself)
231 aContainer.append(maShadowPrimitives);
235 // get the involved ranges (see helper method calculateDiscreteSizes for details)
236 basegfx::B2DRange aDiscreteRange;
237 basegfx::B2DRange aVisibleDiscreteRange;
238 basegfx::B2DRange aUnitVisibleRange;
240 calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
242 if(aVisibleDiscreteRange.isEmpty())
243 return new GroupPrimitive2D(std::move(aContainer));
245 // test if discrete view size (pixel) maybe too big and limit it
246 double fViewSizeX(aVisibleDiscreteRange.getWidth());
247 double fViewSizeY(aVisibleDiscreteRange.getHeight());
248 const double fViewVisibleArea(fViewSizeX * fViewSizeY);
249 const double fMaximumVisibleArea(officecfg::Office::Common::Drawinglayer::Quadratic3DRenderLimit::get());
250 double fReduceFactor(1.0);
252 if(fViewVisibleArea > fMaximumVisibleArea)
254 fReduceFactor = sqrt(fMaximumVisibleArea / fViewVisibleArea);
255 fViewSizeX *= fReduceFactor;
256 fViewSizeY *= fReduceFactor;
259 if(rViewInformation.getReducedDisplayQuality())
261 // when reducing the visualisation is allowed (e.g. an OverlayObject
262 // only needed for dragging), reduce resolution extra
263 // to speed up dragging interactions
264 const double fArea(fViewSizeX * fViewSizeY);
265 if (fArea != 0.0)
267 double fReducedVisualisationFactor(1.0 / (sqrt(fArea) * (1.0 / 170.0)));
269 if(fReducedVisualisationFactor > 1.0)
271 fReducedVisualisationFactor = 1.0;
273 else if(fReducedVisualisationFactor < 0.20)
275 fReducedVisualisationFactor = 0.20;
278 if(fReducedVisualisationFactor != 1.0)
280 fReduceFactor *= fReducedVisualisationFactor;
285 // determine the oversample value
286 static const sal_uInt16 nDefaultOversampleValue(3);
287 sal_uInt16 nOversampleValue(SvtOptionsDrawinglayer::IsAntiAliasing() ? nDefaultOversampleValue : 0);
289 geometry::ViewInformation3D aViewInformation3D(getViewInformation3D());
291 // calculate a transformation from DiscreteRange to evtl. rotated/sheared content.
292 // Start with full transformation from object to discrete units
293 basegfx::B2DHomMatrix aObjToUnit(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
295 // bring to unit coordinates by applying inverse DiscreteRange
296 aObjToUnit.translate(-aDiscreteRange.getMinX(), -aDiscreteRange.getMinY());
297 if (aDiscreteRange.getWidth() != 0.0 && aDiscreteRange.getHeight() != 0.0)
299 aObjToUnit.scale(1.0 / aDiscreteRange.getWidth(), 1.0 / aDiscreteRange.getHeight());
302 // calculate transformed user coordinate system
303 const basegfx::B2DPoint aStandardNull(0.0, 0.0);
304 const basegfx::B2DPoint aUnitRangeTopLeft(aObjToUnit * aStandardNull);
305 const basegfx::B2DVector aStandardXAxis(1.0, 0.0);
306 const basegfx::B2DVector aUnitRangeXAxis(aObjToUnit * aStandardXAxis);
307 const basegfx::B2DVector aStandardYAxis(0.0, 1.0);
308 const basegfx::B2DVector aUnitRangeYAxis(aObjToUnit * aStandardYAxis);
310 if(!aUnitRangeTopLeft.equal(aStandardNull) || !aUnitRangeXAxis.equal(aStandardXAxis) || !aUnitRangeYAxis.equal(aStandardYAxis))
312 // build transformation from unit range to user coordinate system; the unit range
313 // X and Y axes are the column vectors, the null point is the offset
314 basegfx::B2DHomMatrix aUnitRangeToUser;
316 aUnitRangeToUser.set3x2(
317 aUnitRangeXAxis.getX(), aUnitRangeYAxis.getX(), aUnitRangeTopLeft.getX(),
318 aUnitRangeXAxis.getY(), aUnitRangeYAxis.getY(), aUnitRangeTopLeft.getY());
320 // decompose to allow to apply this to the 3D transformation
321 basegfx::B2DVector aScale, aTranslate;
322 double fRotate, fShearX;
323 aUnitRangeToUser.decompose(aScale, aTranslate, fRotate, fShearX);
325 // apply before DeviceToView and after Projection, 3D is in range [-1.0 .. 1.0] in X,Y and Z
326 // and not yet flipped in Y
327 basegfx::B3DHomMatrix aExtendedProjection(aViewInformation3D.getProjection());
329 // bring to unit coordinates, flip Y, leave Z unchanged
330 aExtendedProjection.scale(0.5, -0.5, 1.0);
331 aExtendedProjection.translate(0.5, 0.5, 0.0);
333 // apply extra; Y is flipped now, go with positive shear and rotate values
334 aExtendedProjection.scale(aScale.getX(), aScale.getY(), 1.0);
335 aExtendedProjection.shearXZ(fShearX, 0.0);
336 aExtendedProjection.rotate(0.0, 0.0, fRotate);
337 aExtendedProjection.translate(aTranslate.getX(), aTranslate.getY(), 0.0);
339 // back to state after projection
340 aExtendedProjection.translate(-0.5, -0.5, 0.0);
341 aExtendedProjection.scale(2.0, -2.0, 1.0);
343 aViewInformation3D = geometry::ViewInformation3D(
344 aViewInformation3D.getObjectTransformation(),
345 aViewInformation3D.getOrientation(),
346 aExtendedProjection,
347 aViewInformation3D.getDeviceToView(),
348 aViewInformation3D.getViewTime(),
349 aViewInformation3D.getExtendedInformationSequence());
353 // calculate logic render size in world coordinates for usage in renderer
354 const basegfx::B2DHomMatrix& aInverseOToV(rViewInformation.getInverseObjectToViewTransformation());
355 const double fLogicX((aInverseOToV * basegfx::B2DVector(aDiscreteRange.getWidth() * fReduceFactor, 0.0)).getLength());
356 const double fLogicY((aInverseOToV * basegfx::B2DVector(0.0, aDiscreteRange.getHeight() * fReduceFactor)).getLength());
358 // generate ViewSizes
359 double fFullViewSizeX((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(fLogicX, 0.0)).getLength());
360 double fFullViewSizeY((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fLogicY)).getLength());
362 // generate RasterWidth and RasterHeight for visible part
363 sal_Int32 nRasterWidth(basegfx::fround(fFullViewSizeX * aUnitVisibleRange.getWidth()) + 1);
364 sal_Int32 nRasterHeight(basegfx::fround(fFullViewSizeY * aUnitVisibleRange.getHeight()) + 1);
366 if(!rViewInformation.getReducedDisplayQuality() && comphelper::LibreOfficeKit::isActive())
368 // for this purpose allow reduced 3D quality and make a compromise
369 // between quality and speed. This is balanced between those two
370 // targets, fine-tuning/experimenting can be done with the values
371 // below.
373 // define some values which allow fine-tuning this feature
374 static const double fMin(80.0);
375 static const double fSqareMin(fMin * fMin);
376 static const double fMax(800.0);
377 static const double fSqareMax(fMax * fMax);
378 static const double fMaxReduction(0.65);
380 // get the square pixels (work on pixel numbers to get same
381 // behaviour independent of width/height relations)
382 const double fSquarePixels(nRasterWidth * nRasterHeight);
384 if (fSquarePixels > fSqareMin)
386 // only reduce at all when more than fSqareMin pixels needed
387 double fReduction(fMaxReduction);
389 if (fSquarePixels < fSqareMax)
391 // range between fSqareMin and fSqareMax, calculate a
392 // linear interpolated reduction based on square root
393 fReduction = sqrt(fSquarePixels); // [fMin .. fMax]
394 fReduction = fReduction - fMin; // [0 .. (fMax - fMin)]
395 fReduction = fReduction / (fMax - fMin); // [0 .. 1]
396 fReduction = 1.0 - (fReduction * (1.0 - fMaxReduction)); // [1 .. fMaxReduction]
398 // reduce oversampling for this range
399 if(nOversampleValue > 2)
400 nOversampleValue--;
402 else
404 // more than fSqareMax pixels, disable oversampling
405 nOversampleValue = 0;
408 // adapt needed values to reduction
409 nRasterWidth = basegfx::fround(fReduction * nRasterWidth);
410 nRasterHeight = basegfx::fround(fReduction * nRasterHeight);
411 fFullViewSizeX *= fReduction;
412 fFullViewSizeY *= fReduction;
416 if(!(nRasterWidth && nRasterHeight))
417 return new GroupPrimitive2D(std::move(aContainer));
419 // create view unit buffer
420 basegfx::BZPixelRaster aBZPixelRaster(
421 nOversampleValue ? nRasterWidth * nOversampleValue : nRasterWidth,
422 nOversampleValue ? nRasterHeight * nOversampleValue : nRasterHeight);
424 // check for parallel execution possibilities
425 static bool bMultithreadAllowed = true; // loplugin:constvars:ignore
426 sal_Int32 nThreadCount(0);
427 comphelper::ThreadPool& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool());
429 if(bMultithreadAllowed)
431 nThreadCount = rThreadPool.getWorkerCount();
433 if(nThreadCount > 1)
435 // at least use 10px per processor, so limit number of processors to
436 // target pixel size divided by 10 (which might be zero what is okay)
437 nThreadCount = std::min(nThreadCount, nRasterHeight / 10);
441 if(nThreadCount > 1)
443 class Executor : public comphelper::ThreadTask
445 private:
446 std::unique_ptr<processor3d::ZBufferProcessor3D> mpZBufferProcessor3D;
447 const primitive3d::Primitive3DContainer& mrChildren3D;
449 public:
450 explicit Executor(
451 std::shared_ptr<comphelper::ThreadTaskTag> const & rTag,
452 std::unique_ptr<processor3d::ZBufferProcessor3D> pZBufferProcessor3D,
453 const primitive3d::Primitive3DContainer& rChildren3D)
454 : comphelper::ThreadTask(rTag),
455 mpZBufferProcessor3D(std::move(pZBufferProcessor3D)),
456 mrChildren3D(rChildren3D)
460 virtual void doWork() override
462 mpZBufferProcessor3D->process(mrChildren3D);
463 mpZBufferProcessor3D->finish();
464 mpZBufferProcessor3D.reset();
468 const sal_uInt32 nLinesPerThread(aBZPixelRaster.getHeight() / nThreadCount);
469 std::shared_ptr<comphelper::ThreadTaskTag> aTag = comphelper::ThreadPool::createThreadTaskTag();
471 for(sal_Int32 a(0); a < nThreadCount; a++)
473 std::unique_ptr<processor3d::ZBufferProcessor3D> pNewZBufferProcessor3D(new processor3d::ZBufferProcessor3D(
474 aViewInformation3D,
475 getSdrSceneAttribute(),
476 getSdrLightingAttribute(),
477 aUnitVisibleRange,
478 nOversampleValue,
479 fFullViewSizeX,
480 fFullViewSizeY,
481 aBZPixelRaster,
482 nLinesPerThread * a,
483 a + 1 == nThreadCount ? aBZPixelRaster.getHeight() : nLinesPerThread * (a + 1)));
484 std::unique_ptr<Executor> pExecutor(new Executor(aTag, std::move(pNewZBufferProcessor3D), getChildren3D()));
485 rThreadPool.pushTask(std::move(pExecutor));
488 rThreadPool.waitUntilDone(aTag);
490 else
492 // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
493 processor3d::ZBufferProcessor3D aZBufferProcessor3D(
494 aViewInformation3D,
495 getSdrSceneAttribute(),
496 getSdrLightingAttribute(),
497 aUnitVisibleRange,
498 nOversampleValue,
499 fFullViewSizeX,
500 fFullViewSizeY,
501 aBZPixelRaster,
503 aBZPixelRaster.getHeight());
505 aZBufferProcessor3D.process(getChildren3D());
506 aZBufferProcessor3D.finish();
509 const_cast< ScenePrimitive2D* >(this)->maOldRenderedBitmap = BPixelRasterToBitmapEx(aBZPixelRaster, nOversampleValue);
510 const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel());
512 if(!(aBitmapSizePixel.getWidth() && aBitmapSizePixel.getHeight()))
513 return new GroupPrimitive2D(std::move(aContainer));
515 // create transform for the created bitmap in discrete coordinates first.
516 basegfx::B2DHomMatrix aNew2DTransform;
518 aNew2DTransform.set(0, 0, aVisibleDiscreteRange.getWidth());
519 aNew2DTransform.set(1, 1, aVisibleDiscreteRange.getHeight());
520 aNew2DTransform.set(0, 2, aVisibleDiscreteRange.getMinX());
521 aNew2DTransform.set(1, 2, aVisibleDiscreteRange.getMinY());
523 // transform back to world coordinates for usage in primitive creation
524 aNew2DTransform *= aInverseOToV;
526 // create bitmap primitive and add
527 aContainer.push_back(
528 new BitmapPrimitive2D(
529 maOldRenderedBitmap,
530 aNew2DTransform));
532 // test: Allow to add an outline in the debugger when tests are needed
533 static bool bAddOutlineToCreated3DSceneRepresentation(false); // loplugin:constvars:ignore
535 if(bAddOutlineToCreated3DSceneRepresentation)
537 basegfx::B2DPolygon aOutline(basegfx::utils::createUnitPolygon());
538 aOutline.transform(aNew2DTransform);
539 aContainer.push_back(new PolygonHairlinePrimitive2D(std::move(aOutline), basegfx::BColor(1.0, 0.0, 0.0)));
541 return new GroupPrimitive2D(std::move(aContainer));
544 Primitive2DContainer ScenePrimitive2D::getGeometry2D() const
546 Primitive2DContainer aRetval;
548 // create 2D projected geometry from 3D geometry
549 if(!getChildren3D().empty())
551 // create 2D geometry extraction processor
552 processor3d::Geometry2DExtractingProcessor aGeometryProcessor(
553 getViewInformation3D(),
554 getObjectTransformation());
556 // process local primitives
557 aGeometryProcessor.process(getChildren3D());
559 // fetch result
560 aRetval = aGeometryProcessor.getPrimitive2DSequence();
563 return aRetval;
566 Primitive2DContainer ScenePrimitive2D::getShadow2D() const
568 Primitive2DContainer aRetval;
570 // create 2D shadows from contained 3D primitives
571 if(impGetShadow3D())
573 // add extracted 2d shadows (before 3d scene creations itself)
574 aRetval = maShadowPrimitives;
577 return aRetval;
580 bool ScenePrimitive2D::tryToCheckLastVisualisationDirectHit(const basegfx::B2DPoint& rLogicHitPoint, bool& o_rResult) const
582 if(maOldRenderedBitmap.IsEmpty() || maOldUnitVisiblePart.isEmpty())
583 return false;
585 basegfx::B2DHomMatrix aInverseSceneTransform(getObjectTransformation());
586 aInverseSceneTransform.invert();
587 const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rLogicHitPoint);
589 if(!maOldUnitVisiblePart.isInside(aRelativePoint))
590 return false;
592 // calculate coordinates relative to visualized part
593 double fDivisorX(maOldUnitVisiblePart.getWidth());
594 double fDivisorY(maOldUnitVisiblePart.getHeight());
596 if(basegfx::fTools::equalZero(fDivisorX))
598 fDivisorX = 1.0;
601 if(basegfx::fTools::equalZero(fDivisorY))
603 fDivisorY = 1.0;
606 const double fRelativeX((aRelativePoint.getX() - maOldUnitVisiblePart.getMinX()) / fDivisorX);
607 const double fRelativeY((aRelativePoint.getY() - maOldUnitVisiblePart.getMinY()) / fDivisorY);
609 // combine with real BitmapSizePixel to get bitmap coordinates
610 const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel());
611 const sal_Int32 nX(basegfx::fround(fRelativeX * aBitmapSizePixel.Width()));
612 const sal_Int32 nY(basegfx::fround(fRelativeY * aBitmapSizePixel.Height()));
614 // try to get a statement about transparency in that pixel
615 o_rResult = (0 != maOldRenderedBitmap.GetAlpha(nX, nY));
616 return true;
619 ScenePrimitive2D::ScenePrimitive2D(
620 primitive3d::Primitive3DContainer aChildren3D,
621 attribute::SdrSceneAttribute aSdrSceneAttribute,
622 attribute::SdrLightingAttribute aSdrLightingAttribute,
623 basegfx::B2DHomMatrix aObjectTransformation,
624 geometry::ViewInformation3D aViewInformation3D)
625 : BufferedDecompositionPrimitive2D(),
626 mxChildren3D(std::move(aChildren3D)),
627 maSdrSceneAttribute(std::move(aSdrSceneAttribute)),
628 maSdrLightingAttribute(std::move(aSdrLightingAttribute)),
629 maObjectTransformation(std::move(aObjectTransformation)),
630 maViewInformation3D(std::move(aViewInformation3D)),
631 mbShadow3DChecked(false),
632 mfOldDiscreteSizeX(0.0),
633 mfOldDiscreteSizeY(0.0)
635 // activate callback to flush buffered decomposition content
636 setCallbackSeconds(45);
639 bool ScenePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
641 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
643 const ScenePrimitive2D& rCompare = static_cast<const ScenePrimitive2D&>(rPrimitive);
645 return (getChildren3D() == rCompare.getChildren3D()
646 && getSdrSceneAttribute() == rCompare.getSdrSceneAttribute()
647 && getSdrLightingAttribute() == rCompare.getSdrLightingAttribute()
648 && getObjectTransformation() == rCompare.getObjectTransformation()
649 && getViewInformation3D() == rCompare.getViewInformation3D());
652 return false;
655 basegfx::B2DRange ScenePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
657 // transform unit range to discrete coordinate range
658 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
659 aRetval.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
661 // force to discrete expanded bounds (it grows, so expanding works perfectly well)
662 aRetval.expand(basegfx::B2DTuple(floor(aRetval.getMinX()), floor(aRetval.getMinY())));
663 aRetval.expand(basegfx::B2DTuple(ceil(aRetval.getMaxX()), ceil(aRetval.getMaxY())));
665 // transform back from discrete (view) to world coordinates
666 aRetval.transform(rViewInformation.getInverseObjectToViewTransformation());
668 // expand by evtl. existing shadow primitives
669 if(impGetShadow3D())
671 const basegfx::B2DRange aShadow2DRange(maShadowPrimitives.getB2DRange(rViewInformation));
673 if(!aShadow2DRange.isEmpty())
675 aRetval.expand(aShadow2DRange);
679 return aRetval;
682 void ScenePrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
684 // get the involved ranges (see helper method calculateDiscreteSizes for details)
685 basegfx::B2DRange aDiscreteRange;
686 basegfx::B2DRange aUnitVisibleRange;
687 bool bNeedNewDecomposition(false);
688 bool bDiscreteSizesAreCalculated(false);
690 if(getBuffered2DDecomposition())
692 basegfx::B2DRange aVisibleDiscreteRange;
693 calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
694 bDiscreteSizesAreCalculated = true;
696 // needs to be painted when the new part is not part of the last
697 // decomposition
698 if(!maOldUnitVisiblePart.isInside(aUnitVisibleRange))
700 bNeedNewDecomposition = true;
703 // display has changed and cannot be reused when resolution got bigger. It
704 // can be reused when resolution got smaller, though.
705 if(!bNeedNewDecomposition)
707 if(basegfx::fTools::more(aDiscreteRange.getWidth(), mfOldDiscreteSizeX) ||
708 basegfx::fTools::more(aDiscreteRange.getHeight(), mfOldDiscreteSizeY))
710 bNeedNewDecomposition = true;
715 if(bNeedNewDecomposition)
717 // conditions of last local decomposition have changed, delete
718 const_cast< ScenePrimitive2D* >(this)->setBuffered2DDecomposition(nullptr);
721 if(!getBuffered2DDecomposition())
723 if(!bDiscreteSizesAreCalculated)
725 basegfx::B2DRange aVisibleDiscreteRange;
726 calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
729 // remember last used NewDiscreteSize and NewUnitVisiblePart
730 ScenePrimitive2D* pThat = const_cast< ScenePrimitive2D* >(this);
731 pThat->mfOldDiscreteSizeX = aDiscreteRange.getWidth();
732 pThat->mfOldDiscreteSizeY = aDiscreteRange.getHeight();
733 pThat->maOldUnitVisiblePart = aUnitVisibleRange;
736 // use parent implementation
737 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
740 // provide unique ID
741 sal_uInt32 ScenePrimitive2D::getPrimitive2DID() const
743 return PRIMITIVE2D_ID_SCENEPRIMITIVE2D;
746 } // end of namespace
748 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */