diff options
Diffstat (limited to 'drawinglayer/source/primitive3d')
20 files changed, 5119 insertions, 0 deletions
diff --git a/drawinglayer/source/primitive3d/baseprimitive3d.cxx b/drawinglayer/source/primitive3d/baseprimitive3d.cxx new file mode 100644 index 000000000000..d63d906139c6 --- /dev/null +++ b/drawinglayer/source/primitive3d/baseprimitive3d.cxx @@ -0,0 +1,278 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/baseprimitive3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <basegfx/tools/canvastools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + BasePrimitive3D::BasePrimitive3D() + : BasePrimitive3DImplBase(m_aMutex) + { + } + + BasePrimitive3D::~BasePrimitive3D() + { + } + + bool BasePrimitive3D::operator==( const BasePrimitive3D& rPrimitive ) const + { + return (getPrimitive3DID() == rPrimitive.getPrimitive3DID()); + } + + basegfx::B3DRange BasePrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + return getB3DRangeFromPrimitive3DSequence(get3DDecomposition(rViewInformation), rViewInformation); + } + + Primitive3DSequence BasePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return Primitive3DSequence(); + } + + Primitive3DSequence SAL_CALL BasePrimitive3D::getDecomposition( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException ) + { + const geometry::ViewInformation3D aViewInformation(rViewParameters); + return get3DDecomposition(rViewParameters); + } + + com::sun::star::geometry::RealRectangle3D SAL_CALL BasePrimitive3D::getRange( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException ) + { + const geometry::ViewInformation3D aViewInformation(rViewParameters); + return basegfx::unotools::rectangle3DFromB3DRectangle(getB3DRange(aViewInformation)); + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence BufferedDecompositionPrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return Primitive3DSequence(); + } + + BufferedDecompositionPrimitive3D::BufferedDecompositionPrimitive3D() + : BasePrimitive3D(), + maBuffered3DDecomposition() + { + } + + Primitive3DSequence BufferedDecompositionPrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!getBuffered3DDecomposition().hasElements()) + { + const Primitive3DSequence aNewSequence(create3DDecomposition(rViewInformation)); + const_cast< BufferedDecompositionPrimitive3D* >(this)->setBuffered3DDecomposition(aNewSequence); + } + + return getBuffered3DDecomposition(); + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// tooling + +namespace drawinglayer +{ + namespace primitive3d + { + // get range3D from a given Primitive3DReference + basegfx::B3DRange getB3DRangeFromPrimitive3DReference(const Primitive3DReference& rCandidate, const geometry::ViewInformation3D& aViewInformation) + { + basegfx::B3DRange aRetval; + + if(rCandidate.is()) + { + // try to get C++ implementation base + const BasePrimitive3D* pCandidate(dynamic_cast< BasePrimitive3D* >(rCandidate.get())); + + if(pCandidate) + { + // use it if possible + aRetval.expand(pCandidate->getB3DRange(aViewInformation)); + } + else + { + // use UNO API call instead + const uno::Sequence< beans::PropertyValue >& rViewParameters(aViewInformation.getViewInformationSequence()); + aRetval.expand(basegfx::unotools::b3DRectangleFromRealRectangle3D(rCandidate->getRange(rViewParameters))); + } + } + + return aRetval; + } + + // get range3D from a given Primitive3DSequence + basegfx::B3DRange getB3DRangeFromPrimitive3DSequence(const Primitive3DSequence& rCandidate, const geometry::ViewInformation3D& aViewInformation) + { + basegfx::B3DRange aRetval; + + if(rCandidate.hasElements()) + { + const sal_Int32 nCount(rCandidate.getLength()); + + for(sal_Int32 a(0L); a < nCount; a++) + { + aRetval.expand(getB3DRangeFromPrimitive3DReference(rCandidate[a], aViewInformation)); + } + } + + return aRetval; + } + + bool arePrimitive3DReferencesEqual(const Primitive3DReference& rxA, const Primitive3DReference& rxB) + { + const sal_Bool bAIs(rxA.is()); + + if(bAIs != rxB.is()) + { + return false; + } + + if(!bAIs) + { + return true; + } + + const BasePrimitive3D* pA(dynamic_cast< const BasePrimitive3D* >(rxA.get())); + const BasePrimitive3D* pB(dynamic_cast< const BasePrimitive3D* >(rxB.get())); + const bool bAEqualZero(pA == 0L); + + if(bAEqualZero != (pB == 0L)) + { + return false; + } + + if(bAEqualZero) + { + return false; + } + + return (pA->operator==(*pB)); + } + + bool arePrimitive3DSequencesEqual(const Primitive3DSequence& rA, const Primitive3DSequence& rB) + { + const sal_Bool bAHasElements(rA.hasElements()); + + if(bAHasElements != rB.hasElements()) + { + return false; + } + + if(!bAHasElements) + { + return true; + } + + const sal_Int32 nCount(rA.getLength()); + + if(nCount != rB.getLength()) + { + return false; + } + + for(sal_Int32 a(0L); a < nCount; a++) + { + if(!arePrimitive3DReferencesEqual(rA[a], rB[a])) + { + return false; + } + } + + return true; + } + + // concatenate sequence + void appendPrimitive3DSequenceToPrimitive3DSequence(Primitive3DSequence& rDest, const Primitive3DSequence& rSource) + { + if(rSource.hasElements()) + { + if(rDest.hasElements()) + { + const sal_Int32 nSourceCount(rSource.getLength()); + const sal_Int32 nDestCount(rDest.getLength()); + const sal_Int32 nTargetCount(nSourceCount + nDestCount); + sal_Int32 nInsertPos(nDestCount); + + rDest.realloc(nTargetCount); + + for(sal_Int32 a(0L); a < nSourceCount; a++) + { + if(rSource[a].is()) + { + rDest[nInsertPos++] = rSource[a]; + } + } + + if(nInsertPos != nTargetCount) + { + rDest.realloc(nInsertPos); + } + } + else + { + rDest = rSource; + } + } + } + + // concatenate single Primitive3D + void appendPrimitive3DReferenceToPrimitive3DSequence(Primitive3DSequence& rDest, const Primitive3DReference& rSource) + { + if(rSource.is()) + { + const sal_Int32 nDestCount(rDest.getLength()); + rDest.realloc(nDestCount + 1L); + rDest[nDestCount] = rSource; + } + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/groupprimitive3d.cxx b/drawinglayer/source/primitive3d/groupprimitive3d.cxx new file mode 100644 index 000000000000..8ad65676cf24 --- /dev/null +++ b/drawinglayer/source/primitive3d/groupprimitive3d.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/groupprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + GroupPrimitive3D::GroupPrimitive3D( const Primitive3DSequence& rChildren ) + : BasePrimitive3D(), + maChildren(rChildren) + { + } + + /** The compare opertator uses the Sequence::==operator, so only checking if + the rererences are equal. All non-equal references are interpreted as + non-equal. + */ + bool GroupPrimitive3D::operator==( const BasePrimitive3D& rPrimitive ) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const GroupPrimitive3D& rCompare = static_cast< const GroupPrimitive3D& >(rPrimitive); + + return (arePrimitive3DSequencesEqual(getChildren(), rCompare.getChildren())); + } + + return false; + } + + /// default: just return children, so all renderers not supporting group will use it's content + Primitive3DSequence GroupPrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return getChildren(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(GroupPrimitive3D, PRIMITIVE3D_ID_GROUPPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx b/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx new file mode 100644 index 000000000000..5dbdce756a5a --- /dev/null +++ b/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx @@ -0,0 +1,319 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/range/b2drange.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence HatchTexturePrimitive3D::impCreate3DDecomposition() const + { + Primitive3DSequence aRetval; + + if(getChildren().hasElements()) + { + const Primitive3DSequence aSource(getChildren()); + const sal_uInt32 nSourceCount(aSource.getLength()); + std::vector< Primitive3DReference > aDestination; + + for(sal_uInt32 a(0); a < nSourceCount; a++) + { + // get reference + const Primitive3DReference xReference(aSource[a]); + + if(xReference.is()) + { + // try to cast to BasePrimitive2D implementation + const BasePrimitive3D* pBasePrimitive = dynamic_cast< const BasePrimitive3D* >(xReference.get()); + + if(pBasePrimitive) + { + // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch + // not all content is needed, remove transparencies and ModifiedColorPrimitives + switch(pBasePrimitive->getPrimitive3DID()) + { + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // polyPolygonMaterialPrimitive3D, check texturing and hatching + const PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const PolyPolygonMaterialPrimitive3D& >(*pBasePrimitive); + const basegfx::B3DPolyPolygon aFillPolyPolygon(rPrimitive.getB3DPolyPolygon()); + + if(maHatch.isFillBackground()) + { + // add original primitive for background + aDestination.push_back(xReference); + } + + if(aFillPolyPolygon.areTextureCoordinatesUsed()) + { + const sal_uInt32 nPolyCount(aFillPolyPolygon.count()); + basegfx::B2DPolyPolygon aTexPolyPolygon; + basegfx::B2DPoint a2N; + basegfx::B2DVector a2X, a2Y; + basegfx::B3DPoint a3N; + basegfx::B3DVector a3X, a3Y; + bool b2N(false), b2X(false), b2Y(false); + + for(sal_uInt32 b(0); b < nPolyCount; b++) + { + const basegfx::B3DPolygon aPartPoly(aFillPolyPolygon.getB3DPolygon(b)); + const sal_uInt32 nPointCount(aPartPoly.count()); + basegfx::B2DPolygon aTexPolygon; + + for(sal_uInt32 c(0); c < nPointCount; c++) + { + const basegfx::B2DPoint a2Candidate(aPartPoly.getTextureCoordinate(c)); + + if(!b2N) + { + a2N = a2Candidate; + a3N = aPartPoly.getB3DPoint(c); + b2N = true; + } + else if(!b2X && !a2N.equal(a2Candidate)) + { + a2X = a2Candidate - a2N; + a3X = aPartPoly.getB3DPoint(c) - a3N; + b2X = true; + } + else if(!b2Y && !a2N.equal(a2Candidate) && !a2X.equal(a2Candidate)) + { + a2Y = a2Candidate - a2N; + + const double fCross(a2X.cross(a2Y)); + + if(!basegfx::fTools::equalZero(fCross)) + { + a3Y = aPartPoly.getB3DPoint(c) - a3N; + b2Y = true; + } + } + + aTexPolygon.append(a2Candidate); + } + + aTexPolygon.setClosed(true); + aTexPolyPolygon.append(aTexPolygon); + } + + if(b2N && b2X && b2Y) + { + // found two linearly independent 2D vectors + // get 2d range of texture coordinates + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aTexPolyPolygon)); + const basegfx::BColor aHatchColor(getHatch().getColor()); + const double fAngle(-getHatch().getAngle()); + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + + // get hatch transformations + switch(getHatch().getStyle()) + { + case attribute::HATCHSTYLE_TRIPLE: + { + // rotated 45 degrees + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle + F_PI4); + aHatch.appendTransformations(aMatrices); + } + case attribute::HATCHSTYLE_DOUBLE: + { + // rotated 90 degrees + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle + F_PI2); + aHatch.appendTransformations(aMatrices); + } + case attribute::HATCHSTYLE_SINGLE: + { + // angle as given + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle); + aHatch.appendTransformations(aMatrices); + } + } + + // create geometry from unit line + basegfx::B2DPolyPolygon a2DHatchLines; + basegfx::B2DPolygon a2DUnitLine; + a2DUnitLine.append(basegfx::B2DPoint(0.0, 0.0)); + a2DUnitLine.append(basegfx::B2DPoint(1.0, 0.0)); + + for(sal_uInt32 c(0); c < aMatrices.size(); c++) + { + const basegfx::B2DHomMatrix& rMatrix = aMatrices[c]; + basegfx::B2DPolygon aNewLine(a2DUnitLine); + aNewLine.transform(rMatrix); + a2DHatchLines.append(aNewLine); + } + + if(a2DHatchLines.count()) + { + // clip against texture polygon + a2DHatchLines = basegfx::tools::clipPolyPolygonOnPolyPolygon(a2DHatchLines, aTexPolyPolygon, true, true); + } + + if(a2DHatchLines.count()) + { + // create 2d matrix with 2d vectors as column vectors and 2d point as offset, this represents + // a coordinate system transformation from unit coordinates to the new coordinate system + basegfx::B2DHomMatrix a2D; + a2D.set(0, 0, a2X.getX()); + a2D.set(1, 0, a2X.getY()); + a2D.set(0, 1, a2Y.getX()); + a2D.set(1, 1, a2Y.getY()); + a2D.set(0, 2, a2N.getX()); + a2D.set(1, 2, a2N.getY()); + + // invert that transformation, so we have a back-transformation from texture coordinates + // to unit coordinates + a2D.invert(); + a2DHatchLines.transform(a2D); + + // expand back-transformated geometry tpo 3D + basegfx::B3DPolyPolygon a3DHatchLines(basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon(a2DHatchLines, 0.0)); + + // create 3d matrix with 3d vectors as column vectors (0,0,1 as Z) and 3d point as offset, this represents + // a coordinate system transformation from unit coordinates to the object's 3d coordinate system + basegfx::B3DHomMatrix a3D; + a3D.set(0, 0, a3X.getX()); + a3D.set(1, 0, a3X.getY()); + a3D.set(2, 0, a3X.getZ()); + a3D.set(0, 1, a3Y.getX()); + a3D.set(1, 1, a3Y.getY()); + a3D.set(2, 1, a3Y.getZ()); + a3D.set(0, 3, a3N.getX()); + a3D.set(1, 3, a3N.getY()); + a3D.set(2, 3, a3N.getZ()); + + // transform hatch lines to 3D object coordinates + a3DHatchLines.transform(a3D); + + // build primitives from this geometry + const sal_uInt32 nHatchLines(a3DHatchLines.count()); + + for(sal_uInt32 d(0); d < nHatchLines; d++) + { + const Primitive3DReference xRef(new PolygonHairlinePrimitive3D(a3DHatchLines.getB3DPolygon(d), aHatchColor)); + aDestination.push_back(xRef); + } + } + } + } + + break; + } + default : + { + // add reference to result + aDestination.push_back(xReference); + break; + } + } + } + else + { + // unknown implementation, add to result + aDestination.push_back(xReference); + } + } + } + + // prepare return value + const sal_uInt32 nDestSize(aDestination.size()); + aRetval.realloc(nDestSize); + + for(sal_uInt32 b(0); b < nDestSize; b++) + { + aRetval[b] = aDestination[b]; + } + } + + return aRetval; + } + + HatchTexturePrimitive3D::HatchTexturePrimitive3D( + const attribute::FillHatchAttribute& rHatch, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, + bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maHatch(rHatch), + maBuffered3DDecomposition() + { + } + + bool HatchTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const HatchTexturePrimitive3D& rCompare = (HatchTexturePrimitive3D&)rPrimitive; + + return (getHatch() == rCompare.getHatch()); + } + + return false; + } + + Primitive3DSequence HatchTexturePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!getBuffered3DDecomposition().hasElements()) + { + const Primitive3DSequence aNewSequence(impCreate3DDecomposition()); + const_cast< HatchTexturePrimitive3D* >(this)->setBuffered3DDecomposition(aNewSequence); + } + + return getBuffered3DDecomposition(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(HatchTexturePrimitive3D, PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/hiddengeometryprimitive3d.cxx b/drawinglayer/source/primitive3d/hiddengeometryprimitive3d.cxx new file mode 100644 index 000000000000..e94eeb99f764 --- /dev/null +++ b/drawinglayer/source/primitive3d/hiddengeometryprimitive3d.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hittestprimitive3d.cxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/25 17:12:14 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/hiddengeometryprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + HiddenGeometryPrimitive3D::HiddenGeometryPrimitive3D( + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren) + { + } + + basegfx::B3DRange HiddenGeometryPrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + return getB3DRangeFromPrimitive3DSequence(getChildren(), rViewInformation); + } + + Primitive3DSequence HiddenGeometryPrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // return empty sequence + return Primitive3DSequence(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(HiddenGeometryPrimitive3D, PRIMITIVE3D_ID_HIDDENGEOMETRYPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/makefile.mk b/drawinglayer/source/primitive3d/makefile.mk new file mode 100644 index 000000000000..afad990c0e28 --- /dev/null +++ b/drawinglayer/source/primitive3d/makefile.mk @@ -0,0 +1,62 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=primitive3d +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/baseprimitive3d.obj \ + $(SLO)$/groupprimitive3d.obj \ + $(SLO)$/hatchtextureprimitive3d.obj \ + $(SLO)$/hiddengeometryprimitive3d.obj \ + $(SLO)$/modifiedcolorprimitive3d.obj \ + $(SLO)$/polypolygonprimitive3d.obj \ + $(SLO)$/polygonprimitive3d.obj \ + $(SLO)$/polygontubeprimitive3d.obj \ + $(SLO)$/sdrcubeprimitive3d.obj \ + $(SLO)$/sdrdecompositiontools3d.obj \ + $(SLO)$/sdrextrudelathetools3d.obj \ + $(SLO)$/sdrextrudeprimitive3d.obj \ + $(SLO)$/sdrlatheprimitive3d.obj \ + $(SLO)$/sdrpolypolygonprimitive3d.obj \ + $(SLO)$/sdrprimitive3d.obj \ + $(SLO)$/sdrsphereprimitive3d.obj \ + $(SLO)$/shadowprimitive3d.obj \ + $(SLO)$/textureprimitive3d.obj \ + $(SLO)$/transformprimitive3d.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx b/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx new file mode 100644 index 000000000000..d840aaf49278 --- /dev/null +++ b/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + ModifiedColorPrimitive3D::ModifiedColorPrimitive3D( + const Primitive3DSequence& rChildren, + const basegfx::BColorModifier& rColorModifier) + : GroupPrimitive3D(rChildren), + maColorModifier(rColorModifier) + { + } + + bool ModifiedColorPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const ModifiedColorPrimitive3D& rCompare = (ModifiedColorPrimitive3D&)rPrimitive; + + return (maColorModifier == rCompare.maColorModifier); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(ModifiedColorPrimitive3D, PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polygonprimitive3d.cxx b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx new file mode 100644 index 000000000000..9899e565f69c --- /dev/null +++ b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx @@ -0,0 +1,178 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/polygontubeprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + PolygonHairlinePrimitive3D::PolygonHairlinePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const basegfx::BColor& rBColor) + : BasePrimitive3D(), + maPolygon(rPolygon), + maBColor(rBColor) + { + } + + bool PolygonHairlinePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const PolygonHairlinePrimitive3D& rCompare = (PolygonHairlinePrimitive3D&)rPrimitive; + + return (getB3DPolygon() == rCompare.getB3DPolygon() + && getBColor() == rCompare.getBColor()); + } + + return false; + } + + basegfx::B3DRange PolygonHairlinePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return basegfx::tools::getRange(getB3DPolygon()); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonHairlinePrimitive3D, PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence PolygonStrokePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + + if(getB3DPolygon().count()) + { + basegfx::B3DPolyPolygon aHairLinePolyPolygon; + + if(0.0 == getStrokeAttribute().getFullDotDashLen()) + { + aHairLinePolyPolygon = basegfx::B3DPolyPolygon(getB3DPolygon()); + } + else + { + // apply LineStyle + basegfx::tools::applyLineDashing(getB3DPolygon(), getStrokeAttribute().getDotDashArray(), &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen()); + } + + // prepare result + aRetval.realloc(aHairLinePolyPolygon.count()); + + if(getLineAttribute().getWidth()) + { + // create fat line data + const double fRadius(getLineAttribute().getWidth() / 2.0); + const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin()); + + for(sal_uInt32 a(0L); a < aHairLinePolyPolygon.count(); a++) + { + // create tube primitives + const Primitive3DReference xRef(new PolygonTubePrimitive3D(aHairLinePolyPolygon.getB3DPolygon(a), getLineAttribute().getColor(), fRadius, aLineJoin)); + aRetval[a] = xRef; + } + } + else + { + // create hair line data for all sub polygons + for(sal_uInt32 a(0L); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B3DPolygon aCandidate = aHairLinePolyPolygon.getB3DPolygon(a); + const Primitive3DReference xRef(new PolygonHairlinePrimitive3D(aCandidate, getLineAttribute().getColor())); + aRetval[a] = xRef; + } + } + } + + return aRetval; + } + + PolygonStrokePrimitive3D::PolygonStrokePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const attribute::LineAttribute& rLineAttribute, + const attribute::StrokeAttribute& rStrokeAttribute) + : BufferedDecompositionPrimitive3D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute(rStrokeAttribute) + { + } + + PolygonStrokePrimitive3D::PolygonStrokePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const attribute::LineAttribute& rLineAttribute) + : BufferedDecompositionPrimitive3D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute() + { + } + + bool PolygonStrokePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BufferedDecompositionPrimitive3D::operator==(rPrimitive)) + { + const PolygonStrokePrimitive3D& rCompare = (PolygonStrokePrimitive3D&)rPrimitive; + + return (getB3DPolygon() == rCompare.getB3DPolygon() + && getLineAttribute() == rCompare.getLineAttribute() + && getStrokeAttribute() == rCompare.getStrokeAttribute()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonStrokePrimitive3D, PRIMITIVE3D_ID_POLYGONSTROKEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx new file mode 100644 index 000000000000..7b5f183575b2 --- /dev/null +++ b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx @@ -0,0 +1,579 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/polygontubeprimitive3d.hxx> +#include <drawinglayer/attribute/materialattribute3d.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + namespace // anonymous namespace + { + Primitive3DSequence getLineTubeSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial) + { + // static data for buffered tube primitives + static Primitive3DSequence aLineTubeList; + static sal_uInt32 nLineTubeSegments(0L); + static attribute::MaterialAttribute3D aLineMaterial; + + // may exclusively change static data, use mutex + ::osl::Mutex m_mutex; + + if(nSegments != nLineTubeSegments || !(rMaterial == aLineMaterial)) + { + nLineTubeSegments = nSegments; + aLineMaterial = rMaterial; + aLineTubeList = Primitive3DSequence(); + } + + if(!aLineTubeList.hasElements() && 0L != nLineTubeSegments) + { + const basegfx::B3DPoint aLeft(0.0, 0.0, 0.0); + const basegfx::B3DPoint aRight(1.0, 0.0, 0.0); + basegfx::B3DPoint aLastLeft(0.0, 1.0, 0.0); + basegfx::B3DPoint aLastRight(1.0, 1.0, 0.0); + basegfx::B3DHomMatrix aRot; + aRot.rotate(F_2PI / (double)nLineTubeSegments, 0.0, 0.0); + aLineTubeList.realloc(nLineTubeSegments); + + for(sal_uInt32 a(0L); a < nLineTubeSegments; a++) + { + const basegfx::B3DPoint aNextLeft(aRot * aLastLeft); + const basegfx::B3DPoint aNextRight(aRot * aLastRight); + basegfx::B3DPolygon aNewPolygon; + + aNewPolygon.append(aNextLeft); + aNewPolygon.setNormal(0L, basegfx::B3DVector(aNextLeft - aLeft)); + + aNewPolygon.append(aLastLeft); + aNewPolygon.setNormal(1L, basegfx::B3DVector(aLastLeft - aLeft)); + + aNewPolygon.append(aLastRight); + aNewPolygon.setNormal(2L, basegfx::B3DVector(aLastRight - aRight)); + + aNewPolygon.append(aNextRight); + aNewPolygon.setNormal(3L, basegfx::B3DVector(aNextRight - aRight)); + + aNewPolygon.setClosed(true); + + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); + aLineTubeList[a] = xRef; + + aLastLeft = aNextLeft; + aLastRight = aNextRight; + } + } + + return aLineTubeList; + } + + Primitive3DSequence getLineCapSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial) + { + // static data for buffered tube primitives + static Primitive3DSequence aLineCapList; + static sal_uInt32 nLineCapSegments(0L); + static attribute::MaterialAttribute3D aLineMaterial; + + // may exclusively change static data, use mutex + ::osl::Mutex m_mutex; + + if(nSegments != nLineCapSegments || !(rMaterial == aLineMaterial)) + { + nLineCapSegments = nSegments; + aLineMaterial = rMaterial; + aLineCapList = Primitive3DSequence(); + } + + if(!aLineCapList.hasElements() && 0L != nLineCapSegments) + { + const basegfx::B3DPoint aNull(0.0, 0.0, 0.0); + basegfx::B3DPoint aLast(0.0, 1.0, 0.0); + basegfx::B3DHomMatrix aRot; + aRot.rotate(F_2PI / (double)nLineCapSegments, 0.0, 0.0); + aLineCapList.realloc(nLineCapSegments); + + for(sal_uInt32 a(0L); a < nLineCapSegments; a++) + { + const basegfx::B3DPoint aNext(aRot * aLast); + basegfx::B3DPolygon aNewPolygon; + + aNewPolygon.append(aLast); + aNewPolygon.setNormal(0L, basegfx::B3DVector(aLast - aNull)); + + aNewPolygon.append(aNext); + aNewPolygon.setNormal(1L, basegfx::B3DVector(aNext - aNull)); + + aNewPolygon.append(aNull); + aNewPolygon.setNormal(2L, basegfx::B3DVector(-1.0, 0.0, 0.0)); + + aNewPolygon.setClosed(true); + + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); + aLineCapList[a] = xRef; + + aLast = aNext; + } + } + + return aLineCapList; + } + + Primitive3DSequence getLineJoinSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial, + double fAngle, + double /*fDegreeStepWidth*/, + double fMiterMinimumAngle, + basegfx::B2DLineJoin aLineJoin) + { + // nSegments is for whole circle, adapt to half circle + const sal_uInt32 nVerSeg(nSegments >> 1L); + std::vector< BasePrimitive3D* > aResultVector; + + if(nVerSeg) + { + if(basegfx::B2DLINEJOIN_ROUND == aLineJoin) + { + // calculate new horizontal segments + const sal_uInt32 nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments)); + + if(nHorSeg) + { + // create half-sphere + const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle)); + + for(sal_uInt32 a(0L); a < aSphere.count(); a++) + { + const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a)); + const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aPartPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + } + else + { + // fallback to bevel when there is not at least one segment hor and ver + aLineJoin = basegfx::B2DLINEJOIN_BEVEL; + } + } + + if(basegfx::B2DLINEJOIN_MIDDLE == aLineJoin + || basegfx::B2DLINEJOIN_BEVEL == aLineJoin + || basegfx::B2DLINEJOIN_MITER == aLineJoin) + { + if(basegfx::B2DLINEJOIN_MITER == aLineJoin) + { + const double fMiterAngle(fAngle/2.0); + + if(fMiterAngle < fMiterMinimumAngle) + { + // fallback to bevel when miter's angle is too small + aLineJoin = basegfx::B2DLINEJOIN_BEVEL; + } + } + + const double fInc(F_PI / (double)nVerSeg); + const double fSin(sin(-fAngle)); + const double fCos(cos(-fAngle)); + const bool bMiter(basegfx::B2DLINEJOIN_MITER == aLineJoin); + const double fMiterSin(bMiter ? sin(-(fAngle/2.0)) : 0.0); + const double fMiterCos(bMiter ? cos(-(fAngle/2.0)) : 0.0); + double fPos(-F_PI2); + basegfx::B3DPoint aPointOnXY, aPointRotY, aNextPointOnXY, aNextPointRotY; + basegfx::B3DPoint aCurrMiter, aNextMiter; + basegfx::B3DPolygon aNewPolygon, aMiterPolygon; + + // close polygon + aNewPolygon.setClosed(true); + aMiterPolygon.setClosed(true); + + for(sal_uInt32 a(0L); a < nVerSeg; a++) + { + const bool bFirst(0L == a); + const bool bLast(a + 1L == nVerSeg); + + if(bFirst || !bLast) + { + fPos += fInc; + + aNextPointOnXY = basegfx::B3DPoint( + cos(fPos), + sin(fPos), + 0.0); + + aNextPointRotY = basegfx::B3DPoint( + aNextPointOnXY.getX() * fCos, + aNextPointOnXY.getY(), + aNextPointOnXY.getX() * fSin); + + if(bMiter) + { + aNextMiter = basegfx::B3DPoint( + aNextPointOnXY.getX(), + aNextPointOnXY.getY(), + fMiterSin * (aNextPointOnXY.getX() / fMiterCos)); + } + } + + if(bFirst) + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextMiter); + + aMiterPolygon.clear(); + aMiterPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aMiterPolygon.append(aNextMiter); + aMiterPolygon.append(aNextPointRotY); + } + else + { + aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextPointRotY); + } + } + else if(bLast) + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aNewPolygon.append(aCurrMiter); + aNewPolygon.append(aPointOnXY); + + aMiterPolygon.clear(); + aMiterPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aMiterPolygon.append(aPointRotY); + aMiterPolygon.append(aCurrMiter); + } + else + { + aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aNewPolygon.append(aPointRotY); + aNewPolygon.append(aPointOnXY); + } + } + else + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(aPointOnXY); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextMiter); + aNewPolygon.append(aCurrMiter); + + aMiterPolygon.clear(); + aMiterPolygon.append(aCurrMiter); + aMiterPolygon.append(aNextMiter); + aMiterPolygon.append(aNextPointRotY); + aMiterPolygon.append(aPointRotY); + } + else + { + aNewPolygon.append(aPointRotY); + aNewPolygon.append(aPointOnXY); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextPointRotY); + } + } + + // set normals + for(sal_uInt32 b(0L); b < aNewPolygon.count(); b++) + { + aNewPolygon.setNormal(b, basegfx::B3DVector(aNewPolygon.getB3DPoint(b))); + } + + // create primitive + if(aNewPolygon.count()) + { + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + + if(bMiter && aMiterPolygon.count()) + { + // set normals + for(sal_uInt32 c(0L); c < aMiterPolygon.count(); c++) + { + aMiterPolygon.setNormal(c, basegfx::B3DVector(aMiterPolygon.getB3DPoint(c))); + } + + // create primitive + const basegfx::B3DPolyPolygon aMiterPolyPolygon(aMiterPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aMiterPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + + // prepare next step + if(bFirst || !bLast) + { + aPointOnXY = aNextPointOnXY; + aPointRotY = aNextPointRotY; + + if(bMiter) + { + aCurrMiter = aNextMiter; + } + } + } + } + } + + Primitive3DSequence aRetval(aResultVector.size()); + + for(sal_uInt32 a(0L); a < aResultVector.size(); a++) + { + aRetval[a] = Primitive3DReference(aResultVector[a]); + } + + return aRetval; + } + + basegfx::B3DHomMatrix getRotationFromVector(const basegfx::B3DVector& rVector) + { + // build transformation from unit vector to vector + basegfx::B3DHomMatrix aRetval; + + // get applied rotations from angles in XY and in XZ (cartesian) + const double fRotInXY(atan2(rVector.getY(), rVector.getXZLength())); + const double fRotInXZ(atan2(-rVector.getZ(), rVector.getX())); + + // apply rotations. Rot around Z needs to be done first, so apply in two steps + aRetval.rotate(0.0, 0.0, fRotInXY); + aRetval.rotate(0.0, fRotInXZ, 0.0); + + return aRetval; + } + } // end of anonymous namespace + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + const sal_uInt32 nPointCount(getB3DPolygon().count()); + std::vector< BasePrimitive3D* > aResultVector; + + if(0L != nPointCount) + { + if(basegfx::fTools::more(getRadius(), 0.0)) + { + const attribute::MaterialAttribute3D aMaterial(getBColor()); + static sal_uInt32 nSegments(8L); // default for 3d line segments, for more quality just raise this value (in even steps) + const bool bClosed(getB3DPolygon().isClosed()); + const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin()); + const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1L); + basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L)); + basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0L)); + + for(sal_uInt32 a(0L); a < nLoopCount; a++) + { + // get next data + const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount)); + const basegfx::B3DVector aForw(aNext - aCurr); + const double fForwLen(aForw.getLength()); + + if(basegfx::fTools::more(fForwLen, 0.0)) + { + // get rotation from vector, this describes rotation from (1, 0, 0) to aForw + basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw)); + + // create default transformation with scale and rotate + basegfx::B3DHomMatrix aVectorTrans; + aVectorTrans.scale(fForwLen, getRadius(), getRadius()); + aVectorTrans *= aRotVector; + aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + if(bNoLineJoin || (!bClosed && !a)) + { + // line start edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, getLineCapSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedA); + } + else + { + const basegfx::B3DVector aBack(aCurr - aLast); + const double fCross(basegfx::cross(aBack, aForw).getLength()); + + if(!basegfx::fTools::equalZero(fCross)) + { + // line connect non-parallel, aBack, aForw, use getLineJoin() + const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2 + Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin())); + + // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack + basegfx::B3DHomMatrix aInvRotVector(aRotVector); + aInvRotVector.invert(); + basegfx::B3DVector aTransBack(aInvRotVector * aBack); + const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ())); + + // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X. + // Also apply usual scaling and translation + basegfx::B3DHomMatrix aSphereTrans; + aSphereTrans.rotate(0.0, F_PI2, 0.0); + aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0); + aSphereTrans *= aRotVector; + aSphereTrans.scale(getRadius(), getRadius(), getRadius()); + aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + // line start edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, aNewList); + aResultVector.push_back(pNewTransformedB); + } + } + + // create line segments, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedC = new TransformPrimitive3D(aVectorTrans, getLineTubeSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedC); + + if(bNoLineJoin || (!bClosed && ((a + 1L) == nLoopCount))) + { + // line end edge, first rotate (mirror) and translate, then use use aRotVector + basegfx::B3DHomMatrix aBackTrans; + aBackTrans.rotate(0.0, F_PI, 0.0); + aBackTrans.translate(1.0, 0.0, 0.0); + aBackTrans.scale(fForwLen, getRadius(), getRadius()); + aBackTrans *= aRotVector; + aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + // line end edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, getLineCapSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedD); + } + } + + // prepare next loop step + aLast = aCurr; + aCurr = aNext; + } + } + else + { + // create hairline + PolygonHairlinePrimitive3D* pNew = new PolygonHairlinePrimitive3D(getB3DPolygon(), getBColor()); + aResultVector.push_back(pNew); + } + } + + // prepare return value + Primitive3DSequence aRetval(aResultVector.size()); + + for(sal_uInt32 a(0L); a < aResultVector.size(); a++) + { + aRetval[a] = Primitive3DReference(aResultVector[a]); + } + + return aRetval; + } + + PolygonTubePrimitive3D::PolygonTubePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const basegfx::BColor& rBColor, + double fRadius, basegfx::B2DLineJoin aLineJoin, + double fDegreeStepWidth, + double fMiterMinimumAngle) + : PolygonHairlinePrimitive3D(rPolygon, rBColor), + maLast3DDecomposition(), + mfRadius(fRadius), + mfDegreeStepWidth(fDegreeStepWidth), + mfMiterMinimumAngle(fMiterMinimumAngle), + maLineJoin(aLineJoin) + { + } + + bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(PolygonHairlinePrimitive3D::operator==(rPrimitive)) + { + const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive; + + return (getRadius() == rCompare.getRadius() + && getDegreeStepWidth() == rCompare.getDegreeStepWidth() + && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle() + && getLineJoin() == rCompare.getLineJoin()); + } + + return false; + } + + Primitive3DSequence PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!getLast3DDecomposition().hasElements()) + { + const Primitive3DSequence aNewSequence(impCreate3DDecomposition(rViewInformation)); + const_cast< PolygonTubePrimitive3D* >(this)->setLast3DDecomposition(aNewSequence); + } + + return getLast3DDecomposition(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonTubePrimitive3D, PRIMITIVE3D_ID_POLYGONTUBEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx b/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx new file mode 100644 index 000000000000..b3e6655a001a --- /dev/null +++ b/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + PolyPolygonMaterialPrimitive3D::PolyPolygonMaterialPrimitive3D( + const basegfx::B3DPolyPolygon& rPolyPolygon, + const attribute::MaterialAttribute3D& rMaterial, + bool bDoubleSided) + : BasePrimitive3D(), + maPolyPolygon(rPolyPolygon), + maMaterial(rMaterial), + mbDoubleSided(bDoubleSided) + { + } + + bool PolyPolygonMaterialPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const PolyPolygonMaterialPrimitive3D& rCompare = (PolyPolygonMaterialPrimitive3D&)rPrimitive; + + return (getB3DPolyPolygon() == rCompare.getB3DPolyPolygon() + && getMaterial() == rCompare.getMaterial() + && getDoubleSided() == rCompare.getDoubleSided()); + } + + return false; + } + + basegfx::B3DRange PolyPolygonMaterialPrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return basegfx::tools::getRange(getB3DPolyPolygon()); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolyPolygonMaterialPrimitive3D, PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx new file mode 100644 index 000000000000..6dcea7b0d759 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrcubeprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrCubePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + Primitive3DSequence aRetval; + basegfx::B3DPolyPolygon aFill(basegfx::tools::createCubeFillPolyPolygonFromB3DRange(aUnitRange)); + + // normal creation + if(!getSdrLFSAttribute().getFill().isDefault()) + { + if(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind() + || ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()) + { + // create sphere normals + const basegfx::B3DPoint aCenter(basegfx::tools::getRange(aFill).getCenter()); + aFill = basegfx::tools::applyDefaultNormalsSphere(aFill, aCenter); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + // invert normals + aFill = basegfx::tools::invertNormals(aFill); + } + } + + // texture coordinates + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bSphereX(!bParallelX && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX())); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bSphereY(!bParallelY && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY())); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY); + } + + if(bSphereX || bSphereY) + { + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + const basegfx::B3DPoint aCenter(aRange.getCenter()); + aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter, bSphereX, bSphereY); + } + + if(bObjectSpecificX || bObjectSpecificY) + { + // object-specific + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + basegfx::B3DPolygon aTmpPoly(aFill.getB3DPolygon(a)); + + if(aTmpPoly.count() >= 4L) + { + for(sal_uInt32 b(0L); b < 4L; b++) + { + basegfx::B2DPoint aPoint(aTmpPoly.getTextureCoordinate(b)); + + if(bObjectSpecificX) + { + aPoint.setX((1L == b || 2L == b) ? 1.0 : 0.0); + } + + if(bObjectSpecificY) + { + aPoint.setY((2L == b || 3L == b) ? 1.0 : 0.0); + } + + aTmpPoly.setTextureCoordinate(b, aPoint); + } + + aFill.setB3DPolygon(a, aTmpPoly); + } + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY()); + aFill.transformTextureCoordiantes(aTexMatrix); + } + + // build vector of PolyPolygons + ::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector; + + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a))); + } + + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + aRetval = createHiddenGeometryPrimitives3D( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute()); + } + + // add line + if(!getSdrLFSAttribute().getLine().isDefault()) + { + basegfx::B3DPolyPolygon aLine(basegfx::tools::createCubePolyPolygonFromB3DRange(aUnitRange)); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( + aLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(!getSdrLFSAttribute().getShadow().isDefault() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D( + aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + + return aRetval; + } + + SdrCubePrimitive3D::SdrCubePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute) + { + } + + bool SdrCubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + return SdrPrimitive3D::operator==(rPrimitive); + } + + basegfx::B3DRange SdrCubePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2. + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return getStandard3DRange(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrCubePrimitive3D, PRIMITIVE3D_ID_SDRCUBEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx new file mode 100644 index 000000000000..471d18ed846e --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx @@ -0,0 +1,339 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <drawinglayer/attribute/strokeattribute.hxx> +#include <drawinglayer/primitive3d/baseprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <vcl/vclenum.hxx> +#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <vcl/bmpacc.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/shadowprimitive3d.hxx> +#include <basegfx/range/b2drange.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrobjectattribute3d.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> +#include <drawinglayer/primitive3d/hiddengeometryprimitive3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + basegfx::B3DRange getRangeFrom3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + basegfx::B3DRange aRetval; + + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + aRetval.expand(basegfx::tools::getRange(rFill[a])); + } + + return aRetval; + } + + void applyNormalsKindSphereTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill, const basegfx::B3DRange& rRange) + { + // create sphere normals + const basegfx::B3DPoint aCenter(rRange.getCenter()); + + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultNormalsSphere(rFill[a], aCenter); + } + } + + void applyNormalsKindFlatTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a].clearNormals(); + } + } + + void applyNormalsInvertTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + // invert normals + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::invertNormals(rFill[a]); + } + } + + void applyTextureTo3DGeometry( + ::com::sun::star::drawing::TextureProjectionMode eModeX, + ::com::sun::star::drawing::TextureProjectionMode eModeY, + ::std::vector< basegfx::B3DPolyPolygon >& rFill, + const basegfx::B3DRange& rRange, + const basegfx::B2DVector& rTextureSize) + { + sal_uInt32 a; + + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == eModeX); + const bool bSphereX(!bParallelX && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == eModeX)); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == eModeY); + const bool bSphereY(!bParallelY && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == eModeY)); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + for(a = 0; a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultTextureCoordinatesParallel(rFill[a], rRange, bParallelX, bParallelY); + } + } + + if(bSphereX || bSphereY) + { + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DPoint aCenter(rRange.getCenter()); + + for(a = 0; a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultTextureCoordinatesSphere(rFill[a], aCenter, bSphereX, bSphereY); + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(rTextureSize.getX(), rTextureSize.getY()); + + for(a = 0; a < rFill.size(); a++) + { + rFill[a].transformTextureCoordiantes(aTexMatrix); + } + } + + Primitive3DSequence create3DPolyPolygonLinePrimitives( + const basegfx::B3DPolyPolygon& rUnitPolyPolygon, + const basegfx::B3DHomMatrix& rObjectTransform, + const attribute::SdrLineAttribute& rLine) + { + // prepare fully scaled polyPolygon + basegfx::B3DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon); + aScaledPolyPolygon.transform(rObjectTransform); + + // create line and stroke attribute + const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin()); + const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen()); + + // create primitives + Primitive3DSequence aRetval(aScaledPolyPolygon.count()); + + for(sal_uInt32 a(0L); a < aScaledPolyPolygon.count(); a++) + { + const Primitive3DReference xRef(new PolygonStrokePrimitive3D(aScaledPolyPolygon.getB3DPolygon(a), aLineAttribute, aStrokeAttribute)); + aRetval[a] = xRef; + } + + if(0.0 != rLine.getTransparence()) + { + // create UnifiedTransparenceTexturePrimitive3D, add created primitives and exchange + const Primitive3DReference xRef(new UnifiedTransparenceTexturePrimitive3D(rLine.getTransparence(), aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + return aRetval; + } + + Primitive3DSequence create3DPolyPolygonFillPrimitives( + const ::std::vector< basegfx::B3DPolyPolygon >& r3DPolyPolygonVector, + const basegfx::B3DHomMatrix& rObjectTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::Sdr3DObjectAttribute& aSdr3DObjectAttribute, + const attribute::SdrFillAttribute& rFill, + const attribute::FillGradientAttribute& rFillGradient) + { + Primitive3DSequence aRetval; + + if(r3DPolyPolygonVector.size()) + { + // create list of simple fill primitives + aRetval.realloc(r3DPolyPolygonVector.size()); + + for(sal_uInt32 a(0L); a < r3DPolyPolygonVector.size(); a++) + { + // get scaled PolyPolygon + basegfx::B3DPolyPolygon aScaledPolyPolygon(r3DPolyPolygonVector[a]); + aScaledPolyPolygon.transform(rObjectTransform); + + if(aScaledPolyPolygon.areNormalsUsed()) + { + aScaledPolyPolygon.transformNormals(rObjectTransform); + } + + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D( + aScaledPolyPolygon, + aSdr3DObjectAttribute.getMaterial(), + aSdr3DObjectAttribute.getDoubleSided())); + aRetval[a] = xRef; + } + + // look for and evtl. build texture sub-group primitive + if(!rFill.getGradient().isDefault() + || !rFill.getHatch().isDefault() + || !rFill.getBitmap().isDefault()) + { + bool bModulate(::com::sun::star::drawing::TextureMode_MODULATE == aSdr3DObjectAttribute.getTextureMode()); + bool bFilter(aSdr3DObjectAttribute.getTextureFilter()); + BasePrimitive3D* pNewTexturePrimitive3D = 0; + + if(!rFill.getGradient().isDefault()) + { + // create gradientTexture3D with sublist, add to local aRetval + pNewTexturePrimitive3D = new GradientTexturePrimitive3D( + rFill.getGradient(), + aRetval, + rTextureSize, + bModulate, + bFilter); + } + else if(!rFill.getHatch().isDefault()) + { + // create hatchTexture3D with sublist, add to local aRetval + pNewTexturePrimitive3D = new HatchTexturePrimitive3D( + rFill.getHatch(), + aRetval, + rTextureSize, + bModulate, + bFilter); + } + else // if(!rFill.getBitmap().isDefault()) + { + // create bitmapTexture3D with sublist, add to local aRetval + basegfx::B2DRange aTexRange(0.0, 0.0, rTextureSize.getX(), rTextureSize.getY()); + + pNewTexturePrimitive3D = new BitmapTexturePrimitive3D( + rFill.getBitmap().getFillBitmapAttribute(aTexRange), + aRetval, + rTextureSize, + bModulate, + bFilter); + } + + // exchange aRetval content with texture group + const Primitive3DReference xRef(pNewTexturePrimitive3D); + aRetval = Primitive3DSequence(&xRef, 1L); + + if(::com::sun::star::drawing::TextureKind2_LUMINANCE == aSdr3DObjectAttribute.getTextureKind()) + { + // use modified color primitive to force textures to gray + const basegfx::BColorModifier aBColorModifier(basegfx::BColor(), 0.0, basegfx::BCOLORMODIFYMODE_GRAY); + const Primitive3DReference xRef2(new ModifiedColorPrimitive3D(aRetval, aBColorModifier)); + aRetval = Primitive3DSequence(&xRef2, 1L); + } + } + + if(0.0 != rFill.getTransparence()) + { + // create UnifiedTransparenceTexturePrimitive3D with sublist and exchange + const Primitive3DReference xRef(new UnifiedTransparenceTexturePrimitive3D(rFill.getTransparence(), aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + else if(!rFillGradient.isDefault()) + { + // create TransparenceTexturePrimitive3D with sublist and exchange + const Primitive3DReference xRef(new TransparenceTexturePrimitive3D(rFillGradient, aRetval, rTextureSize)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + } + + return aRetval; + } + + Primitive3DSequence createShadowPrimitive3D( + const Primitive3DSequence& rSource, + const attribute::SdrShadowAttribute& rShadow, + bool bShadow3D) + { + // create Shadow primitives. Uses already created primitives + if(rSource.hasElements() && !basegfx::fTools::moreOrEqual(rShadow.getTransparence(), 1.0)) + { + // prepare new list for shadow geometry + basegfx::B2DHomMatrix aShadowOffset; + aShadowOffset.set(0, 2, rShadow.getOffset().getX()); + aShadowOffset.set(1, 2, rShadow.getOffset().getY()); + + // create shadow primitive and add primitives + const Primitive3DReference xRef(new ShadowPrimitive3D(aShadowOffset, rShadow.getColor(), rShadow.getTransparence(), bShadow3D, rSource)); + return Primitive3DSequence(&xRef, 1L); + } + else + { + return Primitive3DSequence(); + } + } + + Primitive3DSequence createHiddenGeometryPrimitives3D( + const ::std::vector< basegfx::B3DPolyPolygon >& r3DPolyPolygonVector, + const basegfx::B3DHomMatrix& rObjectTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::Sdr3DObjectAttribute& aSdr3DObjectAttribute) + { + // create hidden sub-geometry which can be used for HitTest + // and BoundRect calculations, but will not be visualized + const attribute::SdrFillAttribute aSimplifiedFillAttribute( + 0.0, + basegfx::BColor(), + attribute::FillGradientAttribute(), + attribute::FillHatchAttribute(), + attribute::SdrFillBitmapAttribute()); + + const Primitive3DReference aHidden( + new HiddenGeometryPrimitive3D( + create3DPolyPolygonFillPrimitives( + r3DPolyPolygonVector, + rObjectTransform, + rTextureSize, + aSdr3DObjectAttribute, + aSimplifiedFillAttribute, + attribute::FillGradientAttribute()))); + + return Primitive3DSequence(&aHidden, 1); + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx b/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx new file mode 100644 index 000000000000..98ce52b5c0a7 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx @@ -0,0 +1,991 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/range/b3drange.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <numeric> + +////////////////////////////////////////////////////////////////////////////// +// decompositon helpers for extrude/lathe (rotation) objects + +namespace +{ + ////////////////////////////////////////////////////////////////////////////// + // common helpers + + basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter( + const basegfx::B2DPolyPolygon& rSource, + double fScale) + { + basegfx::B2DPolyPolygon aRetval(rSource); + + if(!basegfx::fTools::equalZero(fScale)) + { + const basegfx::B2DRange aRange(basegfx::tools::getRange(rSource)); + const basegfx::B2DPoint aCenter(aRange.getCenter()); + basegfx::B2DHomMatrix aTrans; + + aTrans.translate(-aCenter.getX(), -aCenter.getY()); + aTrans.scale(fScale, fScale); + aTrans.translate(aCenter.getX(), aCenter.getY()); + aRetval.transform(aTrans); + } + + return aRetval; + } + + void impGetOuterPolyPolygon( + basegfx::B2DPolyPolygon& rPolygon, + basegfx::B2DPolyPolygon& rOuterPolyPolygon, + double fOffset, + bool bCharacterMode) + { + rOuterPolyPolygon = rPolygon; + + if(basegfx::fTools::more(fOffset, 0.0)) + { + if(bCharacterMode) + { + // grow the outside polygon and scale all polygons to original size. This is done + // to avoid a shrink which potentially would lead to self-intersections, but changes + // the original polygon -> not a precision step, so e.g. not usable for charts + const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolygon)); + rPolygon = basegfx::tools::growInNormalDirection(rPolygon, fOffset); + const basegfx::B2DRange aGrownRange(basegfx::tools::getRange(rPolygon)); + const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth()); + const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight()); + basegfx::B2DHomMatrix aScaleTrans; + + aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY()); + aScaleTrans.scale(fScaleX, fScaleY); + aScaleTrans.translate(aRange.getMinX(), aRange.getMinY()); + rPolygon.transform(aScaleTrans); + rOuterPolyPolygon.transform(aScaleTrans); + } + else + { + // use more precision, shrink the outer polygons. Since this may lead to self-intersections, + // some kind of correction should be applied here after that step + rOuterPolyPolygon = basegfx::tools::growInNormalDirection(rPolygon, -fOffset); + basegfx::tools::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon); + } + } + } + + void impAddInBetweenFill( + basegfx::B3DPolyPolygon& rTarget, + const basegfx::B3DPolyPolygon& rPolA, + const basegfx::B3DPolyPolygon& rPolB, + double fTexVerStart, + double fTexVerStop, + bool bCreateNormals, + bool bCreateTextureCoordinates) + { + OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); + const sal_uInt32 nPolygonCount(rPolA.count()); + + for(sal_uInt32 a(0L); a < nPolygonCount; a++) + { + const basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1L); + double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0); + double fPolygonPosA(0.0), fPolygonPosB(0.0); + + if(bCreateTextureCoordinates) + { + const double fPolygonLengthA(basegfx::tools::getLength(aSubA)); + fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA; + + const double fPolygonLengthB(basegfx::tools::getLength(aSubB)); + fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB; + } + + for(sal_uInt32 b(0L); b < nEdgeCount; b++) + { + const sal_uInt32 nIndexA(b); + const sal_uInt32 nIndexB((b + 1L) % nPointCount); + + const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA)); + const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB)); + const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA)); + const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB)); + + basegfx::B3DPolygon aNew; + aNew.setClosed(true); + + aNew.append(aStartA); + aNew.append(aStartB); + aNew.append(aEndB); + aNew.append(aEndA); + + if(bCreateNormals) + { + aNew.setNormal(0L, aSubA.getNormal(nIndexA)); + aNew.setNormal(1L, aSubB.getNormal(nIndexA)); + aNew.setNormal(2L, aSubB.getNormal(nIndexB)); + aNew.setNormal(3L, aSubA.getNormal(nIndexB)); + } + + if(bCreateTextureCoordinates) + { + const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA); + const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength()); + fPolygonPosA += fEdgeLengthA; + const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA); + + const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB); + const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength()); + fPolygonPosB += fEdgeLengthB; + const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB); + + aNew.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL, fTexVerStart)); + aNew.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL, fTexVerStop)); + aNew.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR, fTexVerStop)); + aNew.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR, fTexVerStart)); + } + + rTarget.append(aNew); + } + } + } + } + + void impSetNormal( + basegfx::B3DPolyPolygon& rCandidate, + const basegfx::B3DVector& rNormal) + { + for(sal_uInt32 a(0L); a < rCandidate.count(); a++) + { + basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a)); + + for(sal_uInt32 b(0L); b < aSub.count(); b++) + { + aSub.setNormal(b, rNormal); + } + + rCandidate.setB3DPolygon(a, aSub); + } + } + + void impCreateInBetweenNormals( + basegfx::B3DPolyPolygon& rPolA, + basegfx::B3DPolyPolygon& rPolB, + bool bSmoothHorizontalNormals) + { + OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + + for(sal_uInt32 a(0L); a < rPolA.count(); a++) + { + basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + if(nPointCount) + { + basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L)); + basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L)); + const bool bClosed(aSubA.isClosed()); + + for(sal_uInt32 b(0L); b < nPointCount; b++) + { + const sal_uInt32 nIndNext((b + 1L) % nPointCount); + const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext)); + const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b)); + + // vector to back + basegfx::B3DVector aDepth(aCurrB - aCurrA); + aDepth.normalize(); + + if(aDepth.equalZero()) + { + // no difference, try to get depth from next point + const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext)); + aDepth = aNextB - aNextA; + aDepth.normalize(); + } + + // vector to left (correct for non-closed lines) + const bool bFirstAndNotClosed(!bClosed && 0L == b); + basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA); + aLeft.normalize(); + + // create left normal + const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft)); + + if(bSmoothHorizontalNormals) + { + // vector to right (correct for non-closed lines) + const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount); + basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA); + aRight.normalize(); + + // create right normal + const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth)); + + // create smoothed in-between normal + basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight); + aNewNormal.normalize(); + + // set as new normal at polygons + aSubA.setNormal(b, aNewNormal); + aSubB.setNormal(b, aNewNormal); + } + else + { + // set aNormalLeft as new normal at polygons + aSubA.setNormal(b, aNormalLeft); + aSubB.setNormal(b, aNormalLeft); + } + + // prepare next step + aPrevA = aCurrA; + aCurrA = aNextA; + } + + rPolA.setB3DPolygon(a, aSubA); + rPolB.setB3DPolygon(a, aSubB); + } + } + } + + void impMixNormals( + basegfx::B3DPolyPolygon& rPolA, + const basegfx::B3DPolyPolygon& rPolB, + double fWeightA) + { + const double fWeightB(1.0 - fWeightA); + OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + + for(sal_uInt32 a(0L); a < rPolA.count(); a++) + { + basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + for(sal_uInt32 b(0L); b < nPointCount; b++) + { + const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA); + const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB); + basegfx::B3DVector aVNew(aVA + aVB); + aVNew.normalize(); + aSubA.setNormal(b, aVNew); + } + + rPolA.setB3DPolygon(a, aSubA); + } + } + + bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd) + { + // polygon is closed, one of the points is a member + const sal_uInt32 nPointCount(rPoly.count()); + + if(nPointCount) + { + basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0)); + const basegfx::B2DVector aVector(rEnd - rStart); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex)); + const basegfx::B2DVector aEdgeVector(aNext - aCurrent); + + if(basegfx::tools::findCut( + rStart, aVector, + aCurrent, aEdgeVector)) + { + return true; + } + + aCurrent = aNext; + } + } + + return false; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + void createLatheSlices( + Slice3DVector& rSliceVector, + const basegfx::B2DPolyPolygon& rSource, + double fBackScale, + double fDiagonal, + double fRotation, + sal_uInt32 nSteps, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + { + if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps) + { + // no rotation or no steps, just one plane + rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); + } + else + { + const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); + const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI)); + basegfx::B2DPolyPolygon aFront(rSource); + basegfx::B2DPolyPolygon aBack(rSource); + basegfx::B3DHomMatrix aTransformBack; + basegfx::B2DPolyPolygon aOuterBack; + + if(bClosedRotation) + { + bCloseFront = bCloseBack = false; + } + + if(bBackScale) + { + // avoid null zoom + if(basegfx::fTools::equalZero(fBackScale)) + { + fBackScale = 0.000001; + } + + // back is scaled compared to front, create scaled version + aBack = impScalePolyPolygonOnCenter(aBack, fBackScale); + } + + if(bCloseFront || bCloseBack) + { + const basegfx::B2DRange aBaseRange(basegfx::tools::getRange(aFront)); + const double fOuterLength(aBaseRange.getMaxX() * fRotation); + const double fInnerLength(aBaseRange.getMinX() * fRotation); + const double fAverageLength((fOuterLength + fInnerLength) * 0.5); + + if(bCloseFront) + { + const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); + basegfx::B2DPolyPolygon aOuterFront; + impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode); + basegfx::B3DHomMatrix aTransform; + aTransform.translate(0.0, 0.0, fOffsetLen); + rSliceVector.push_back(Slice3D(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP)); + } + + if(bCloseBack) + { + const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); + impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode); + aTransformBack.translate(0.0, 0.0, -fOffsetLen); + aTransformBack.rotate(0.0, fRotation, 0.0); + } + } + + // add start polygon (a = 0L) + if(!bClosedRotation) + { + rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix())); + } + + // create segments (a + 1 .. nSteps) + const double fStepSize(1.0 / (double)nSteps); + + for(sal_uInt32 a(0L); a < nSteps; a++) + { + const double fStep((double)(a + 1L) * fStepSize); + basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::tools::interpolate(aFront, aBack, fStep) : aFront); + basegfx::B3DHomMatrix aNewMat; + aNewMat.rotate(0.0, fRotation * fStep, 0.0); + rSliceVector.push_back(Slice3D(aNewPoly, aNewMat)); + } + + if(bCloseBack) + { + rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP)); + } + } + } + + void createExtrudeSlices( + Slice3DVector& rSliceVector, + const basegfx::B2DPolyPolygon& rSource, + double fBackScale, + double fDiagonal, + double fDepth, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + { + if(basegfx::fTools::equalZero(fDepth)) + { + // no depth, just one plane + rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); + } + else + { + // there is depth, create Polygons for front,back and their default depth positions + basegfx::B2DPolyPolygon aFront(rSource); + basegfx::B2DPolyPolygon aBack(rSource); + const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); + double fZFront(fDepth); // default depth for aFront + double fZBack(0.0); // default depth for aBack + basegfx::B2DPolyPolygon aOuterBack; + + if(bBackScale) + { + // avoid null zoom + if(basegfx::fTools::equalZero(fBackScale)) + { + fBackScale = 0.000001; + } + + // aFront is scaled compared to aBack, create scaled version + aFront = impScalePolyPolygonOnCenter(aFront, fBackScale); + } + + if(bCloseFront) + { + const double fOffset(fDepth * fDiagonal * 0.5); + fZFront = fDepth - fOffset; + basegfx::B2DPolyPolygon aOuterFront; + impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode); + basegfx::B3DHomMatrix aTransformFront; + aTransformFront.translate(0.0, 0.0, fDepth); + rSliceVector.push_back(Slice3D(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP)); + } + + if(bCloseBack) + { + const double fOffset(fDepth * fDiagonal * 0.5); + fZBack = fOffset; + impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode); + } + + // add front and back polygons at evtl. changed depths + { + basegfx::B3DHomMatrix aTransformA, aTransformB; + + aTransformA.translate(0.0, 0.0, fZFront); + rSliceVector.push_back(Slice3D(aFront, aTransformA)); + + aTransformB.translate(0.0, 0.0, fZBack); + rSliceVector.push_back(Slice3D(aBack, aTransformB)); + } + + if(bCloseBack) + { + rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP)); + } + } + } + + basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines) + { + basegfx::B3DPolyPolygon aRetval; + const sal_uInt32 nNumSlices(rSliceVector.size()); + + if(nNumSlices) + { + const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count()); + + for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++) + { + const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count()); + + for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++) + { + basegfx::B3DPolygon aNew; + + for(sal_uInt32 d(0); d < nNumSlices; d++) + { + OSL_ENSURE(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count(), + "Slice PolyPolygon with different Polygon count (!)"); + OSL_ENSURE(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count(), + "Slice Polygon with different point count (!)"); + aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c)); + } + + aNew.setClosed(bCloseHorLines); + aRetval.append(aNew); + } + } + } + + return aRetval; + } + + basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector) + { + basegfx::B3DPolyPolygon aRetval; + const sal_uInt32 nNumSlices(rSliceVector.size()); + + for(sal_uInt32 a(0L); a < nNumSlices; a++) + { + aRetval.append(rSliceVector[a].getB3DPolyPolygon()); + } + + return aRetval; + } + + void extractPlanesFromSlice( + ::std::vector< basegfx::B3DPolyPolygon >& rFill, + const Slice3DVector& rSliceVector, + bool bCreateNormals, + bool bSmoothHorizontalNormals, + bool bSmoothNormals, + bool bSmoothLids, + bool bClosed, + double fSmoothNormalsMix, + double fSmoothLidsMix, + bool bCreateTextureCoordinates, + const basegfx::B2DHomMatrix& rTexTransform) + { + const sal_uInt32 nNumSlices(rSliceVector.size()); + + if(nNumSlices) + { + // common parameters + const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L); + basegfx::B3DPolyPolygon aEdgeRounding; + sal_uInt32 a; + + // tetxture parameters + double fInvTexHeight(1.0); + double fTexHeightPos(0.0); + double fTexStart(0.0); + double fTexStop(1.0); + ::std::vector<double> aTexHeightArray; + basegfx::B3DRange aTexRangeFront; + basegfx::B3DRange aTexRangeBack; + + if(bCreateTextureCoordinates) + { + aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()); + aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon()); + + if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth()) + { + // last polygon is rotated so that depth is bigger than width, exchange X and Z + // for making applyDefaultTextureCoordinatesParallel use Z instead of X for + // horizontal texture coordinate + aTexRangeBack = basegfx::B3DRange( + aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(), + aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX()); + } + + basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter()); + + for(a = 0L; a < nLoopCount; a++) + { + const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter()); + const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength()); + aTexHeightArray.push_back(fLength); + aCenter = aNextCenter; + } + + const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0)); + + if(!basegfx::fTools::equalZero(fTexHeight)) + { + fInvTexHeight = 1.0 / fTexHeight; + } + } + + if(nLoopCount) + { + for(a = 0L; a < nLoopCount; a++) + { + const Slice3D& rSliceA(rSliceVector[a]); + const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]); + const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType()); + basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon()); + + if(bAcceptPair) + { + if(bCreateNormals) + { + impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals); + } + + { + const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices); + const Slice3D& rSlicePrev(rSliceVector[nIndPrev]); + basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon()); + + if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType()) + { + basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon()); + const bool bHasSlant(aPolAA != aPrev); + + if(bCreateTextureCoordinates) + { + aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); + } + + if(bCreateNormals) + { + basegfx::B3DVector aNormal(0.0, 0.0, -1.0); + + if(aFront.count()) + { + aNormal = -aFront.getB3DPolygon(0L).getNormal(); + } + + impSetNormal(aFront, aNormal); + + if(bHasSlant) + { + impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); + + if(bSmoothNormals) + { + // smooth and copy + impMixNormals(aPolA, aPolAA, fSmoothNormalsMix); + aPolAA = aPolA; + } + else + { + // take over from surface + aPolAA = aPolA; + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aFront, aPrev, fSmoothLidsMix); + aPrev = aFront; + } + else + { + // take over from front + aPrev = aFront; + } + } + else + { + if(bSmoothNormals) + { + // smooth + impMixNormals(aPolA, aFront, fSmoothNormalsMix); + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aFront, aPolA, fSmoothLidsMix); + aPolA = aFront; + } + } + } + + if(bHasSlant) + { + if(bCreateTextureCoordinates) + { + fTexStart = fTexHeightPos * fInvTexHeight; + fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + aFront.flip(); + rFill.push_back(aFront); + } + else + { + if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L)) + { + impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); + impMixNormals(aPolA, aPolAA, 0.5); + } + } + } + + { + const sal_uInt32 nIndNext((a + 2L) % nNumSlices); + const Slice3D& rSliceNext(rSliceVector[nIndNext]); + basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon()); + + if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType()) + { + basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon()); + const bool bHasSlant(aPolBB != aNext); + + if(bCreateTextureCoordinates) + { + aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack); + } + + if(bCreateNormals) + { + const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0)); + impSetNormal(aBack, aNormal); + + if(bHasSlant) + { + impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); + + if(bSmoothNormals) + { + // smooth and copy + impMixNormals(aPolB, aPolBB, fSmoothNormalsMix); + aPolBB = aPolB; + } + else + { + // take over from surface + aPolBB = aPolB; + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aBack, aNext, fSmoothLidsMix); + aNext = aBack; + } + else + { + // take over from back + aNext = aBack; + } + } + else + { + if(bSmoothNormals) + { + // smooth + impMixNormals(aPolB, aBack, fSmoothNormalsMix); + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aBack, aPolB, fSmoothLidsMix); + aPolB = aBack; + } + } + } + + if(bHasSlant) + { + if(bCreateTextureCoordinates) + { + fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight; + fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + rFill.push_back(aBack); + } + else + { + if(bCreateNormals && bSmoothNormals && (nIndNext != a)) + { + impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); + impMixNormals(aPolB, aPolBB, 0.5); + } + } + } + + if(bCreateTextureCoordinates) + { + fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; + fTexStop = fTexHeightPos * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + if(bCreateTextureCoordinates) + { + fTexHeightPos += aTexHeightArray[a]; + } + } + } + else + { + // no loop, but a single slice (1 == nNumSlices), create a filling from the single + // front plane + const Slice3D& rSlice(rSliceVector[0]); + basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon()); + + if(bCreateTextureCoordinates) + { + aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); + } + + if(bCreateNormals) + { + basegfx::B3DVector aNormal(0.0, 0.0, -1.0); + + if(aFront.count()) + { + aNormal = -aFront.getB3DPolygon(0L).getNormal(); + } + + impSetNormal(aFront, aNormal); + } + + aFront.flip(); + rFill.push_back(aFront); + } + + if(bCreateTextureCoordinates) + { + aEdgeRounding.transformTextureCoordiantes(rTexTransform); + } + + for(a = 0L; a < aEdgeRounding.count(); a++) + { + rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a))); + } + } + } + + void createReducedOutlines( + const geometry::ViewInformation3D& rViewInformation, + const basegfx::B3DHomMatrix& rObjectTransform, + const basegfx::B3DPolygon& rLoopA, + const basegfx::B3DPolygon& rLoopB, + basegfx::B3DPolyPolygon& rTarget) + { + const sal_uInt32 nPointCount(rLoopA.count()); + + // with idetic polygons there are no outlines + if(rLoopA != rLoopB) + { + if(nPointCount && nPointCount == rLoopB.count()) + { + const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform); + const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform)); + const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform)); + const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter()); + const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter()); + + // without detectable Y-Axis there are no outlines + if(!a2DCenterA.equal(a2DCenterB)) + { + // search for outmost left and right inter-loop-edges which do not cut the loops + const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB)); + const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB); + double fMaxLeft(0.0); + double fMaxRight(0.0); + sal_uInt32 nIndexLeft(0); + sal_uInt32 nIndexRight(0); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a)); + const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a)); + const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd)); + + if(!basegfx::tools::isInside(a2DLoopA, aMiddle)) + { + if(!basegfx::tools::isInside(a2DLoopB, aMiddle)) + { + if(!impHasCutWith(a2DLoopA, aStart, aEnd)) + { + if(!impHasCutWith(a2DLoopB, aStart, aEnd)) + { + const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter); + const double fCross(aCandidateVector.cross(aAxisVector)); + const double fDistance(aCandidateVector.getLength()); + + if(fCross > 0.0) + { + if(fDistance > fMaxLeft) + { + fMaxLeft = fDistance; + nIndexLeft = a; + } + } + else if(fCross < 0.0) + { + if(fDistance > fMaxRight) + { + fMaxRight = fDistance; + nIndexRight = a; + } + } + } + } + } + } + } + + if(fMaxLeft != 0.0) + { + basegfx::B3DPolygon aToBeAdded; + aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft)); + aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft)); + rTarget.append(aToBeAdded); + } + + if(fMaxRight != 0.0) + { + basegfx::B3DPolygon aToBeAdded; + aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight)); + aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight)); + rTarget.append(aToBeAdded); + } + } + } + } + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx new file mode 100644 index 000000000000..2485d467b7f4 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx @@ -0,0 +1,526 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrextrudeprimitive3d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrExtrudePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + Primitive3DSequence aRetval; + + // get slices + const Slice3DVector& rSliceVector = getSlices(); + + if(rSliceVector.size()) + { + sal_uInt32 a; + + // decide what to create + const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind); + const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + double fRelativeTextureWidth(1.0); + basegfx::B2DHomMatrix aTexTransform; + + if(!getSdrLFSAttribute().getFill().isDefault() && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY)) + { + const basegfx::B2DPolygon aFirstPolygon(maCorrectedPolyPolygon.getB2DPolygon(0L)); + const double fFrontLength(basegfx::tools::getLength(aFirstPolygon)); + const double fFrontArea(basegfx::tools::getArea(aFirstPolygon)); + const double fSqrtFrontArea(sqrt(fFrontArea)); + fRelativeTextureWidth = basegfx::fTools::equalZero(fSqrtFrontArea) ? 1.0 : fFrontLength / fSqrtFrontArea; + fRelativeTextureWidth = (double)((sal_uInt32)(fRelativeTextureWidth - 0.5)); + + if(fRelativeTextureWidth < 1.0) + { + fRelativeTextureWidth = 1.0; + } + + aTexTransform.translate(-0.5, -0.5); + aTexTransform.scale(-1.0, -1.0); + aTexTransform.translate(0.5, 0.5); + aTexTransform.scale(fRelativeTextureWidth, 1.0); + } + + // create geometry + ::std::vector< basegfx::B3DPolyPolygon > aFill; + extractPlanesFromSlice(aFill, rSliceVector, + bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), false, + 0.5, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // normal creation + if(!getSdrLFSAttribute().getFill().isDefault()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // texture coordinates + if(!getSdrLFSAttribute().getFill().isDefault()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + aRetval = createHiddenGeometryPrimitives3D( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute()); + } + + // add line + if(!getSdrLFSAttribute().getLine().isDefault()) + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + // create geometric outlines with reduced line geometry for chart. + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + const sal_uInt32 nCount(aVerLine.count()); + basegfx::B3DPolyPolygon aReducedLoops; + basegfx::B3DPolyPolygon aNewLineGeometry; + + // sort out doubles (front and back planes when no edge rounding is done). Since + // this is a line geometry merged from PolyPolygons, loop over all Polygons + for(a = 0; a < nCount; a++) + { + const sal_uInt32 nReducedCount(aReducedLoops.count()); + const basegfx::B3DPolygon aCandidate(aVerLine.getB3DPolygon(a)); + bool bAdd(true); + + if(nReducedCount) + { + for(sal_uInt32 b(0); bAdd && b < nReducedCount; b++) + { + if(aCandidate == aReducedLoops.getB3DPolygon(b)) + { + bAdd = false; + } + } + } + + if(bAdd) + { + aReducedLoops.append(aCandidate); + } + } + + // from here work with reduced loops and reduced count without changing them + const sal_uInt32 nReducedCount(aReducedLoops.count()); + + if(nReducedCount > 1) + { + for(sal_uInt32 b(1); b < nReducedCount; b++) + { + // get loop pair + const basegfx::B3DPolygon aCandA(aReducedLoops.getB3DPolygon(b - 1)); + const basegfx::B3DPolygon aCandB(aReducedLoops.getB3DPolygon(b)); + + // for each loop pair create the connection edges + createReducedOutlines( + rViewInformation, + getTransform(), + aCandA, + aCandB, + aNewLineGeometry); + } + } + + // add reduced loops themselves + aNewLineGeometry.append(aReducedLoops); + + // to create vertical edges at non-C1/C2 steady loops, use maCorrectedPolyPolygon + // directly since the 3D Polygons do not suport this. + // + // Unfortunately there is no bezier polygon provided by the chart module; one reason is + // that the API for extrude wants a 3D polygon geometry (for historical reasons, i guess) + // and those have no beziers. Another reason is that he chart module uses self-created + // stuff to create the 2D geometry (in ShapeFactory::createPieSegment), but this geometry + // does not contain bezier infos, either. The only way which is possible for now is to 'detect' + // candidates for vertical edges of pie segments by looking for the angles in the polygon. + // + // This is all not very well designed ATM. Ideally, the ReducedLineGeometry is responsible + // for creating the outer geometry edges (createReducedOutlines), but for special edges + // like the vertical ones for pie center and both start/end, the incarnation with the + // knowledge about that it needs to create those and IS a pie segment -> in this case, + // the chart itself. + const sal_uInt32 nPolyCount(maCorrectedPolyPolygon.count()); + + for(sal_uInt32 c(0); c < nPolyCount; c++) + { + const basegfx::B2DPolygon aCandidate(maCorrectedPolyPolygon.getB2DPolygon(c)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount > 2) + { + sal_uInt32 nIndexA(nPointCount); + sal_uInt32 nIndexB(nPointCount); + sal_uInt32 nIndexC(nPointCount); + + for(sal_uInt32 d(0); d < nPointCount; d++) + { + const sal_uInt32 nPrevInd((d + nPointCount - 1) % nPointCount); + const sal_uInt32 nNextInd((d + 1) % nPointCount); + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(d)); + const basegfx::B2DVector aPrev(aCandidate.getB2DPoint(nPrevInd) - aPoint); + const basegfx::B2DVector aNext(aCandidate.getB2DPoint(nNextInd) - aPoint); + const double fAngle(aPrev.angle(aNext)); + + // take each angle which deviates more than 10% from going straight as + // special edge. This will detect the two outer edges of pie segments, + // but not always the center one (think about a near 180 degree pie) + if(F_PI - fabs(fAngle) > F_PI * 0.1) + { + if(nPointCount == nIndexA) + { + nIndexA = d; + } + else if(nPointCount == nIndexB) + { + nIndexB = d; + } + else if(nPointCount == nIndexC) + { + nIndexC = d; + d = nPointCount; + } + } + } + + const bool bIndexAUsed(nIndexA != nPointCount); + const bool bIndexBUsed(nIndexB != nPointCount); + bool bIndexCUsed(nIndexC != nPointCount); + + if(bIndexCUsed) + { + // already three special edges found, so the center one was already detected + // and does not need to be searched + } + else if(bIndexAUsed && bIndexBUsed) + { + // outer edges detected (they are approx. 90 degrees), but center one not. + // Look with the knowledge that it's in-between the two found ones + if(((nIndexA + 2) % nPointCount) == nIndexB) + { + nIndexC = (nIndexA + 1) % nPointCount; + } + else if(((nIndexA + nPointCount - 2) % nPointCount) == nIndexB) + { + nIndexC = (nIndexA + nPointCount - 1) % nPointCount; + } + + bIndexCUsed = (nIndexC != nPointCount); + } + + if(bIndexAUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexA)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + + if(bIndexBUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexB)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + + if(bIndexCUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexC)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + } + } + + // append loops themselves + aNewLineGeometry.append(aReducedLoops); + + if(aNewLineGeometry.count()) + { + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( + aNewLineGeometry, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + } + else + { + // extract line geometry from slices + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, false)); + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + + // add horizontal lines + const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives( + aHorLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines); + + // add vertical lines + const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives( + aVerLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines); + } + } + + // add shadow + if(!getSdrLFSAttribute().getShadow().isDefault() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D( + aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + void SdrExtrudePrimitive3D::impCreateSlices() + { + // prepare the polygon. No double points, correct orientations and a correct + // outmost polygon are needed + maCorrectedPolyPolygon = getPolyPolygon(); + maCorrectedPolyPolygon.removeDoublePoints(); + maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); + maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); + + // prepare slices as geometry + createExtrudeSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getDepth(), getCharacterMode(), getCloseFront(), getCloseBack()); + } + + const Slice3DVector& SdrExtrudePrimitive3D::getSlices() const + { + // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() + // again when no longer geometry is needed for non-visible 3D objects as it is now for chart + if(getPolyPolygon().count() && !maSlices.size()) + { + ::osl::Mutex m_mutex; + const_cast< SdrExtrudePrimitive3D& >(*this).impCreateSlices(); + } + + return maSlices; + } + + SdrExtrudePrimitive3D::SdrExtrudePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fDepth, + double fDiagonal, + double fBackScale, + bool bSmoothNormals, + bool bSmoothHorizontalNormals, + bool bSmoothLids, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maCorrectedPolyPolygon(), + maSlices(), + maPolyPolygon(rPolyPolygon), + mfDepth(fDepth), + mfDiagonal(fDiagonal), + mfBackScale(fBackScale), + mpLastRLGViewInformation(0), + mbSmoothNormals(bSmoothNormals), + mbSmoothHorizontalNormals(bSmoothHorizontalNormals), + mbSmoothLids(bSmoothLids), + mbCharacterMode(bCharacterMode), + mbCloseFront(bCloseFront), + mbCloseBack(bCloseBack) + { + // make sure depth is positive + if(basegfx::fTools::lessOrEqual(getDepth(), 0.0)) + { + mfDepth = 0.0; + } + + // make sure the percentage value getDiagonal() is between 0.0 and 1.0 + if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) + { + mfDiagonal = 0.0; + } + else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) + { + mfDiagonal = 1.0; + } + + // no close front/back when polygon is not closed + if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) + { + mbCloseFront = mbCloseBack = false; + } + + // no edge rounding when not closing + if(!getCloseFront() && !getCloseBack()) + { + mfDiagonal = 0.0; + } + } + + SdrExtrudePrimitive3D::~SdrExtrudePrimitive3D() + { + if(mpLastRLGViewInformation) + { + delete mpLastRLGViewInformation; + } + } + + bool SdrExtrudePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrExtrudePrimitive3D& rCompare = static_cast< const SdrExtrudePrimitive3D& >(rPrimitive); + + return (getPolyPolygon() == rCompare.getPolyPolygon() + && getDepth() == rCompare.getDepth() + && getDiagonal() == rCompare.getDiagonal() + && getBackScale() == rCompare.getBackScale() + && getSmoothNormals() == rCompare.getSmoothNormals() + && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() + && getSmoothLids() == rCompare.getSmoothLids() + && getCharacterMode() == rCompare.getCharacterMode() + && getCloseFront() == rCompare.getCloseFront() + && getCloseBack() == rCompare.getCloseBack()); + } + + return false; + } + + basegfx::B3DRange SdrExtrudePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return get3DRangeFromSlices(getSlices()); + } + + Primitive3DSequence SdrExtrudePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + if(!mpLastRLGViewInformation || + (getBuffered3DDecomposition().hasElements() + && *mpLastRLGViewInformation != rViewInformation)) + { + // conditions of last local decomposition with reduced lines have changed. Remember + // new one and clear current decompositiopn + ::osl::Mutex m_mutex; + SdrExtrudePrimitive3D* pThat = const_cast< SdrExtrudePrimitive3D* >(this); + pThat->setBuffered3DDecomposition(Primitive3DSequence()); + delete pThat->mpLastRLGViewInformation; + pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); + } + } + + // no test for buffering needed, call parent + return SdrPrimitive3D::get3DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrExtrudePrimitive3D, PRIMITIVE3D_ID_SDREXTRUDEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx new file mode 100644 index 000000000000..d2ca2f5786bc --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx @@ -0,0 +1,387 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrlatheprimitive3d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + Primitive3DSequence aRetval; + + // get slices + const Slice3DVector& rSliceVector = getSlices(); + + if(rSliceVector.size()) + { + const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0)); + const bool bClosedRotation(!bBackScale && getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI)); + sal_uInt32 a; + + // decide what to create + const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind); + const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + basegfx::B2DHomMatrix aTexTransform; + + if(!getSdrLFSAttribute().getFill().isDefault() + && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY)) + { + aTexTransform.set(0, 0, 0.0); + aTexTransform.set(0, 1, 1.0); + aTexTransform.set(1, 0, 1.0); + aTexTransform.set(1, 1, 0.0); + + aTexTransform.translate(0.0, -0.5); + aTexTransform.scale(1.0, -1.0); + aTexTransform.translate(0.0, 0.5); + } + + // create geometry + ::std::vector< basegfx::B3DPolyPolygon > aFill; + extractPlanesFromSlice(aFill, rSliceVector, + bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), bClosedRotation, + 0.85, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // normal creation + if(!getSdrLFSAttribute().getFill().isDefault()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // texture coordinates + if(!getSdrLFSAttribute().getFill().isDefault()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + aRetval = createHiddenGeometryPrimitives3D( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute()); + } + + // add line + if(!getSdrLFSAttribute().getLine().isDefault()) + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + // create geometric outlines with reduced line geometry for chart + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); + const sal_uInt32 nCount(aHorLine.count()); + basegfx::B3DPolyPolygon aNewLineGeometry; + + for(a = 1; a < nCount; a++) + { + // for each loop pair create the connection edges + createReducedOutlines( + rViewInformation, + getTransform(), + aHorLine.getB3DPolygon(a - 1), + aHorLine.getB3DPolygon(a), + aNewLineGeometry); + } + + for(a = 0; a < nCount; a++) + { + // filter hor lines for empty loops (those who have their defining point on the Y-Axis) + basegfx::B3DPolygon aCandidate(aHorLine.getB3DPolygon(a)); + aCandidate.removeDoublePoints(); + + if(aCandidate.count()) + { + aNewLineGeometry.append(aCandidate); + } + } + + if(aNewLineGeometry.count()) + { + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( + aNewLineGeometry, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + } + else + { + // extract line geometry from slices + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + + // add horizontal lines + const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives( + aHorLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines); + + // add vertical lines + const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives( + aVerLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines); + } + } + + // add shadow + if(!getSdrLFSAttribute().getShadow().isDefault() + && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D( + aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + void SdrLathePrimitive3D::impCreateSlices() + { + // prepare the polygon. No double points, correct orientations and a correct + // outmost polygon are needed + maCorrectedPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(getPolyPolygon()); + maCorrectedPolyPolygon.removeDoublePoints(); + maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); + maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); + + // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures + // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0L is different + // at all (and not always) + const basegfx::B2DPolygon aSubCandidate(maCorrectedPolyPolygon.getB2DPolygon(0)); + const sal_uInt32 nSubEdgeCount(aSubCandidate.isClosed() ? aSubCandidate.count() : (aSubCandidate.count() ? aSubCandidate.count() - 1L : 0L)); + + if(nSubEdgeCount != getVerticalSegments()) + { + maCorrectedPolyPolygon = basegfx::tools::reSegmentPolyPolygon(maCorrectedPolyPolygon, getVerticalSegments()); + } + + // prepare slices as geometry + createLatheSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack()); + } + + const Slice3DVector& SdrLathePrimitive3D::getSlices() const + { + // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() + // again when no longer geometry is needed for non-visible 3D objects as it is now for chart + if(getPolyPolygon().count() && !maSlices.size()) + { + ::osl::Mutex m_mutex; + const_cast< SdrLathePrimitive3D& >(*this).impCreateSlices(); + } + + return maSlices; + } + + SdrLathePrimitive3D::SdrLathePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + const basegfx::B2DPolyPolygon& rPolyPolygon, + sal_uInt32 nHorizontalSegments, + sal_uInt32 nVerticalSegments, + double fDiagonal, + double fBackScale, + double fRotation, + bool bSmoothNormals, + bool bSmoothHorizontalNormals, + bool bSmoothLids, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maCorrectedPolyPolygon(), + maSlices(), + maPolyPolygon(rPolyPolygon), + mnHorizontalSegments(nHorizontalSegments), + mnVerticalSegments(nVerticalSegments), + mfDiagonal(fDiagonal), + mfBackScale(fBackScale), + mfRotation(fRotation), + mpLastRLGViewInformation(0), + mbSmoothNormals(bSmoothNormals), + mbSmoothHorizontalNormals(bSmoothHorizontalNormals), + mbSmoothLids(bSmoothLids), + mbCharacterMode(bCharacterMode), + mbCloseFront(bCloseFront), + mbCloseBack(bCloseBack) + { + // make sure Rotation is positive + if(basegfx::fTools::lessOrEqual(getRotation(), 0.0)) + { + mfRotation = 0.0; + } + + // make sure the percentage value getDiagonal() is between 0.0 and 1.0 + if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) + { + mfDiagonal = 0.0; + } + else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) + { + mfDiagonal = 1.0; + } + + // no close front/back when polygon is not closed + if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) + { + mbCloseFront = mbCloseBack = false; + } + + // no edge rounding when not closing + if(!getCloseFront() && !getCloseBack()) + { + mfDiagonal = 0.0; + } + } + + SdrLathePrimitive3D::~SdrLathePrimitive3D() + { + if(mpLastRLGViewInformation) + { + delete mpLastRLGViewInformation; + } + } + + bool SdrLathePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrLathePrimitive3D& rCompare = static_cast< const SdrLathePrimitive3D& >(rPrimitive); + + return (getPolyPolygon() == rCompare.getPolyPolygon() + && getHorizontalSegments() == rCompare.getHorizontalSegments() + && getVerticalSegments() == rCompare.getVerticalSegments() + && getDiagonal() == rCompare.getDiagonal() + && getBackScale() == rCompare.getBackScale() + && getRotation() == rCompare.getRotation() + && getSmoothNormals() == rCompare.getSmoothNormals() + && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() + && getSmoothLids() == rCompare.getSmoothLids() + && getCharacterMode() == rCompare.getCharacterMode() + && getCloseFront() == rCompare.getCloseFront() + && getCloseBack() == rCompare.getCloseBack()); + } + + return false; + } + + basegfx::B3DRange SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return get3DRangeFromSlices(getSlices()); + } + + Primitive3DSequence SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + if(!mpLastRLGViewInformation || + (getBuffered3DDecomposition().hasElements() + && *mpLastRLGViewInformation != rViewInformation)) + { + // conditions of last local decomposition with reduced lines have changed. Remember + // new one and clear current decompositiopn + ::osl::Mutex m_mutex; + SdrLathePrimitive3D* pThat = const_cast< SdrLathePrimitive3D* >(this); + pThat->setBuffered3DDecomposition(Primitive3DSequence()); + delete pThat->mpLastRLGViewInformation; + pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); + } + } + + // no test for buffering needed, call parent + return SdrPrimitive3D::get3DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrLathePrimitive3D, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx new file mode 100644 index 000000000000..825bd6ee4671 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx @@ -0,0 +1,194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrpolypolygonprimitive3d.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrPolyPolygonPrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + + if(getPolyPolygon3D().count()) + { + ::std::vector< basegfx::B3DPolyPolygon > aFill; + aFill.push_back(getPolyPolygon3D()); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // #i98295# normal creation + if(!getSdrLFSAttribute().getFill().isDefault()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == getSdr3DObjectAttribute().getNormalsKind()) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // #i98314# texture coordinates + if(!getSdrLFSAttribute().getFill().isDefault()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + aRetval = createHiddenGeometryPrimitives3D( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute()); + } + + // add line + if(!getSdrLFSAttribute().getLine().isDefault()) + { + basegfx::B3DPolyPolygon aLine(getPolyPolygon3D()); + aLine.clearNormals(); + aLine.clearTextureCoordinates(); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( + aLine, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(!getSdrLFSAttribute().getShadow().isDefault() + && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D( + aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + SdrPolyPolygonPrimitive3D::SdrPolyPolygonPrimitive3D( + const basegfx::B3DPolyPolygon& rPolyPolygon3D, + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maPolyPolygon3D(rPolyPolygon3D) + { + } + + bool SdrPolyPolygonPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrPolyPolygonPrimitive3D& rCompare = static_cast< const SdrPolyPolygonPrimitive3D& >(rPrimitive); + + return (getPolyPolygon3D() == rCompare.getPolyPolygon3D()); + } + + return false; + } + + basegfx::B3DRange SdrPolyPolygonPrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // added this implementation to make sure that non-visible objects of this + // kind will deliver their expansion. If not implemented, it would never deliver + // the used space for non-visible objects since the decomposition for that + // case will be empty (what is correct). To support chart ATM which relies on + // non-visible objects occupying space in 3D, this method was added + basegfx::B3DRange aRetval; + + if(getPolyPolygon3D().count()) + { + aRetval = basegfx::tools::getRange(getPolyPolygon3D()); + aRetval.transform(getTransform()); + + if(!getSdrLFSAttribute().getLine().isDefault()) + { + const attribute::SdrLineAttribute& rLine = getSdrLFSAttribute().getLine(); + + if(!rLine.isDefault() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by half LineWidth as tube radius + aRetval.grow(rLine.getWidth() / 2.0); + } + } + } + + return aRetval; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrPolyPolygonPrimitive3D, PRIMITIVE3D_ID_SDRPOLYPOLYGONPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrprimitive3d.cxx new file mode 100644 index 000000000000..e5f722126d42 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrprimitive3d.cxx @@ -0,0 +1,125 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + basegfx::B3DRange SdrPrimitive3D::getStandard3DRange() const + { + basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + aUnitRange.transform(getTransform()); + + if(!getSdrLFSAttribute().getLine().isDefault()) + { + const attribute::SdrLineAttribute& rLine = getSdrLFSAttribute().getLine(); + + if(!rLine.isDefault() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by hald LineWidth as tube radius + aUnitRange.grow(rLine.getWidth() / 2.0); + } + } + + return aUnitRange; + } + + basegfx::B3DRange SdrPrimitive3D::get3DRangeFromSlices(const Slice3DVector& rSlices) const + { + basegfx::B3DRange aRetval; + + if(rSlices.size()) + { + for(sal_uInt32 a(0L); a < rSlices.size(); a++) + { + aRetval.expand(basegfx::tools::getRange(rSlices[a].getB3DPolyPolygon())); + } + + aRetval.transform(getTransform()); + + if(!getSdrLFSAttribute().getLine().isDefault()) + { + const attribute::SdrLineAttribute& rLine = getSdrLFSAttribute().getLine(); + + if(!rLine.isDefault() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by half LineWidth as tube radius + aRetval.grow(rLine.getWidth() / 2.0); + } + } + } + + return aRetval; + } + + SdrPrimitive3D::SdrPrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : BufferedDecompositionPrimitive3D(), + maTransform(rTransform), + maTextureSize(rTextureSize), + maSdrLFSAttribute(rSdrLFSAttribute), + maSdr3DObjectAttribute(rSdr3DObjectAttribute) + { + } + + bool SdrPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BufferedDecompositionPrimitive3D::operator==(rPrimitive)) + { + const SdrPrimitive3D& rCompare = static_cast< const SdrPrimitive3D& >(rPrimitive); + + return (getTransform() == rCompare.getTransform() + && getTextureSize() == rCompare.getTextureSize() + && getSdrLFSAttribute() == rCompare.getSdrLFSAttribute() + && getSdr3DObjectAttribute() == rCompare.getSdr3DObjectAttribute()); + } + + return false; + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx new file mode 100644 index 000000000000..b10b4ad6164b --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx @@ -0,0 +1,224 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrsphereprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/attribute/sdrfillattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrSpherePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind() + || ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()); + + // create unit geometry + basegfx::B3DPolyPolygon aFill(basegfx::tools::createSphereFillPolyPolygonFromB3DRange(aUnitRange, + getHorizontalSegments(), getVerticalSegments(), bCreateNormals)); + + // normal inversion + if(!getSdrLFSAttribute().getFill().isDefault() + && bCreateNormals + && getSdr3DObjectAttribute().getNormalsInvert() + && aFill.areNormalsUsed()) + { + // invert normals + aFill = basegfx::tools::invertNormals(aFill); + } + + // texture coordinates + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bSphereX(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX()); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bSphereY(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY()); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY); + } + + if(bSphereX || bObjectSpecificX || bSphereY || bObjectSpecificY) + { + double fRelativeAngle(0.0); + + if(bObjectSpecificX) + { + // Since the texture coordinates are (for historical reasons) + // different from forced to sphere texture coordinates, + // create a old version from it by rotating to old state before applying + // the texture coordinates to emulate old behaviour + fRelativeAngle = F_2PI * ((double)((getHorizontalSegments() >> 1L) - 1L) / (double)getHorizontalSegments()); + basegfx::B3DHomMatrix aRot; + aRot.rotate(0.0, fRelativeAngle, 0.0); + aFill.transform(aRot); + } + + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + const basegfx::B3DPoint aCenter(aRange.getCenter()); + aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter, + bSphereX || bObjectSpecificX, bSphereY || bObjectSpecificY); + + if(bObjectSpecificX) + { + // rotate back again + basegfx::B3DHomMatrix aRot; + aRot.rotate(0.0, -fRelativeAngle, 0.0); + aFill.transform(aRot); + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY()); + aFill.transformTextureCoordiantes(aTexMatrix); + } + + // build vector of PolyPolygons + ::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector; + + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a))); + } + + if(!getSdrLFSAttribute().getFill().isDefault()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + aRetval = createHiddenGeometryPrimitives3D( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute()); + } + + // add line + if(!getSdrLFSAttribute().getLine().isDefault()) + { + basegfx::B3DPolyPolygon aSphere(basegfx::tools::createSpherePolyPolygonFromB3DRange(aUnitRange, getHorizontalSegments(), getVerticalSegments())); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( + aSphere, getTransform(), getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(!getSdrLFSAttribute().getShadow().isDefault() + && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D( + aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + + return aRetval; + } + + SdrSpherePrimitive3D::SdrSpherePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + sal_uInt32 nHorizontalSegments, + sal_uInt32 nVerticalSegments) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + mnHorizontalSegments(nHorizontalSegments), + mnVerticalSegments(nVerticalSegments) + { + } + + bool SdrSpherePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrSpherePrimitive3D& rCompare = static_cast< const SdrSpherePrimitive3D& >(rPrimitive); + + return (getHorizontalSegments() == rCompare.getHorizontalSegments() + && getVerticalSegments() == rCompare.getVerticalSegments()); + } + + return false; + } + + basegfx::B3DRange SdrSpherePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return getStandard3DRange(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrSpherePrimitive3D, PRIMITIVE3D_ID_SDRSPHEREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/shadowprimitive3d.cxx b/drawinglayer/source/primitive3d/shadowprimitive3d.cxx new file mode 100644 index 000000000000..97ac5d930d62 --- /dev/null +++ b/drawinglayer/source/primitive3d/shadowprimitive3d.cxx @@ -0,0 +1,80 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/shadowprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + ShadowPrimitive3D::ShadowPrimitive3D( + const basegfx::B2DHomMatrix& rShadowTransform, + const basegfx::BColor& rShadowColor, + double fShadowTransparence, + bool bShadow3D, + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren), + maShadowTransform(rShadowTransform), + maShadowColor(rShadowColor), + mfShadowTransparence(fShadowTransparence), + mbShadow3D(bShadow3D) + { + } + + bool ShadowPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const ShadowPrimitive3D& rCompare = (ShadowPrimitive3D&)rPrimitive; + + return (getShadowTransform() == rCompare.getShadowTransform() + && getShadowColor() == rCompare.getShadowColor() + && getShadowTransparence() == rCompare.getShadowTransparence() + && getShadow3D() == rCompare.getShadow3D()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(ShadowPrimitive3D, PRIMITIVE3D_ID_SHADOWPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/textureprimitive3d.cxx b/drawinglayer/source/primitive3d/textureprimitive3d.cxx new file mode 100644 index 000000000000..d10fc52b8bb2 --- /dev/null +++ b/drawinglayer/source/primitive3d/textureprimitive3d.cxx @@ -0,0 +1,227 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <basegfx/color/bcolor.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + TexturePrimitive3D::TexturePrimitive3D( + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, bool bFilter) + : GroupPrimitive3D(rChildren), + maTextureSize(rTextureSize), + mbModulate(bModulate), + mbFilter(bFilter) + { + } + + bool TexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const TexturePrimitive3D& rCompare = (TexturePrimitive3D&)rPrimitive; + + return (getModulate() == rCompare.getModulate() + && getFilter() == rCompare.getFilter()); + } + + return false; + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + UnifiedTransparenceTexturePrimitive3D::UnifiedTransparenceTexturePrimitive3D( + double fTransparence, + const Primitive3DSequence& rChildren) + : TexturePrimitive3D(rChildren, basegfx::B2DVector(), false, false), + mfTransparence(fTransparence) + { + } + + bool UnifiedTransparenceTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const UnifiedTransparenceTexturePrimitive3D& rCompare = (UnifiedTransparenceTexturePrimitive3D&)rPrimitive; + + return (getTransparence() == rCompare.getTransparence()); + } + + return false; + } + + basegfx::B3DRange UnifiedTransparenceTexturePrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + // do not use the fallback to decomposition here since for a correct BoundRect we also + // need invisible (1.0 == getTransparence()) geometry; these would be deleted in the decomposition + return getB3DRangeFromPrimitive3DSequence(getChildren(), rViewInformation); + } + + Primitive3DSequence UnifiedTransparenceTexturePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + if(0.0 == getTransparence()) + { + // no transparence used, so just use content + return getChildren(); + } + else if(getTransparence() > 0.0 && getTransparence() < 1.0) + { + // create TransparenceTexturePrimitive3D with fixed transparence as replacement + const basegfx::BColor aGray(getTransparence(), getTransparence(), getTransparence()); + const attribute::FillGradientAttribute aFillGradient(attribute::GRADIENTSTYLE_LINEAR, 0.0, 0.0, 0.0, 0.0, aGray, aGray, 1); + const Primitive3DReference xRef(new TransparenceTexturePrimitive3D(aFillGradient, getChildren(), getTextureSize())); + return Primitive3DSequence(&xRef, 1L); + } + else + { + // completely transparent or invalid definition, add nothing + return Primitive3DSequence(); + } + } + + // provide unique ID + ImplPrimitrive3DIDBlock(UnifiedTransparenceTexturePrimitive3D, PRIMITIVE3D_ID_UNIFIEDTRANSPARENCETEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + GradientTexturePrimitive3D::GradientTexturePrimitive3D( + const attribute::FillGradientAttribute& rGradient, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, + bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maGradient(rGradient) + { + } + + bool GradientTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const GradientTexturePrimitive3D& rCompare = (GradientTexturePrimitive3D&)rPrimitive; + + return (getGradient() == rCompare.getGradient()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(GradientTexturePrimitive3D, PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + BitmapTexturePrimitive3D::BitmapTexturePrimitive3D( + const attribute::FillBitmapAttribute& rFillBitmapAttribute, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maFillBitmapAttribute(rFillBitmapAttribute) + { + } + + bool BitmapTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const BitmapTexturePrimitive3D& rCompare = (BitmapTexturePrimitive3D&)rPrimitive; + + return (getFillBitmapAttribute() == rCompare.getFillBitmapAttribute()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(BitmapTexturePrimitive3D, PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + TransparenceTexturePrimitive3D::TransparenceTexturePrimitive3D( + const attribute::FillGradientAttribute& rGradient, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize) + : GradientTexturePrimitive3D(rGradient, rChildren, rTextureSize, false, false) + { + } + + bool TransparenceTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + return (GradientTexturePrimitive3D::operator==(rPrimitive)); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(TransparenceTexturePrimitive3D, PRIMITIVE3D_ID_TRANSPARENCETEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/transformprimitive3d.cxx b/drawinglayer/source/primitive3d/transformprimitive3d.cxx new file mode 100644 index 000000000000..f50fb061df04 --- /dev/null +++ b/drawinglayer/source/primitive3d/transformprimitive3d.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + TransformPrimitive3D::TransformPrimitive3D( + const basegfx::B3DHomMatrix& rTransformation, + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren), + maTransformation(rTransformation) + { + } + + bool TransformPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const TransformPrimitive3D& rCompare = static_cast< const TransformPrimitive3D& >(rPrimitive); + + return (getTransformation() == rCompare.getTransformation()); + } + + return false; + } + + basegfx::B3DRange TransformPrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + basegfx::B3DRange aRetval(getB3DRangeFromPrimitive3DSequence(getChildren(), rViewInformation)); + aRetval.transform(getTransformation()); + return aRetval; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(TransformPrimitive3D, PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof |