/*************************************************************************
 *
 *  $RCSfile: lathe3d.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: aw $ $Date: 2001-02-15 18:38:06 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "svdstr.hrc"
#include "svdglob.hxx"

#ifndef _SV_POLY_HXX
#include <vcl/poly.hxx>
#endif

#ifndef _SVDPAGE_HXX
#include "svdpage.hxx"
#endif

#ifndef _XOUTX_HXX
#include "xoutx.hxx"
#endif

#ifndef _E3D_GLOBL3D_HXX
#include "globl3d.hxx"
#endif

#ifndef _SVDIO_HXX
#include "svdio.hxx"
#endif

#ifndef _E3D_POLYOB3D_HXX
#include "polyob3d.hxx"
#endif

#ifndef _E3D_LATHE3D_HXX
#include "lathe3d.hxx"
#endif

#ifndef _POLY3D_HXX
#include "poly3d.hxx"
#endif

#ifndef _XPOLY_HXX
#include "xpoly.hxx"
#endif

#ifndef _SVX_SVXIDS_HRC
#include "svxids.hrc"
#endif

#ifndef _SVDOPATH_HXX
#include "svdopath.hxx"
#endif

#ifndef _SVDMODEL_HXX
#include "svdmodel.hxx"
#endif

#ifndef _SVX3DITEMS_HXX
#include "svx3ditems.hxx"
#endif

TYPEINIT1(E3dLatheObj, E3dCompoundObject);

/*************************************************************************
|*
|* Konstruktor aus SV-Polygon, Scale gibt den Umrechnungsfaktor fuer
|* die Koordinaten an
|*
\************************************************************************/

E3dLatheObj::E3dLatheObj(E3dDefaultAttributes& rDefault, const PolyPolygon& rPoly)
:   E3dCompoundObject(rDefault),
    aPolyPoly3D (PolyPolygon3D(rPoly, rDefault.GetDefaultLatheScale()))
{
    // Defaults setzen
    SetDefaultAttributes(rDefault);

    // Ueberfluessige Punkte entfernen, insbesondere doppelte
    // Start- und Endpunkte verhindern
    aPolyPoly3D.RemoveDoublePoints();

    const Polygon3D rPoly3D = aPolyPoly3D[0];
    sal_uInt32 nSegCnt((sal_uInt32)rPoly3D.GetPointCount());
    if(nSegCnt && !rPoly3D.IsClosed())
        nSegCnt -= 1;
    mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nSegCnt));

    // Geometrie erzeugen
    CreateGeometry();
}

/*************************************************************************
|*
|* wie voriger Konstruktor, nur mit XPolygon; das XPolygon wird
|* jedoch nicht Bezier-konvertiert, sondern es werden nur seine
|* Punktkoordinaten uebernommen
|*
\************************************************************************/

E3dLatheObj::E3dLatheObj(E3dDefaultAttributes& rDefault, const XPolyPolygon& rXPoly)
:   E3dCompoundObject(rDefault),
    aPolyPoly3D (PolyPolygon3D(rXPoly, rDefault.GetDefaultLatheScale()))
{
    // Defaults setzen
    SetDefaultAttributes(rDefault);

    // Ueberfluessige Punkte entfernen, insbesondere doppelte
    // Start- und Endpunkte verhindern
    aPolyPoly3D.RemoveDoublePoints();
    const Polygon3D rPoly = aPolyPoly3D[0];
    sal_uInt32 nSegCnt((sal_uInt32)rPoly.GetPointCount());
    if(nSegCnt && !rPoly.IsClosed())
        nSegCnt -= 1;
    mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nSegCnt));

    // Geometrie erzeugen
    CreateGeometry();
}

/*************************************************************************
|*
\************************************************************************/

E3dLatheObj::E3dLatheObj(E3dDefaultAttributes& rDefault, const XPolygon& rXPoly)
:   E3dCompoundObject(rDefault),
    aPolyPoly3D (PolyPolygon3D(rXPoly, rDefault.GetDefaultLatheScale()))
{
    // Defaults setzen
    SetDefaultAttributes(rDefault);

    // Ueberfluessige Punkte entfernen, insbesondere doppelte
    // Start- und Endpunkte verhindern
    aPolyPoly3D.RemoveDoublePoints();
    const Polygon3D rPoly = aPolyPoly3D[0];
    sal_uInt32 nSegCnt((sal_uInt32)rPoly.GetPointCount());
    if(nSegCnt && !rPoly.IsClosed())
        nSegCnt -= 1;
    mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nSegCnt));

    // Geometrie erzeugen
    CreateGeometry();
}

/*************************************************************************
|*
|* Konstruktor aus 3D-Polygon, Scale gibt den Umrechnungsfaktor fuer
|* die Koordinaten an
|*
\************************************************************************/

E3dLatheObj::E3dLatheObj (E3dDefaultAttributes& rDefault, const PolyPolygon3D rPoly3D)
:   E3dCompoundObject(rDefault),
    aPolyPoly3D(rPoly3D)
{
    // Defaults setzen
    SetDefaultAttributes(rDefault);

    // Ueberfluessige Punkte entfernen, insbesondere doppelte
    // Start- und Endpunkte verhindern
    aPolyPoly3D.RemoveDoublePoints();
    const Polygon3D rPoly = aPolyPoly3D[0];
    sal_uInt32 nSegCnt((sal_uInt32)rPoly.GetPointCount());
    if(nSegCnt && !rPoly.IsClosed())
        nSegCnt -= 1;
    mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nSegCnt));

    // Geometrie erzeugen
    CreateGeometry();
}

/*************************************************************************
|*
|* Leer-Konstruktor
|*
\************************************************************************/

E3dLatheObj::E3dLatheObj()
:    aPolyPoly3D(Polygon3D())
{
    // Defaults setzen
    E3dDefaultAttributes aDefault;
    SetDefaultAttributes(aDefault);
}

void E3dLatheObj::SetDefaultAttributes(E3dDefaultAttributes& rDefault)
{
    // Defaults setzen
    ImpForceItemSet();

    fLatheScale = rDefault.GetDefaultLatheScale();
    bLatheSmoothed = rDefault.GetDefaultLatheSmoothed();
    bLatheSmoothFrontBack = rDefault.GetDefaultLatheSmoothFrontBack();
    bLatheCharacterMode = rDefault.GetDefaultLatheCharacterMode();
    bLatheCloseFront = rDefault.GetDefaultLatheCloseFront();
    bLatheCloseBack = rDefault.GetDefaultLatheCloseBack();
}

