/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: lathe3d.cxx,v $ * * $Revision: 1.25 $ * * last change: $Author: hr $ $Date: 2007-06-27 18:03:44 $ * * 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_svx.hxx" #include "svdstr.hrc" #include "svdglob.hxx" #ifndef _TL_POLY_HXX #include <tools/poly.hxx> #endif #ifndef _SVDPAGE_HXX #include <svx/svdpage.hxx> #endif #ifndef _XOUTX_HXX #include <svx/xoutx.hxx> #endif #ifndef _E3D_GLOBL3D_HXX #include "globl3d.hxx" #endif #ifndef _E3D_LATHE3D_HXX #include <svx/lathe3d.hxx> #endif #ifndef _XPOLY_HXX #include <svx/xpoly.hxx> #endif #ifndef _SVX_SVXIDS_HRC #include <svx/svxids.hrc> #endif #ifndef _SVDOPATH_HXX #include <svx/svdopath.hxx> #endif #ifndef _SVDMODEL_HXX #include <svx/svdmodel.hxx> #endif #ifndef _SVX3DITEMS_HXX #include <svx/svx3ditems.hxx> #endif #ifndef _SDR_PROPERTIES_E3DLATHEPROPERTIES_HXX #include <svx/sdr/properties/e3dlatheproperties.hxx> #endif #ifndef _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX #include <basegfx/polygon/b2dpolypolygontools.hxx> #endif #ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX #include <basegfx/polygon/b2dpolygontools.hxx> #endif #ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX #include <basegfx/matrix/b2dhommatrix.hxx> #endif ////////////////////////////////////////////////////////////////////////////// sdr::properties::BaseProperties* E3dLatheObj::CreateObjectSpecificProperties() { return new sdr::properties::E3dLatheProperties(*this); } ////////////////////////////////////////////////////////////////////////////// TYPEINIT1(E3dLatheObj, E3dCompoundObject); /************************************************************************* |* |* Konstruktor aus 3D-Polygon, Scale gibt den Umrechnungsfaktor fuer |* die Koordinaten an |* \************************************************************************/ E3dLatheObj::E3dLatheObj(E3dDefaultAttributes& rDefault, const basegfx::B2DPolyPolygon rPoly2D) : E3dCompoundObject(rDefault), maPolyPoly2D(rPoly2D) { // since the old class PolyPolygon3D did mirror the given PolyPolygons in Y, do the same here basegfx::B2DHomMatrix aMirrorY; aMirrorY.scale(1.0, -1.0); maPolyPoly2D.transform(aMirrorY); // Defaults setzen SetDefaultAttributes(rDefault); // Ueberfluessige Punkte entfernen, insbesondere doppelte // Start- und Endpunkte verhindern maPolyPoly2D.removeDoublePoints(); if(maPolyPoly2D.count()) { const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0L)); sal_uInt32 nSegCnt(rPoly.count()); if(nSegCnt && !rPoly.isClosed()) { nSegCnt -= 1; } GetProperties().SetObjectItemDirect(Svx3DVerticalSegmentsItem(nSegCnt)); } // Geometrie erzeugen CreateGeometry(); } /************************************************************************* |* |* Leer-Konstruktor |* \************************************************************************/ E3dLatheObj::E3dLatheObj() : E3dCompoundObject() { // Defaults setzen E3dDefaultAttributes aDefault; SetDefaultAttributes(aDefault); } void E3dLatheObj::SetDefaultAttributes(E3dDefaultAttributes& rDefault) { GetProperties().SetObjectItemDirect(Svx3DSmoothNormalsItem(rDefault.GetDefaultLatheSmoothed())); GetProperties().SetObjectItemDirect(Svx3DSmoothLidsItem(rDefault.GetDefaultLatheSmoothFrontBack())); GetProperties().SetObjectItemDirect(Svx3DCharacterModeItem(rDefault.GetDefaultLatheCharacterMode())); GetProperties().SetObjectItemDirect(Svx3DCloseFrontItem(rDefault.GetDefaultLatheCloseFront())); GetProperties().SetObjectItemDirect(Svx3DCloseBackItem(rDefault.GetDefaultLatheCloseBack())); } /************************************************************************* |* |* Give out simple line geometry |* \************************************************************************/ basegfx::B3DPolyPolygon E3dLatheObj::Get3DLineGeometry() const { return maLinePolyPolygon; } /************************************************************************* |* |* Die eigentliche Konstruktionmethode, erzeugt einen Koerper durch |* Rotation des uebergebenen Polygons um die senkrechte Y-Achse. Wenn |* nEndAngle < 3600 ist, werden ausserdem zwei Deckelflaechen-Polygone |* erzeugt, die den Koerper abschliessen. Das Polygon sollte in der |* XY-Ebene liegen, mit X-Koordinaten >= 0; wenn die Anfangs- und End- |* X-Koordinaten nicht 0 sind, sollte das Polygon geschlossen sein. |* Wenn bDblSided TRUE ist, werden die Rotationsflaechen doppelseitig |* angelegt und keine Deckelflaechen erzeugt. |* \************************************************************************/ // Geometrieerzeugung void E3dLatheObj::CreateGeometry() { // Start der Geometrieerzeugung ankuendigen StartCreateGeometry(); // #78972# maLinePolyPolygon.clear(); if(maPolyPoly2D.count()) { // Polygon erzeugen // Eventuelle Anpassung der Segmentanzahlen basegfx::B2DPolyPolygon aLathePoly2D(CreateLathePolyPoly(maPolyPoly2D, GetVerticalSegments())); aLathePoly2D = basegfx::tools::correctOrientations(aLathePoly2D); const basegfx::B2VectorOrientation aOrient = basegfx::tools::getOrientation(aLathePoly2D.getB2DPolygon(0L)); if(basegfx::ORIENTATION_NEGATIVE == aOrient) { aLathePoly2D.flip(); } // #i28528# basegfx::B3DPolyPolygon aFrontLines; basegfx::B3DPolyPolygon aBackLines; basegfx::B3DPolyPolygon aInBetweenLines; basegfx::B3DPolyPolygon aLathePoly3D(basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon(aLathePoly2D)); // Spezialfall Einzelnes Polygon erzeugen BOOL bSinglePoly = (GetEndAngle() == 0 || GetHorizontalSegments() == 0); if(bSinglePoly) { // nur ein Polygon erzeugen GetProperties().SetObjectItemDirect(Svx3DDoubleSidedItem(TRUE)); // Fuer evtl. selbst erzeugte Normalen basegfx::B3DPolyPolygon aNormalsFront(ImpCreateByPattern(aLathePoly3D)); // Normalen und Vorderseite selbst erzeugen aNormalsFront = ImpAddFrontNormals(aNormalsFront, basegfx::B3DVector(0.0, 0.0, 1.0)); ImpCreateFront(aLathePoly3D, aNormalsFront, GetCreateNormals(), GetCreateTexture()); // #i28528# aInBetweenLines.append(aLathePoly3D); } else { // Eventuell doppelseitig erzeugen? if(!aLathePoly3D.isClosed()) { GetProperties().SetObjectItemDirect(Svx3DDoubleSidedItem(TRUE)); } // Seiten genenrieren? BOOL bCreateSides = ((GetEndAngle() < 3600 && !GetDoubleSided()) || (GetBackScale() != 100)); // Polygone vorbereiten basegfx::B3DPolyPolygon aPrev, aFront, aBack, aNext; // Rotation vorbereiten double fAng = DEG2RAD(double(GetEndAngle()) / 10); basegfx::B3DHomMatrix aRotMat; // Skalierung vorbereiten double fScalePerStep(1.0); if(GetBackScale() != 100) { fScalePerStep = (((double)GetBackScale() - 100.0) / 100.0) / (double)GetHorizontalSegments(); } // Texturen erzeugen? double fTextureDepth(1.0); double fTextureStart(0.0); if(!GetCreateTexture()) { fTextureStart = fTextureDepth = 0.0; } // aPrev bis aBack ausfuellen als Startvorbereitung aRotMat.rotate(0.0, -(fAng / (double)GetHorizontalSegments()), 0.0); aPrev = aLathePoly3D; aPrev.transform(aRotMat); if(GetBackScale() != 100) { // #i74056# aPrev = ImpScalePoly(aPrev, 1.0 - fScalePerStep); } aRotMat.identity(); aRotMat.rotate(0.0, fAng / (double)GetHorizontalSegments(), 0.0); aFront = aLathePoly3D; aBack = aLathePoly3D; aBack.transform(aRotMat); if(GetBackScale() != 100) { // #i74056# aBack = ImpScalePoly(aBack, 1.0 + fScalePerStep); } // Werte fuer Textur-Zwischensegmenterzeugung berechnen double fTmpStart(0.0); double fTmpLength(fTextureDepth / (double)GetHorizontalSegments()); sal_uInt16 nUpperBound((sal_uInt16)GetHorizontalSegments()); for(UINT16 a=0;a<nUpperBound;a++) { // Naechstes Polygon vorbereiten aNext = aLathePoly3D; // Rotieren if(!(a+2 == nUpperBound && GetEndAngle() == 3600)) { aRotMat.identity(); aRotMat.rotate(0.0, (fAng * (double)(a+2))/ (double)nUpperBound, 0.0); aNext.transform(aRotMat); } // Skalieren if(GetBackScale() != 100) { // #i74056# aNext = ImpScalePoly(aNext, 1.0 + (fScalePerStep * (double)(a+2))); } // Jetzt Segment erzeugen ImpCreateSegment( aFront, aBack, &aPrev, &aNext, (a == 0) && bCreateSides && GetCloseFront(), // #107245# bLatheCloseFront, (a == nUpperBound-1) && bCreateSides && GetCloseBack(), // #107245# bLatheCloseBack, ((double)GetPercentDiagonal() / 200.0) * (double(nUpperBound) / 6.0), GetSmoothNormals(), // #107245# GetLatheSmoothed(), GetSmoothNormals(), // #107245# GetLatheSmoothed(), GetSmoothLids(), // #107245# GetLatheSmoothFrontBack(), 1.0, fTmpStart, fTmpLength, GetCreateTexture(), GetCreateNormals(), GetCharacterMode(), // #107245# GetLatheCharacterMode(), TRUE, // #78972# &aFrontLines, &aBackLines, &aInBetweenLines); // naechsten Schritt vorbereiten fTmpStart += fTmpLength; aPrev = aFront; aFront = aBack; aBack = aNext; } } // #78972# // Simply add them for preparing line geometry maLinePolyPolygon.append(aFrontLines); maLinePolyPolygon.append(aInBetweenLines); maLinePolyPolygon.append(aBackLines); // #i28528# sal_Bool bClosedLines((3600 == GetEndAngle()) && (100 == GetBackScale())); basegfx::B3DPolyPolygon aNewPolyPoly(ImpCompleteLinePolygon(maLinePolyPolygon, aLathePoly3D.count(), bClosedLines)); if(GetReducedLineGeometry()) { // replace vertical with horizontal lines maLinePolyPolygon = aNewPolyPoly; // append front lines maLinePolyPolygon.append(aFrontLines); // append back lines maLinePolyPolygon.append(aBackLines); } else { // append horizontal lines maLinePolyPolygon.append(aNewPolyPoly); } //ImpCorrectLinePolygon(maLinePolyPolygon, aLathePoly3D.count()); } // call parent E3dCompoundObject::CreateGeometry(); } basegfx::B2DPolyPolygon E3dLatheObj::CreateLathePolyPoly(const basegfx::B2DPolyPolygon& rPolyPoly2D, sal_uInt32 nVSegs) { basegfx::B2DPolyPolygon aRetval(rPolyPoly2D); const sal_uInt32 nCnt(aRetval.count()); const basegfx::B2DPolygon aFirstOriginal(aRetval.getB2DPolygon(0L)); sal_uInt32 nOrigSegmentCnt(aFirstOriginal.count()); if(nOrigSegmentCnt && !aFirstOriginal.isClosed()) { nOrigSegmentCnt -= 1; } if(nVSegs && nVSegs != nOrigSegmentCnt) { // make sure minimum is not too small, 3 edges for closed // and 2 edges for open obects sal_uInt32 nMinVSegs(aFirstOriginal.isClosed() ? 3L : 2L); if(nVSegs <= nMinVSegs) { nVSegs = nMinVSegs; } if(nVSegs != nOrigSegmentCnt) { // Erstes Polygon anpassen aRetval.setB2DPolygon(0L, CreateLathePoly(aRetval.getB2DPolygon(0L), nVSegs)); GetProperties().SetObjectItemDirect(Svx3DVerticalSegmentsItem(nVSegs)); // andere Polygone im richtigen Verhaeltnis anpassen, // aber nur, wenn Wert fuer erstes angepasst werden musste for(sal_uInt32 i(1L); i < nCnt; i++ ) { basegfx::B2DPolygon aPoly2D(aRetval.getB2DPolygon(i)); sal_uInt32 nSegCnt(aPoly2D.count()); if(nSegCnt && !aPoly2D.isClosed()) { nSegCnt -= 1; } sal_uInt32 nNewVSegs((nSegCnt * nVSegs) / nOrigSegmentCnt); // make sure min is not too small for subpolys, too if(nNewVSegs <= nMinVSegs) { nNewVSegs = nMinVSegs; } if(nNewVSegs && nNewVSegs != nSegCnt) { aRetval.setB2DPolygon(i, CreateLathePoly(aPoly2D, nNewVSegs)); } } } } return aRetval; } basegfx::B2DPolygon E3dLatheObj::CreateLathePoly(const basegfx::B2DPolygon& rPoly2D, sal_uInt32 nVSegs) { // attention: Here number of SEGMENTS is given, while GetExpandedPolygon() // takes number of points. Calc PntNum first sal_uInt32 nNumPts(rPoly2D.isClosed() ? nVSegs : nVSegs + 1L); if(nNumPts && rPoly2D.count() && nNumPts != rPoly2D.count()) { // create a expanded or compresssed poly with exactly nNum Points basegfx::B2DPolygon aRetval; const double fLength(basegfx::tools::getLength(rPoly2D)); const double fDivisor(rPoly2D.isClosed() ? ((double)nNumPts) : ((double)(nNumPts - 1L))); for(sal_uInt32 a(0L); a < nNumPts; a++) { const double fRelativePos((double)a / fDivisor); // 0.0 .. 1.0 for open, less for closed (without 1.0 e.g. last point) const basegfx::B2DPoint aNewPoint(basegfx::tools::getPositionRelative(rPoly2D, fRelativePos, fLength)); aRetval.append(aNewPoint); } // copy closed flag aRetval.setClosed(rPoly2D.isClosed()); return aRetval; } return rPoly2D; } /************************************************************************* |* |* Identifier zurueckgeben |* \************************************************************************/ UINT16 E3dLatheObj::GetObjIdentifier() const { return E3D_LATHEOBJ_ID; } /************************************************************************* |* |* Zuweisungsoperator |* \************************************************************************/ void E3dLatheObj::operator=(const SdrObject& rObj) { // erstmal alle Childs kopieren E3dCompoundObject::operator=(rObj); // weitere Parameter kopieren const E3dLatheObj& r3DObj = (const E3dLatheObj&)rObj; maPolyPoly2D = r3DObj.maPolyPoly2D; // #95519# copy LinePolygon info, too maLinePolyPolygon = r3DObj.maLinePolyPolygon; } /************************************************************************* |* |* Wandle das Objekt in ein Gruppenobjekt bestehend aus n Polygonen |* \************************************************************************/ SdrObject *E3dLatheObj::DoConvertToPolyObj(BOOL /*bBezier*/) const { return NULL; } /************************************************************************* |* |* Neue Segmentierung (Beschreibung siehe Header-File) |* \************************************************************************/ void E3dLatheObj::ReSegment(sal_uInt32 nHSegs, sal_uInt32 nVSegs) { if ((nHSegs != GetHorizontalSegments() || nVSegs != GetVerticalSegments()) && (nHSegs != 0 || nVSegs != 0)) { GetProperties().SetObjectItemDirect(Svx3DHorizontalSegmentsItem(nHSegs)); GetProperties().SetObjectItemDirect(Svx3DVerticalSegmentsItem(nVSegs)); bGeometryValid = FALSE; } } /************************************************************************* |* |* Lokale Parameter setzen mit Geometrieneuerzeugung |* \************************************************************************/ void E3dLatheObj::SetPolyPoly2D(const basegfx::B2DPolyPolygon& rNew) { if(maPolyPoly2D != rNew) { maPolyPoly2D = rNew; maPolyPoly2D.removeDoublePoints(); if(maPolyPoly2D.count()) { const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0L)); sal_uInt32 nSegCnt(rPoly.count()); if(nSegCnt && !rPoly.isClosed()) { nSegCnt -= 1; } GetProperties().SetObjectItemDirect(Svx3DVerticalSegmentsItem(nSegCnt)); } bGeometryValid = FALSE; } } /************************************************************************* |* |* Get the name of the object (singular) |* \************************************************************************/ void E3dLatheObj::TakeObjNameSingul(XubString& rName) const { rName=ImpGetResStr(STR_ObjNameSingulLathe3d); String aName( GetName() ); if(aName.Len()) { rName += sal_Unicode(' '); rName += sal_Unicode('\''); rName += aName; rName += sal_Unicode('\''); } } /************************************************************************* |* |* Get the name of the object (plural) |* \************************************************************************/ void E3dLatheObj::TakeObjNamePlural(XubString& rName) const { rName=ImpGetResStr(STR_ObjNamePluralLathe3d); } /************************************************************************* |* |* Aufbrechen |* \************************************************************************/ BOOL E3dLatheObj::IsBreakObjPossible() { return TRUE; } SdrAttrObj* E3dLatheObj::GetBreakObj() { // create PathObj basegfx::B3DPolyPolygon aLathePoly3D(basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon(maPolyPoly2D)); basegfx::B2DPolyPolygon aTransPoly(TransformToScreenCoor(aLathePoly3D)); SdrPathObj* pPathObj = new SdrPathObj(OBJ_PLIN, aTransPoly); if(pPathObj) { // Attribute setzen SfxItemSet aSet(GetObjectItemSet()); // Linien aktivieren, um Objekt garantiert sichtbar zu machen aSet.Put(XLineStyleItem(XLINE_SOLID)); pPathObj->SetMergedItemSet(aSet); } return pPathObj; } // eof