/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_drawinglayer.hxx" #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// 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