/*************************************************************************
|*
|* 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();

    // Polygon erzeugen
    PolyPolygon3D aLathePoly3D(aPolyPoly3D);

    // Eventuelle Anpassung der Segmentanzahlen
    aLathePoly3D = CreateLathePolyPoly(aPolyPoly3D, GetVerticalSegments());

    // Normale holen
    Vector3D aNormal = aLathePoly3D.GetNormal();
    if(aNormal.Z() > 0.0)
    {
        aLathePoly3D.FlipDirections();
        aNormal = aLathePoly3D.GetNormal();
    }

    // Orientierung evtl. vorhandener Loecher in einen definierten
    // Ausgangszustand bringen
    aLathePoly3D.SetDirections();

    // Spezialfall Einzelnes Polygon erzeugen
    BOOL bSinglePoly = (GetEndAngle() == 0 || GetHorizontalSegments() == 0);
    if(bSinglePoly)
    {
        // nur ein Polygon erzeugen
        mpObjectItemSet->Put(Svx3DDoubleSidedItem(TRUE));

        // Fuer evtl. selbst erzeugte Normalen
        PolyPolygon3D aNormalsFront;

        // Normalen und Vorderseite selbst erzeugen
        AddFrontNormals(aLathePoly3D, aNormalsFront, aNormal);
        CreateFront(aLathePoly3D, aNormalsFront, GetCreateNormals(), GetCreateTexture());
    }
    else
    {
        // Eventuell doppelseitig erzeugen?
        if(!aLathePoly3D.IsClosed())
            mpObjectItemSet->Put(Svx3DDoubleSidedItem(TRUE));

        // Seiten genenrieren?
        BOOL bCreateSides = ((GetEndAngle() < 3600 && !GetDoubleSided())
            || (GetBackScale() != 100));

        // Polygone vorbereiten
        PolyPolygon3D aPrev, aFront, aBack, aNext;

        // Rotation vorbereiten
        double fAng = DEG2RAD(double(GetEndAngle()) / 10);
        Matrix4D aRotMat;

        // Skalierung vorbereiten
        double fScalePerStep;
        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.RotateY(-(fAng / (double)GetHorizontalSegments()));
        aPrev = aLathePoly3D;
        RotatePoly(aPrev, aRotMat);
        if(GetBackScale() != 100)
        {
            ScalePoly(aPrev, 1.0 - fScalePerStep);
        }
        aRotMat.Identity();
        aRotMat.RotateY(fAng / (double)GetHorizontalSegments());
        aFront = aLathePoly3D;
        aBack = aLathePoly3D;
        RotatePoly(aBack, aRotMat);
        if(GetBackScale() != 100)
        {
            ScalePoly(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.RotateY((fAng * (double)(a+2))/ (double)nUpperBound);
                RotatePoly(aNext, aRotMat);
            }

            // Skalieren
            if(GetBackScale() != 100)
            {
                ScalePoly(aNext, 1.0 + (fScalePerStep * (double)(a+2)));
            }

            // Jetzt Segment erzeugen
            CreateSegment(
                aFront,
                aBack,
                &aPrev,
                &aNext,
                (a == 0) && bCreateSides && bLatheCloseFront,
                (a == nUpperBound-1) && bCreateSides && bLatheCloseBack,
                ((double)GetPercentDiagonal() / 200.0)
                    * (double(nUpperBound) / 6.0),
                GetLatheSmoothed(),
                GetLatheSmoothed(),
                GetLatheSmoothFrontBack(),
                1.0,
                fTmpStart,
                fTmpLength,
                GetCreateTexture(),
                GetCreateNormals(),
                GetLatheCharacterMode(),
                TRUE);

            // naechsten Schritt vorbereiten
            fTmpStart += fTmpLength;
            aPrev = aFront;
            aFront = aBack;
            aBack = aNext;
        }
    }

    // call parent
    E3dCompoundObject::CreateGeometry();
}

PolyPolygon3D E3dLatheObj::CreateLathePolyPoly(PolyPolygon3D& rPolyPoly3D, long nVSegs)
{
    PolyPolygon3D aLathePolyPolygon3D = rPolyPoly3D;
    sal_uInt16 nCnt = aLathePolyPolygon3D.Count();
    sal_uInt16 nOrigSegmentCnt = aPolyPoly3D[0].GetPointCount();

    if(nOrigSegmentCnt && !aPolyPoly3D[0].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_Int32 nMinVSegs = aPolyPoly3D[0].IsClosed() ? 3 : 2;
        if(nVSegs <= nMinVSegs)
            nVSegs = nMinVSegs;

        if(nVSegs != nOrigSegmentCnt)
        {
            // Erstes Polygon anpassen
            aLathePolyPolygon3D[0] = CreateLathePoly(aLathePolyPolygon3D[0], nVSegs);
            mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nVSegs));

            // andere Polygone im richtigen Verhaeltnis anpassen,
            // aber nur, wenn Wert fuer erstes angepasst werden musste
            for(UINT16 i = 1; i < nCnt; i++ )
            {
                Polygon3D &rPoly3D = aLathePolyPolygon3D[i];
                sal_uInt16 nSegCnt(rPoly3D.GetPointCount());
                if(nSegCnt && !rPoly3D.IsClosed())
                    nSegCnt -= 1;
                long nNewVSegs = (nSegCnt * nVSegs) / nOrigSegmentCnt;

                // make sure min is not too small for subpolys, too
                if(nNewVSegs <= nMinVSegs)
                    nNewVSegs = nMinVSegs;

                if(nNewVSegs && nNewVSegs != nSegCnt)
                {
                    aLathePolyPolygon3D[i] = CreateLathePoly(aLathePolyPolygon3D[i], nNewVSegs);
                }
            }
        }
    }
    return aLathePolyPolygon3D;
}

Polygon3D E3dLatheObj::CreateLathePoly(Polygon3D& rPoly3D, long nVSegs)
{
    // attention: Here number of SEGMENTS is given, while GetExpandedPolygon()
    // takes number of points. Calc PntNum first
    long nNumPts = rPoly3D.IsClosed() ? nVSegs : nVSegs + 1;
    if(nNumPts != rPoly3D.GetPointCount())
        return rPoly3D.GetExpandedPolygon(nNumPts);
    return rPoly3D;
}

/*************************************************************************
|*
|* Identifier zurueckgeben
|*
\************************************************************************/

