diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2021-12-12 14:18:23 +0100 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2021-12-15 13:34:51 +0100 |
commit | 90b925307da4066cd18fcbf31b903e948fa55e82 (patch) | |
tree | da55b28c5bc17f7e70f989da67bd912404e54c54 /svx | |
parent | fd06b1b2689d4189fd94beade3983af4acc5ffc3 (diff) |
tdf#145904,tdf#145956 improve extrusion of custom shapes
The patch addressed these errors:
The property Origin is relative to the bounding rectangle of the shape
not to the snap rectangle. That error is visible e.g. for a block arc.
Rotation center x- and y- values are relative to the snap rectangle and
not absolute.
Rotation center z-value is in Hmm and needs conversion to Twips in
Writer.
Rotation is around rotation center, which might be different from shape
center. That has been ignored.
I have moved calculation of the 2D logic rectangle of the scene to
main method to be able to reuse the transformation and other values.
I consider using a special local class as unneeded overhead.
I have reordered some parts to bring geometry relevant parts together.
Change-Id: I35ad0721091b365ae99cd3d7b2afb0ad7efe47fd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126847
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 453c5b6214654b440fe1d3e926cddfb695e17f10)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126868
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'svx')
-rw-r--r-- | svx/qa/unit/customshapes.cxx | 54 | ||||
-rwxr-xr-x | svx/qa/unit/data/tdf145904_center_Y0dot25.doc | bin | 0 -> 27136 bytes | |||
-rwxr-xr-x | svx/qa/unit/data/tdf145904_center_Y0dot25.odt | bin | 0 -> 10618 bytes | |||
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShape3d.cxx | 310 | ||||
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShape3d.hxx | 31 |
5 files changed, 195 insertions, 200 deletions
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx index 92fbfc9fa62e..84a18fc77b4d 100644 --- a/svx/qa/unit/customshapes.cxx +++ b/svx/qa/unit/customshapes.cxx @@ -127,6 +127,58 @@ void lcl_AssertRectEqualWithTolerance(std::string_view sInfo, const tools::Recta std::abs(rExpected.GetHeight() - rActual.GetHeight()) <= nTolerance); } +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145904_Extrusion_CenterY_odt) +{ + // The X- and Y-component of the extrusion rotation center specify the position as fraction of + // shape size. Error was, that the relative fraction was handled as absolute value in Hmm. + + // Load document + OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145904_center_Y0dot25.odt"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument"); + + // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape + // center and bottom shape edge. The bottom edge of the projected solid has roughly the + // y-coordinate of the rotation center. + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is()); + awt::Rectangle aBoundRect; + xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + awt::Point aAnchorPosition; + xPropSet->getPropertyValue("AnchorPosition") >>= aAnchorPosition; + sal_Int32 nActualTop = aBoundRect.Y - aAnchorPosition.Y; + + // Without the fix it would have failed with top = 2252. + // The tolerance 10 is estimated and can be adjusted if required for HiDPI. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop, 10); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145904_Extrusion_CenterY_doc) +{ + // The X- and Y-component of the extrusion rotation center specify the position as fraction of + // shape size. Error was, that the relative fraction was handled as absolute value in EMU. + + // Load document + OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145904_center_Y0dot25.doc"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument"); + + // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape + // center and bottom shape edge. The bottom edge of the projected solid has roughly the + // y-coordinate of the center. + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is()); + awt::Rectangle aBoundRect; + xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + awt::Point aAnchorPosition; + xPropSet->getPropertyValue("AnchorPosition") >>= aAnchorPosition; + sal_Int32 nActualTop = aBoundRect.Y - aAnchorPosition.Y; + + // Without the fix it would have failed with top = 2330 + // The tolerance 10 is estimated and can be adjusted if required for HiDPI. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop, 10); +} + CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145245_ExtrusionPosition) { // The second parameter of the extrusion-depth property specifies how much of the extrusion @@ -1002,7 +1054,7 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf141268) // Check left/bottom of bound rect. Without fix it would be left=6722, bottom=9483. tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect()); CPPUNIT_ASSERT_EQUAL(tools::Long(7620), aBoundRect.Left()); - CPPUNIT_ASSERT_EQUAL(tools::Long(8585), aBoundRect.Bottom()); + CPPUNIT_ASSERT_EQUAL(tools::Long(8584), aBoundRect.Bottom()); } CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf136176) diff --git a/svx/qa/unit/data/tdf145904_center_Y0dot25.doc b/svx/qa/unit/data/tdf145904_center_Y0dot25.doc Binary files differnew file mode 100755 index 000000000000..f4f9b28f2f03 --- /dev/null +++ b/svx/qa/unit/data/tdf145904_center_Y0dot25.doc diff --git a/svx/qa/unit/data/tdf145904_center_Y0dot25.odt b/svx/qa/unit/data/tdf145904_center_Y0dot25.odt Binary files differnew file mode 100755 index 000000000000..fcdbbff6c573 --- /dev/null +++ b/svx/qa/unit/data/tdf145904_center_Y0dot25.odt diff --git a/svx/source/customshapes/EnhancedCustomShape3d.cxx b/svx/source/customshapes/EnhancedCustomShape3d.cxx index bbad9f60753a..d378a0d1ff85 100644 --- a/svx/source/customshapes/EnhancedCustomShape3d.cxx +++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx @@ -172,80 +172,6 @@ drawing::Direction3D GetDirection3D( const SdrCustomShapeGeometryItem& rItem, co } -EnhancedCustomShape3d::Transformation2D::Transformation2D( - const SdrObjCustomShape& rSdrObjCustomShape, - const double *pMap) -: aCenter(rSdrObjCustomShape.GetSnapRect().Center()) - , eProjectionMode( drawing::ProjectionMode_PARALLEL ) - , fSkewAngle(0.0) - , fSkew(0.0) - , fOriginX(0.0) - , fOriginY(0.0) -{ - const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )); - const Any* pAny = rGeometryItem.GetPropertyValueByName( "Extrusion", "ProjectionMode" ); - if ( pAny ) - *pAny >>= eProjectionMode; - - if ( eProjectionMode == drawing::ProjectionMode_PARALLEL ) - GetSkew( rGeometryItem, fSkew, fSkewAngle ); - else - { - GetOrigin( rGeometryItem, fOriginX, fOriginY ); - fOriginX = fOriginX * rSdrObjCustomShape.GetLogicRect().GetWidth(); - fOriginY = fOriginY * rSdrObjCustomShape.GetLogicRect().GetHeight(); - - drawing::Position3D aViewPointDefault( 3472, -3472, 25000 ); - drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) ); - fViewPoint.setX(aViewPoint.PositionX); - fViewPoint.setY(aViewPoint.PositionY); - fViewPoint.setZ(-aViewPoint.PositionZ); - } -} - -basegfx::B3DPolygon EnhancedCustomShape3d::Transformation2D::ApplySkewSettings( const basegfx::B3DPolygon& rPoly3D ) const -{ - basegfx::B3DPolygon aRetval; - - sal_uInt32 j; - for ( j = 0; j < rPoly3D.count(); j++ ) - { - const basegfx::B3DPoint aPoint(rPoly3D.getB3DPoint(j)); - double fDepth(-( aPoint.getZ() * fSkew ) / 100.0); - aRetval.append(basegfx::B3DPoint( - aPoint.getX() + (fDepth * cos( fSkewAngle )), - aPoint.getY() - (fDepth * sin( fSkewAngle )), - aPoint.getZ())); - } - - return aRetval; -} - -Point EnhancedCustomShape3d::Transformation2D::Transform2D( const basegfx::B3DPoint& rPoint3D ) const -{ - Point aPoint2D; - if ( eProjectionMode == drawing::ProjectionMode_PARALLEL ) - { - aPoint2D.setX( static_cast<sal_Int32>(rPoint3D.getX()) ); - aPoint2D.setY( static_cast<sal_Int32>(rPoint3D.getY()) ); - } - else if (double fDiv = rPoint3D.getZ() - fViewPoint.getZ(); fDiv != 0.0) - { - double fX = rPoint3D.getX() - fOriginX; - double fY = rPoint3D.getY() - fOriginY; - double f = ( - fViewPoint.getZ() ) / fDiv; - aPoint2D.setX( static_cast<sal_Int32>(( fX - fViewPoint.getX() ) * f + fViewPoint.getX() + fOriginX ) ); - aPoint2D.setY( static_cast<sal_Int32>(( fY - fViewPoint.getY() ) * f + fViewPoint.getY() + fOriginY ) ); - } - aPoint2D.Move( aCenter.X(), aCenter.Y() ); - return aPoint2D; -} - -bool EnhancedCustomShape3d::Transformation2D::IsParallel() const -{ - return eProjectionMode == css::drawing::ProjectionMode_PARALLEL; -} - SdrObject* EnhancedCustomShape3d::Create3DObject( const SdrObject* pShape2d, const SdrObjCustomShape& rSdrObjCustomShape) @@ -313,7 +239,6 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( const Any* pAny = rGeometryItem.GetPropertyValueByName( "Extrusion", "ProjectionMode" ); if ( pAny ) *pAny >>= eProjectionMode; - ProjectionType eProjectionType( eProjectionMode == drawing::ProjectionMode_PARALLEL ? ProjectionType::Parallel : ProjectionType::Perspective ); // pShape2d Convert in scenes which include 3D Objects E3dDefaultAttributes a3DDefaultAttr; a3DDefaultAttr.SetDefaultLatheCharacterMode( true ); @@ -365,6 +290,7 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( } tools::Rectangle aBoundRect2d; + basegfx::B2DPolyPolygon aTotalPolyPoly; SdrObjListIter aIter( *pShape2d, SdrIterMode::DeepNoGroups ); const bool bMultipleSubObjects(aIter.Count() > 1); @@ -473,6 +399,7 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( const basegfx::B2DRange aTempRange(basegfx::utils::getRange(aPolyPoly)); const tools::Rectangle aBoundRect(basegfx::fround(aTempRange.getMinX()), basegfx::fround(aTempRange.getMinY()), basegfx::fround(aTempRange.getMaxX()), basegfx::fround(aTempRange.getMaxY())); + aTotalPolyPoly.append(aPolyPoly); aBoundRect2d.Union( aBoundRect ); // #i122777# depth 0 is okay for planes when using double-sided @@ -584,45 +511,73 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( // Camera settings, Perspective ... Camera3D rCamera = pScene->GetCamera(); - const basegfx::B3DRange& rVolume = pScene->GetBoundVolume(); pScene->NbcSetSnapRect( aSnapRect ); // InitScene replacement - double fW = rVolume.getWidth(); - double fH = rVolume.getHeight(); - + double fW = aBoundRect2d.getWidth(); + double fH = aBoundRect2d.getHeight(); rCamera.SetAutoAdjustProjection( false ); rCamera.SetViewWindow( -fW / 2, - fH / 2, fW, fH); basegfx::B3DPoint aLookAt( 0.0, 0.0, 0.0 ); basegfx::B3DPoint aCamPos( 0.0, 0.0, 100.0 ); rCamera.SetPosAndLookAt( aCamPos, aLookAt ); rCamera.SetFocalLength( 1.0 ); + ProjectionType eProjectionType( eProjectionMode == drawing::ProjectionMode_PARALLEL ? ProjectionType::Parallel : ProjectionType::Perspective ); rCamera.SetProjection( eProjectionType ); pScene->SetCamera( rCamera ); pScene->SetBoundAndSnapRectsDirty(); - double fOriginX, fOriginY; - GetOrigin( rGeometryItem, fOriginX, fOriginY ); - fOriginX = fOriginX * aSnapRect.GetWidth(); - fOriginY = fOriginY * aSnapRect.GetHeight(); - basegfx::B3DHomMatrix aNewTransform( pScene->GetTransform() ); - aNewTransform.translate( -aCenter.X(), aCenter.Y(), -pScene->GetBoundVolume().getDepth() ); + basegfx::B2DHomMatrix aPolyPolyTransform; + // Apply flip and z-rotation to scene transformation (y up). At same time transform + // aTotalPolyPoly (y down) which will be used for 2D boundRect of shape having 2D + // transformations applied. + + // API values use shape center as origin. Move scene so, that shape center is origin. + aNewTransform.translate( -aCenter.X(), aCenter.Y(), -fExtrusionBackward); + aPolyPolyTransform.translate(-aCenter.X(), -aCenter.Y()); - double fXRotate, fYRotate; - GetRotateAngle( rGeometryItem, fXRotate, fYRotate ); double fZRotate(basegfx::deg2rad(rSdrObjCustomShape.GetObjectRotation())); if ( fZRotate != 0.0 ) + { aNewTransform.rotate( 0.0, 0.0, fZRotate ); + aPolyPolyTransform.rotate(-fZRotate); + } if ( bIsMirroredX ) + { aNewTransform.scale( -1.0, 1, 1 ); + aPolyPolyTransform.scale(-1.0, 1); + } if ( bIsMirroredY ) + { aNewTransform.scale( 1, -1.0, 1 ); + aPolyPolyTransform.scale(1, -1.0); + } + aPolyPolyTransform.translate(aCenter.X(), aCenter.Y()); + aTotalPolyPoly.transform(aPolyPolyTransform); + + // x- and y-rotation have an own rotation center. x- and y-value of rotation center are + // fractions of shape size, z-value is in Hmm in property. Shape center is (0 0 0). + // Values in property are in custom shape extrusion space with y-axis down. + double fXRotate, fYRotate; + GetRotateAngle( rGeometryItem, fXRotate, fYRotate ); + drawing::Direction3D aRotationCenterDefault( 0, 0, 0 ); + drawing::Direction3D aRotationCenter( GetDirection3D( rGeometryItem, "RotationCenter", aRotationCenterDefault ) ); + aRotationCenter.DirectionX *= aSnapRect.getWidth(); + aRotationCenter.DirectionY *= aSnapRect.getHeight(); + if (pMap) + { + aRotationCenter.DirectionZ *= *pMap; + } + aNewTransform.translate( -aRotationCenter.DirectionX, aRotationCenter.DirectionY, -aRotationCenter.DirectionZ ); if( fYRotate != 0.0 ) aNewTransform.rotate( 0.0, -fYRotate, 0.0 ); if( fXRotate != 0.0 ) aNewTransform.rotate( -fXRotate, 0.0, 0.0 ); - if ( eProjectionType == ProjectionType::Parallel ) + aNewTransform.translate(aRotationCenter.DirectionX, -aRotationCenter.DirectionY, aRotationCenter.DirectionZ); + + // oblique parallel projection is done by shearing the object, not by moving the camera + if (eProjectionMode == drawing::ProjectionMode_PARALLEL) { double fSkew, fAlpha; GetSkew( rGeometryItem, fSkew, fAlpha ); @@ -636,6 +591,53 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( fInvTanBeta * sin(fAlpha)); } } + } + + pScene->NbcSetTransform( aNewTransform ); + + // These values are used later again, so declare them outside the if-statement. They will + // contain the absolute values of ViewPoint in 3D scene coordinate system, y-axis up. + double fViewPointX = 0; // dummy values + double fViewPointY = 0; + double fViewPointZ = 25000; + if (eProjectionMode == drawing::ProjectionMode_PERSPECTIVE) + { + double fOriginX, fOriginY; + // Calculate BoundRect of shape, including flip and z-rotation, from aTotalPolyPoly. + tools::Rectangle aBoundAfter2DTransform; // aBoundAfter2DTransform has y-axis down. + basegfx::B2DRange aTotalPolyPolyRange(aTotalPolyPoly.getB2DRange()); + aBoundAfter2DTransform.SetLeft(aTotalPolyPolyRange.getMinX()); + aBoundAfter2DTransform.SetTop(aTotalPolyPolyRange.getMinY()); + aBoundAfter2DTransform.SetRight(aTotalPolyPolyRange.getMaxX()); + aBoundAfter2DTransform.SetBottom(aTotalPolyPolyRange.getMaxY()); + + // Property "Origin" in API is relativ to bounding box of shape after 2D + // transformations. Range is [-0.5;0.5] with center of bounding box as 0. + // Resolve "Origin" fractions to length + GetOrigin( rGeometryItem, fOriginX, fOriginY ); + fOriginX *= aBoundAfter2DTransform.GetWidth(); + fOriginY *= aBoundAfter2DTransform.GetHeight(); + // Resolve length to absolute value for 3D + fOriginX += aBoundAfter2DTransform.Center().X(); + fOriginY += aBoundAfter2DTransform.Center().Y(); + fOriginY = - fOriginY; + // Scene is translated so that shape center is origin of coordinate system. + // Translate point "Origin" too. + fOriginX -= aCenter.X(); + fOriginY -= -aCenter.Y(); + // API ViewPoint values are relativ to point "Origin" and have y-axis down. + // ToDo: These default ViewPoint values are used as default by MS Office. But ODF + // default is (3500, -3500, 25000), details in tdf#146192. + drawing::Position3D aViewPointDefault( 3472, -3472, 25000 ); + drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) ); + fViewPointX = aViewPoint.PositionX + fOriginX; + fViewPointY = - aViewPoint.PositionY + fOriginY; + fViewPointZ = aViewPoint.PositionZ; + } + + // now set correct camera position + if (eProjectionMode == drawing::ProjectionMode_PARALLEL) + { basegfx::B3DPoint _aLookAt( 0.0, 0.0, 0.0 ); basegfx::B3DPoint _aNewCamPos( 0.0, 0.0, 25000.0 ); rCamera.SetPosAndLookAt( _aNewCamPos, _aLookAt ); @@ -643,20 +645,62 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( } else { - aNewTransform.translate( -fOriginX, fOriginY, 0.0 ); - // now set correct camera position - drawing::Position3D aViewPointDefault( 3472, -3472, 25000 ); - drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) ); - double fViewPointX = aViewPoint.PositionX; - double fViewPointY = aViewPoint.PositionY; - double fViewPointZ = aViewPoint.PositionZ; - basegfx::B3DPoint _aLookAt( fViewPointX, -fViewPointY, 0.0 ); - basegfx::B3DPoint aNewCamPos( fViewPointX, -fViewPointY, fViewPointZ ); + basegfx::B3DPoint _aLookAt(fViewPointX, fViewPointY, 0.0); + basegfx::B3DPoint aNewCamPos(fViewPointX, fViewPointY, fViewPointZ); rCamera.SetPosAndLookAt( aNewCamPos, _aLookAt ); pScene->SetCamera( rCamera ); } - pScene->NbcSetTransform( aNewTransform ); + // NbcSetTransform has not updated the scene 2D rectangles. + // Idea: Get a bound volume as polygon from bound rectangle of shape without 2D + // transfomations. Calculate its projection to the XY-plane. Then calculate the bounding + // rectangle of the projection and convert this rectangle back to absolut 2D coordinates. + // Set that as 2D rectangle of the scene. + const tools::Polygon aPolygon(aBoundRect2d); // y-up + basegfx::B3DPolygon aPolygonBoundVolume; // y-down, scene coordinates + for (sal_uInt16 i = 0; i < 4; i++ ) + { + aPolygonBoundVolume.append(basegfx::B3DPoint(aPolygon[i].X(), -aPolygon[i].Y(), 0)); + } + for (sal_uInt16 i = 0; i < 4; i++ ) + { + aPolygonBoundVolume.append(basegfx::B3DPoint(aPolygon[i].X(), -aPolygon[i].Y(), fDepth)); + } + aPolygonBoundVolume.transform(aNewTransform); + + // projection + tools::Polygon a2DProjectionResult(8); // in fact 3D points with z=0 + for (sal_uInt16 i = 0; i < 8; i++ ) + { + const basegfx::B3DPoint aPoint3D(aPolygonBoundVolume.getB3DPoint(i)); + + if (eProjectionMode == drawing::ProjectionMode_PARALLEL) + { + a2DProjectionResult[i].setX(aPoint3D.getX()); + a2DProjectionResult[i].setY(aPoint3D.getY()); + } + else + { + // skip point if line from viewpoint to point is parallel to xy-plane + if (double fDiv = aPoint3D.getZ() - fViewPointZ; fDiv != 0.0) + { + double f = (- fViewPointZ) / fDiv; + double fX = (aPoint3D.getX() - fViewPointX) * f + fViewPointX; + double fY = (aPoint3D.getY() - fViewPointY) * f + fViewPointY;; + a2DProjectionResult[i].setX(static_cast<sal_Int32>(fX)); + a2DProjectionResult[i].setY(static_cast<sal_Int32>(fY)); + } + } + } + // Convert to y-axis down + for (sal_uInt16 i = 0; i < 8; i++ ) + { + a2DProjectionResult[i].setY(- a2DProjectionResult[i].Y()); + } + // Shift back to shape center + a2DProjectionResult.Translate(aCenter); + + pScene->SetLogicRect(a2DProjectionResult.GetBoundRect()); // light @@ -760,13 +804,6 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection4Item(aSpotLight1)); } - pScene->SetLogicRect( - CalculateNewSnapRect( - rSdrObjCustomShape, - aSnapRect, - aBoundRect2d, - pMap)); - // removing placeholder objects for (E3dCompoundObject* pTemp : aPlaceholderObjectList) { @@ -786,67 +823,4 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( return pRet; } -tools::Rectangle EnhancedCustomShape3d::CalculateNewSnapRect( - const SdrObjCustomShape& rSdrObjCustomShape, - const tools::Rectangle& rSnapRect, - const tools::Rectangle& rBoundRect, - const double* pMap) -{ - const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )); - const Point aCenter( rSnapRect.Center() ); - double fExtrusionBackward, fExtrusionForward; - GetExtrusionDepth( rGeometryItem, pMap, fExtrusionBackward, fExtrusionForward ); - sal_uInt32 i; - - // creating initial bound volume ( without rotation. skewing.and camera ) - basegfx::B3DPolygon aBoundVolume; - const tools::Polygon aPolygon( rBoundRect ); - - for ( i = 0; i < 4; i++ ) - { - aBoundVolume.append(basegfx::B3DPoint(aPolygon[ static_cast<sal_uInt16>(i) ].X() - aCenter.X(), aPolygon[ static_cast<sal_uInt16>(i) ].Y() - aCenter.Y(), -fExtrusionForward)); - } - - for ( i = 0; i < 4; i++ ) - { - aBoundVolume.append(basegfx::B3DPoint(aPolygon[ static_cast<sal_uInt16>(i) ].X() - aCenter.X(), aPolygon[ static_cast<sal_uInt16>(i) ].Y() - aCenter.Y(), fExtrusionBackward)); - } - - drawing::Direction3D aRotationCenterDefault( 0, 0, 0 ); // default seems to be wrong, a fractional size of shape has to be used!! - drawing::Direction3D aRotationCenter( GetDirection3D( rGeometryItem, "RotationCenter", aRotationCenterDefault ) ); - - double fXRotate, fYRotate; - GetRotateAngle( rGeometryItem, fXRotate, fYRotate ); - double fZRotate(basegfx::deg2rad(rSdrObjCustomShape.GetObjectRotation())); - - // rotating bound volume - basegfx::B3DHomMatrix aMatrix; - aMatrix.translate(-aRotationCenter.DirectionX, -aRotationCenter.DirectionY, -aRotationCenter.DirectionZ); - if ( fZRotate != 0.0 ) - aMatrix.rotate( 0.0, 0.0, fZRotate ); - if (rSdrObjCustomShape.IsMirroredX()) - aMatrix.scale( -1.0, 1, 1 ); - if (rSdrObjCustomShape.IsMirroredY()) - aMatrix.scale( 1, -1.0, 1 ); - if( fYRotate != 0.0 ) - aMatrix.rotate( 0.0, fYRotate, 0.0 ); - if( fXRotate != 0.0 ) - aMatrix.rotate( -fXRotate, 0.0, 0.0 ); - aMatrix.translate(aRotationCenter.DirectionX, aRotationCenter.DirectionY, aRotationCenter.DirectionZ); - aBoundVolume.transform(aMatrix); - - Transformation2D aTransformation2D( - rSdrObjCustomShape, - pMap); - - if ( aTransformation2D.IsParallel() ) - aBoundVolume = aTransformation2D.ApplySkewSettings( aBoundVolume ); - - tools::Polygon aTransformed( 8 ); - for ( i = 0; i < 8; i++ ) - aTransformed[ static_cast<sal_uInt16>(i) ] = aTransformation2D.Transform2D( aBoundVolume.getB3DPoint( i ) ); - - return aTransformed.GetBoundRect(); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/customshapes/EnhancedCustomShape3d.hxx b/svx/source/customshapes/EnhancedCustomShape3d.hxx index 233b99441362..106edff9becd 100644 --- a/svx/source/customshapes/EnhancedCustomShape3d.hxx +++ b/svx/source/customshapes/EnhancedCustomShape3d.hxx @@ -31,37 +31,6 @@ class SdrObjCustomShape; class EnhancedCustomShape3d final { - class Transformation2D - { - Point aCenter; - css::drawing::ProjectionMode eProjectionMode; - - // parallel projection - double fSkewAngle; - double fSkew; // in percent - - // perspective projection - basegfx::B3DPoint fViewPoint; - double fOriginX; - double fOriginY; - - public: - Transformation2D( - const SdrObjCustomShape& rSdrObjCustomShape, - const double* pMap); - - basegfx::B3DPolygon ApplySkewSettings( const basegfx::B3DPolygon& rPolygon3D ) const; - Point Transform2D( const basegfx::B3DPoint& rPoint ) const; - bool IsParallel() const; - }; - - friend class Transformation2D; - - static tools::Rectangle CalculateNewSnapRect( - const SdrObjCustomShape& rSdrObjCustomShape, - const tools::Rectangle& rSnapRect, - const tools::Rectangle& rBoundRect, - const double* pMap); public: static SdrObject* Create3DObject( |