UINT16 E3dLatheObj::GetObjIdentifier() const
{
    return E3D_LATHEOBJ_ID;
}

/*************************************************************************
|*
|* Wireframe erzeugen
|*
\************************************************************************/

void E3dLatheObj::CreateWireframe(Polygon3D& rWirePoly, const Matrix4D* pTf,
    E3dDragDetail eDetail)
{
    // Nur selbst erzeugen, wenn alle Linien angezeigt werden sollen
    if ( eDetail == E3DDETAIL_ALLLINES ||
        (eDetail == E3DDETAIL_DEFAULT && GetDragDetail() == E3DDETAIL_ALLLINES) )
    {
        // Detailliert erzeugen
    }
    else
    {
        // call parent
        E3dObject::CreateWireframe(rWirePoly, pTf, eDetail);
    }
}

/*************************************************************************
|*
|* Zuweisungsoperator
|*
\************************************************************************/

void E3dLatheObj::operator=(const SdrObject& rObj)
{
    // erstmal alle Childs kopieren
    E3dCompoundObject::operator=(rObj);

    // weitere Parameter kopieren
    const E3dLatheObj& r3DObj = (const E3dLatheObj&)rObj;

    aPolyPoly3D  = r3DObj.aPolyPoly3D;
    fLatheScale  = r3DObj.fLatheScale;

    // Ab Version 374 (15.12.97)
    bLatheSmoothed = r3DObj.bLatheSmoothed;
    bLatheSmoothFrontBack = r3DObj.bLatheSmoothFrontBack;
    bLatheCharacterMode = r3DObj.bLatheCharacterMode;
    bLatheCloseFront = r3DObj.bLatheCloseFront;
    bLatheCloseBack = r3DObj.bLatheCloseBack;
}

/*************************************************************************
|*
|* Objektdaten in Stream speichern
|*
\************************************************************************/

void E3dLatheObj::WriteData(SvStream& rOut) const
{
    long nVersion = rOut.GetVersion(); // Build_Nr * 10 z.B. 3810
    if(nVersion < 3800)
    {
        // Alte Geometrie erzeugen, um die E3dPolyObj's zu haben
        ((E3dCompoundObject*)this)->ReCreateGeometry(TRUE);
    }

    // leider kann das E3dLatheObj nicht auf E3dObject abgestuetzt werden,
    // da neue Member hinzugekommen sind und die Kompatibilitaet erhalten
    // bleiben muss.
    SdrAttrObj::WriteData(rOut);

    // Fuer Abwaertskompatibilitaet (Lesen neuer Daten mit altem Code)
    SdrDownCompat aCompat(rOut, STREAM_WRITE);
#ifdef DBG_UTIL
    aCompat.SetID("E3dLatheObj");
#endif

    pSub->Save(rOut);

    // Parameter aus E3dObject speichern
    rOut << aLocalBoundVol;
    Old_Matrix3D aMat3D;
    aMat3D = aTfMatrix;
    rOut << aMat3D;
    rOut << nLogicalGroup;
    rOut << nObjTreeLevel;
    rOut << nPartOfParent;
    rOut << UINT16(eDragDetail);

    // neue Member
    // Alte version schreibt Polygon3D raus, neue Version
    // benutzt dafuer das erste Teilpolygon von PolyPolygon3D
    // rOut << aPolyPoly3D;
    rOut << aPolyPoly3D[0];

    rOut << GetHorizontalSegments();

    rOut << GetEndAngle();

    rOut << ((E3dLatheObj*)this)->GetDoubleSided();
    rOut << fLatheScale;

    // Ab Version 364f (19.06.97)

    // #83965# internally the real number of segments (edges) is
    // used, no longer the number of points
    sal_Int32 nVSegs = GetVerticalSegments();
    if(!aPolyPoly3D[0].IsClosed())
        nVSegs += 1;

    rOut << nVSegs;

    // Ab Version 374 (15.12.97)
    rOut << aPolyPoly3D;

    rOut << ((double)GetBackScale() / 100.0);

    rOut << ((double)GetPercentDiagonal() / 200.0);

    rOut << (BOOL)bLatheSmoothed;
    rOut << (BOOL)bLatheSmoothFrontBack;
    rOut << (BOOL)bLatheCharacterMode;

    // Ab Version 395 (8.6.98): Parameter aus dem Objekt
    // E3dCompoundObject. Da irgendwann mal jemand die Ableitungs-
    // hierarchie beim FileFormat unterbrochen hat, wurden diese Attribute
    // bisher NOCH NIE gespeichert (Grrr). Diese Stelle muss nun natuerlich
    // auch IMMER MITGEPFLEGT werden, wenn sich Parameter in
    // E3dCompoundObject oder E3dObject aendern.
    rOut << GetDoubleSided();

    rOut << BOOL(bCreateNormals);
    rOut << BOOL(bCreateTexture);

    sal_uInt16 nVal = GetNormalsKind();
    rOut << BOOL(nVal > 0);
    rOut << BOOL(nVal > 1);

    nVal = GetTextureProjectionX();
    rOut << BOOL(nVal > 0);
    rOut << BOOL(nVal > 1);

    nVal = GetTextureProjectionY();
    rOut << BOOL(nVal > 0);
    rOut << BOOL(nVal > 1);

    rOut << BOOL(GetShadow3D());

    rOut << GetMaterialAmbientColor();
    rOut << GetMaterialColor();
    rOut << GetMaterialSpecular();
    rOut << GetMaterialEmission();
    rOut << GetMaterialSpecularIntensity();

    aBackMaterial.WriteData(rOut);

    rOut << (UINT16)GetTextureKind();

    rOut << (UINT16)GetTextureMode();

    rOut << BOOL(GetNormalsInvert());

    // Ab Version 513a (5.2.99): Parameter fuer das
    // Erzeugen der Vorder/Rueckwand
    rOut << BOOL(bLatheCloseFront);
    rOut << BOOL(bLatheCloseBack);

    // neu ab 534: (hat noch gefehlt)
    rOut << BOOL(GetTextureFilter());

    if(nVersion < 3800)
    {
        // Geometrie neu erzeugen, um E3dPolyObj's wieder loszuwerden
        ((E3dCompoundObject*)this)->ReCreateGeometry();
    }
}

/*************************************************************************
|*
|* Objektdaten aus Stream laden
|*
\************************************************************************/

void E3dLatheObj::ReadData(const SdrObjIOHeader& rHead, SvStream& rIn)
{
    if (ImpCheckSubRecords (rHead, rIn))
    {
        // leider kann das E3dLatheObj nicht auf E3dObject abgestuetzt werden,
        // da neue Member hinzugekommen sind und die Kompatibilitaet erhalten
        // bleiben muss.
        SdrAttrObj::ReadData(rHead, rIn);

        // Fuer Abwaertskompatibilitaet (Lesen neuer Daten mit altem Code)
        SdrDownCompat aCompat(rIn, STREAM_READ);
#ifdef DBG_UTIL
        aCompat.SetID("E3dLatheObj");
#endif
        // dann die Member
        UINT16  nTmp16;

        pSub->Load(rIn, *pPage);

        // Parameter aus E3dObject laden
        rIn >> aLocalBoundVol;
        Old_Matrix3D aMat3D;
        rIn >> aMat3D;
        aTfMatrix = Matrix4D(aMat3D);
        rIn >> nLogicalGroup;
        rIn >> nObjTreeLevel;
        rIn >> nPartOfParent;
        rIn >> nTmp16; eDragDetail = E3dDragDetail(nTmp16);

        // BoundVolume muss neu berechnet werden
        bBoundVolValid = FALSE;

        if (aCompat.GetBytesLeft ())
        {
            // neue Member
            BOOL bTmp;
            sal_Int32 nTmp;

            // alte Version holt sich nur ein Polygon3D, wird hier durch
            // Eintragen als erstes Teilpolygon geladen
            // rIn >> aPolyPoly3D;
            rIn >> aPolyPoly3D[0];

            rIn >> nTmp;
            mpObjectItemSet->Put(Svx3DHorizontalSegmentsItem(nTmp));

            rIn >> nTmp;
            mpObjectItemSet->Put(Svx3DEndAngleItem(nTmp));

            rIn >> bTmp;
            mpObjectItemSet->Put(Svx3DDoubleSidedItem(bTmp));

            rIn >> fLatheScale;
        }

        if (aCompat.GetBytesLeft())
        {
            // Ab Version 364f (19.06.97)
            sal_Int32 nTmp;
            rIn >> nTmp;

            // #83965# internally the real number of segments (edges) is
            // used, no longer the number of points
            if(!aPolyPoly3D[0].IsClosed())
                nTmp -= 1;

            mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nTmp));
        }

        if (aCompat.GetBytesLeft())
        {
            // Ab Version 374 (15.12.97)
            // Gesamtes PolyPolygon laden
            BOOL bTmp;
            double fTmp;

            aPolyPoly3D.Clear();
            rIn >> aPolyPoly3D;

            rIn >> fTmp;
            mpObjectItemSet->Put(Svx3DBackscaleItem((sal_uInt16)(fTmp * 100.0)));

            rIn >> fTmp;
            mpObjectItemSet->Put(Svx3DPercentDiagonalItem(sal_uInt16(fTmp * 200.0)));

            rIn >> bTmp; bLatheSmoothed = bTmp;
            rIn >> bTmp; bLatheSmoothFrontBack = bTmp;
            rIn >> bTmp; bLatheCharacterMode = bTmp;
        }
        else
        {
            // Geometrie aus erzeugten PolyObj's rekonstruieren
            mpObjectItemSet->Put(Svx3DBackscaleItem(100));

            mpObjectItemSet->Put(Svx3DPercentDiagonalItem(10));

            bLatheSmoothed = TRUE;
            bLatheSmoothFrontBack = FALSE;
            bLatheCharacterMode = FALSE;
        }

        if (aCompat.GetBytesLeft())
        {
            // Ab Version 395 (8.6.98): Parameter aus dem Objekt
            // E3dCompoundObject. Da irgendwann mal jemand die Ableitungs-
            // hierarchie beim FileFormat unterbrochen hat, wurden diese Attribute
            // bisher NOCH NIE gespeichert (Grrr). Diese Stelle muss nun natuerlich
            // auch IMMER MITGEPFLEGT werden, wenn sich Parameter in
            // E3dCompoundObject oder E3dObject aendern.
            BOOL bTmp, bTmp2;
            sal_uInt16 nTmp;

            rIn >> bTmp;
            mpObjectItemSet->Put(Svx3DDoubleSidedItem(bTmp));

            rIn >> bTmp; bCreateNormals = bTmp;
            rIn >> bTmp; bCreateTexture = bTmp;

            rIn >> bTmp;
            rIn >> bTmp2;
            if(bTmp == FALSE && bTmp2 == FALSE)
                nTmp = 0;
            else if(bTmp == TRUE && bTmp2 == FALSE)
                nTmp = 1;
            else
                nTmp = 2;
            mpObjectItemSet->Put(Svx3DNormalsKindItem(nTmp));

            rIn >> bTmp;
            rIn >> bTmp2;
            if(bTmp == FALSE && bTmp2 == FALSE)
                nTmp = 0;
            else if(bTmp == TRUE && bTmp2 == FALSE)
                nTmp = 1;
            else
                nTmp = 2;
            mpObjectItemSet->Put(Svx3DTextureProjectionXItem(nTmp));

            rIn >> bTmp;
            rIn >> bTmp2;
            if(bTmp == FALSE && bTmp2 == FALSE)
                nTmp = 0;
            else if(bTmp == TRUE && bTmp2 == FALSE)
                nTmp = 1;
            else
                nTmp = 2;
            mpObjectItemSet->Put(Svx3DTextureProjectionYItem(nTmp));

            rIn >> bTmp;
            mpObjectItemSet->Put(Svx3DShadow3DItem(bTmp));

            Color aCol;

            rIn >> aCol;
            SetMaterialAmbientColor(aCol);

            rIn >> aCol;
            // do NOT use, this is the old 3D-Color(!)
            // SetItem(XFillColorItem(String(), aCol));

            rIn >> aCol;
            mpObjectItemSet->Put(Svx3DMaterialSpecularItem(aCol));

            rIn >> aCol;
            mpObjectItemSet->Put(Svx3DMaterialEmissionItem(aCol));

            rIn >> nTmp;
            mpObjectItemSet->Put(Svx3DMaterialSpecularIntensityItem(nTmp));

            aBackMaterial.ReadData(rIn);

            rIn >> nTmp;
            mpObjectItemSet->Put(Svx3DTextureKindItem(nTmp));

            rIn >> nTmp;
            mpObjectItemSet->Put(Svx3DTextureModeItem(nTmp));

            rIn >> bTmp;
            mpObjectItemSet->Put(Svx3DNormalsInvertItem(bTmp));
        }

        if (aCompat.GetBytesLeft())
        {
            // Ab Version 513a (5.2.99): Parameter fuer das
            // Erzeugen der Vorder/Rueckwand
            BOOL bTmp;

            rIn >> bTmp; bLatheCloseFront = bTmp;
            rIn >> bTmp; bLatheCloseBack = bTmp;
        }
        else
        {
            bLatheCloseFront = TRUE;
            bLatheCloseBack = TRUE;
        }

        // neu ab 534: (hat noch gefehlt)
        if (aCompat.GetBytesLeft () >= sizeof (BOOL))
        {
            BOOL bTmp;
            rIn >> bTmp;
            mpObjectItemSet->Put(Svx3DTextureFilterItem(bTmp));
        }
    }

    // correct position of extrude polygon, in case it's not positioned
    // at the Z==0 layer
    if(aPolyPoly3D.Count() && aPolyPoly3D[0].GetPointCount())
    {
        const Vector3D& rFirstPoint = aPolyPoly3D[0][0];
        if(rFirstPoint.Z() != 0.0)
        {
            // change transformation so that source poly lies in Z == 0,
            // so it can be exported as 2D polygon
            //
            // ATTENTION: the translation has to be multiplied from LEFT
            // SIDE since it was executed as the first translate for this
            // 3D object during it's creation.
            double fTransDepth(rFirstPoint.Z());
            Matrix4D aTransMat;
            aTransMat.TranslateZ(fTransDepth);
            NbcSetTransform(aTransMat * GetTransform());

            // correct polygon itself
            aTransMat.Identity();
            aTransMat.TranslateZ(-fTransDepth);
            aPolyPoly3D.Transform(aTransMat);
        }
    }

    // Geometrie neu erzeugen
    ReCreateGeometry();
}

/*************************************************************************
|*
|* 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(long nHSegs, long nVSegs)
{
    if ((nHSegs != GetHorizontalSegments() || nVSegs != GetVerticalSegments()) &&
        (nHSegs != 0 || nVSegs != 0))
    {
        mpObjectItemSet->Put(Svx3DHorizontalSegmentsItem(nHSegs));

        mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nVSegs));

        bGeometryValid = FALSE;
    }
}

/*************************************************************************
|*
|* Lokale Parameter setzen mit Geometrieneuerzeugung
|*
\************************************************************************/

void E3dLatheObj::SetPolyPoly3D(const PolyPolygon3D& rNew)
{
    if(aPolyPoly3D != rNew)
    {
        aPolyPoly3D = rNew;

        // #83965# take care of vertical segments, too.
        sal_Int32 nNumVSegs = aPolyPoly3D[0].GetPointCount();
        if(!aPolyPoly3D[0].IsClosed())
            nNumVSegs -= 1;
        ImpForceItemSet();
        mpObjectItemSet->Put(Svx3DVerticalSegmentsItem(nNumVSegs));

        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheScale(double fNew)
{
    if(fLatheScale != fNew)
    {
        fLatheScale = fNew;
        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheSmoothed(BOOL bNew)
{
    if(bLatheSmoothed != bNew)
    {
        bLatheSmoothed = bNew;
        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheSmoothFrontBack(BOOL bNew)
{
    if(bLatheSmoothFrontBack != bNew)
    {
        bLatheSmoothFrontBack = bNew;
        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheCharacterMode(BOOL bNew)
{
    if(bLatheCharacterMode != bNew)
    {
        bLatheCharacterMode = bNew;
        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheCloseFront(BOOL bNew)
{
    if(bLatheCloseFront != bNew)
    {
        bLatheCloseFront = bNew;
        bGeometryValid = FALSE;
    }
}

void E3dLatheObj::SetLatheCloseBack(BOOL bNew)
{
    if(bLatheCloseBack != bNew)
    {
        bLatheCloseBack = bNew;
        bGeometryValid = FALSE;
    }
}

//////////////////////////////////////////////////////////////////////////////
// private support routines for ItemSet access

void E3dLatheObj::PostItemChange(const sal_uInt16 nWhich)
{
    // call parent
    E3dCompoundObject::PostItemChange(nWhich);

    switch(nWhich)
    {
        case SDRATTR_3DOBJ_HORZ_SEGS:
        {
            bGeometryValid = FALSE;
            break;
        }
        case SDRATTR_3DOBJ_VERT_SEGS:
        {
            bGeometryValid = FALSE;
            break;
        }
        case SDRATTR_3DOBJ_PERCENT_DIAGONAL:
        {
            bGeometryValid = FALSE;
            break;
        }
        case SDRATTR_3DOBJ_BACKSCALE:
        {
            bGeometryValid = FALSE;
            break;
        }
        case SDRATTR_3DOBJ_END_ANGLE:
        {
            bGeometryValid = FALSE;
            break;
        }
    }
}

/*************************************************************************
|*
|* Get the name of the object (singular)
|*
\************************************************************************/

void E3dLatheObj::TakeObjNameSingul(XubString& rName) const
{
    rName=ImpGetResStr(STR_ObjNameSingulLathe3d);
}

/*************************************************************************
|*
|* 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
    PolyPolygon3D aTransPoly = TransformToScreenCoor(GetPolyPolygon());
    XPolyPolygon aPoly(aTransPoly.GetXPolyPolygon());
    SdrPathObj* pPathObj = new SdrPathObj(OBJ_PLIN, aPoly);

    if(pPathObj)
    {
        // set position ans size
        Rectangle aNewPosSize(aPoly.GetBoundRect());
        pPathObj->SetSnapRect(aNewPosSize);

        // Objekt ggf. schliessen
        BOOL bDistSmallerTen = FALSE;
        for(UINT16 nCnt=0;nCnt<pPathObj->GetPathPoly().Count();nCnt++)
        if(((XPolygon)(pPathObj->GetPathPoly()[0])).CalcDistance(0, pPathObj->GetPathPoly()[0].GetPointCount()-1) < 10)
        bDistSmallerTen = TRUE;
        if (!pPathObj->IsClosed() && bDistSmallerTen)
            pPathObj->ToggleClosed(0);

        // Attribute setzen
        SfxItemSet aSet(GetItemSet());

        // Linien aktivieren, um Objekt garantiert sichtbar zu machen
        aSet.Put(XLineStyleItem (XLINE_SOLID));

        pPathObj->SetItemSet(aSet);
    }

    return pPathObj;
}

// EOF