    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   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 .
     */

    #include <string.h>
    #include <vcl/gdimtf.hxx>
    #include <vcl/metaact.hxx>
    #include <vcl/virdev.hxx>
    #include <tools/poly.hxx>
    #include "dxf2mtf.hxx"

    #include <math.h>

    sal_uLong DXF2GDIMetaFile::CountEntities(const DXFEntities & rEntities)
    {
        const DXFBasicEntity * pBE;
        sal_uLong nRes;

        nRes=0;
        for (pBE=rEntities.pFirst; pBE!=nullptr; pBE=pBE->pSucc) nRes++;
        return nRes;
    }

    Color DXF2GDIMetaFile::ConvertColor(sal_uInt8 nColor)
    {
        return Color(
            pDXF->aPalette.GetRed( nColor ),
            pDXF->aPalette.GetGreen( nColor ),
            pDXF->aPalette.GetBlue( nColor ) );
    }

    long DXF2GDIMetaFile::GetEntityColor(const DXFBasicEntity & rE)
    {
        long nColor;
        const DXFLayer * pLayer;

        nColor=rE.nColor;
        if (nColor==256) {
            if (rE.m_sLayer.getLength() < 2) {
                nColor=nParentLayerColor;
            } else {
                pLayer=pDXF->aTables.SearchLayer(rE.m_sLayer);
                if (pLayer!=nullptr) nColor=pLayer->nColor;
                else nColor=nParentLayerColor;
            }
        }
        else if (nColor==0) nColor=nBlockColor;
        return nColor;
    }

    DXFLineInfo DXF2GDIMetaFile::LTypeToDXFLineInfo(OString const& rLineType)
    {
        const DXFLType * pLT;
        DXFLineInfo aDXFLineInfo;

        pLT = pDXF->aTables.SearchLType(rLineType);
        if (pLT==nullptr || pLT->nDashCount == 0) {
            aDXFLineInfo.eStyle = LineStyle::Solid;
        }
        else {
            aDXFLineInfo.eStyle = LineStyle::Dash;
            for (long i=0; i < (pLT->nDashCount); i++) {
                const double x = pLT->fDash[i] * pDXF->getGlobalLineTypeScale();
                if ( x >= 0.0 ) {
                    if ( aDXFLineInfo.nDotCount == 0 ) {
                        aDXFLineInfo.nDotCount ++;
                        aDXFLineInfo.fDotLen = x;
                    }
                    else if ( aDXFLineInfo.fDotLen == x ) {
                        aDXFLineInfo.nDotCount ++;
                    }
                    else if ( aDXFLineInfo.nDashCount == 0 ) {
                        aDXFLineInfo.nDashCount ++;
                        aDXFLineInfo.fDashLen = x;
                    }
                    else if ( aDXFLineInfo.fDashLen == x ) {
                        aDXFLineInfo.nDashCount ++;
                    }
                    else {
                        // It is impossible to be converted.
                    }
                }
                else {
                    if ( aDXFLineInfo.fDistance == 0 ) {
                        aDXFLineInfo.fDistance = -1 * x;
                    }
                    else {
                        // It is impossible to be converted.
                    }
                }

            }
        }

        return aDXFLineInfo;
    }

    DXFLineInfo DXF2GDIMetaFile::GetEntityDXFLineInfo(const DXFBasicEntity & rE)
    {
        DXFLineInfo aDXFLineInfo;

        aDXFLineInfo.eStyle = LineStyle::Solid;
        aDXFLineInfo.fWidth = 0;
        aDXFLineInfo.nDashCount = 0;
        aDXFLineInfo.fDashLen = 0;
        aDXFLineInfo.nDotCount = 0;
        aDXFLineInfo.fDotLen = 0;
        aDXFLineInfo.fDistance = 0;

        if (rE.m_sLineType == "BYLAYER") {
            if (rE.m_sLayer.getLength() < 2) {
                aDXFLineInfo=aParentLayerDXFLineInfo;
            } else {
                const DXFLayer * pLayer=pDXF->aTables.SearchLayer(rE.m_sLayer);
                if (pLayer!=nullptr) {
                    aDXFLineInfo = LTypeToDXFLineInfo(pLayer->m_sLineType);
                }
                else aDXFLineInfo=aParentLayerDXFLineInfo;
            }
        }
        else if (rE.m_sLineType == "BYBLOCK") {
            aDXFLineInfo=aBlockDXFLineInfo;
        }
        else {
            aDXFLineInfo = LTypeToDXFLineInfo(rE.m_sLineType);
        }
        return aDXFLineInfo;
    }

    bool DXF2GDIMetaFile::SetLineAttribute(const DXFBasicEntity & rE)
    {
        long nColor;
        Color aColor;

        nColor=GetEntityColor(rE);
        if (nColor<0) return false;
        aColor=ConvertColor(static_cast<sal_uInt8>(nColor));

        if (aActLineColor!=aColor) {
            pVirDev->SetLineColor( aActLineColor = aColor );
        }

        if (aActFillColor!=COL_TRANSPARENT) {
            pVirDev->SetFillColor(aActFillColor = COL_TRANSPARENT);
        }
        return true;
    }

    bool DXF2GDIMetaFile::SetAreaAttribute(const DXFBasicEntity & rE)
    {
        long nColor;
        Color aColor;

        nColor=GetEntityColor(rE);
        if (nColor<0) return false;
        aColor=ConvertColor(static_cast<sal_uInt8>(nColor));

        if (aActLineColor!=aColor) {
            pVirDev->SetLineColor( aActLineColor = aColor );
        }

        if ( aActFillColor == COL_TRANSPARENT || aActFillColor != aColor) {
            pVirDev->SetFillColor( aActFillColor = aColor );
        }
        return true;
    }

    bool DXF2GDIMetaFile::SetFontAttribute(const DXFBasicEntity & rE, short nAngle, sal_uInt16 nHeight)
    {
        long nColor;
        Color aColor;
        vcl::Font aFont;

        nAngle=-nAngle;
        while (nAngle>=3600) nAngle-=3600;
        while (nAngle<0) nAngle+=3600;

        nColor=GetEntityColor(rE);
        if (nColor<0) return false;
        aColor=ConvertColor(static_cast<sal_uInt8>(nColor));

        aFont.SetColor(aColor);
        aFont.SetTransparent(true);
        aFont.SetFamily(FAMILY_SWISS);
        aFont.SetFontSize(Size(0,nHeight));
        aFont.SetAlignment(ALIGN_BASELINE);
        aFont.SetOrientation(nAngle);
        if (aActFont!=aFont) {
            aActFont=aFont;
            pVirDev->SetFont(aActFont);
        }

        return true;
    }

    void DXF2GDIMetaFile::DrawLineEntity(const DXFLineEntity & rE, const DXFTransform & rTransform)
    {
        if (SetLineAttribute(rE)) {
            Point aP0,aP1;
            rTransform.Transform(rE.aP0,aP0);
            rTransform.Transform(rE.aP1,aP1);

            DXFLineInfo aDXFLineInfo;
            aDXFLineInfo=GetEntityDXFLineInfo(rE);
            LineInfo aLineInfo;
            aLineInfo = rTransform.Transform(aDXFLineInfo);

            pVirDev->DrawLine(aP0,aP1,aLineInfo);
            if (rE.fThickness!=0) {
                Point aP2,aP3;
                rTransform.Transform(rE.aP0+DXFVector(0,0,rE.fThickness),aP2);
                rTransform.Transform(rE.aP1+DXFVector(0,0,rE.fThickness),aP3);
                DrawLine(aP2,aP3);
                DrawLine(aP0,aP2);
                DrawLine(aP1,aP3);
            }
        }
    }

    void DXF2GDIMetaFile::DrawPointEntity(const DXFPointEntity & rE, const DXFTransform & rTransform)
    {

        if (SetLineAttribute(rE)) {
            Point aP0;
            rTransform.Transform(rE.aP0,aP0);
            if (rE.fThickness==0) pVirDev->DrawPixel(aP0);
            else {
                Point aP1;
                rTransform.Transform(rE.aP0+DXFVector(0,0,rE.fThickness),aP1);
                DrawLine(aP0,aP1);
            }
        }
    }

    void DXF2GDIMetaFile::DrawCircleEntity(const DXFCircleEntity & rE, const DXFTransform & rTransform)
    {
        double frx,fry;
        sal_uInt16 nPoints,i;
        DXFVector aC;

        if (!SetLineAttribute(rE)) return;
        rTransform.Transform(rE.aP0,aC);
        if (rE.fThickness==0 && rTransform.TransCircleToEllipse(rE.fRadius,frx,fry)) {
            pVirDev->DrawEllipse(
                tools::Rectangle(static_cast<long>(aC.fx-frx+0.5),static_cast<long>(aC.fy-fry+0.5),
                          static_cast<long>(aC.fx+frx+0.5),static_cast<long>(aC.fy+fry+0.5)));
        }
        else {
            double fAng;
            nPoints=OptPointsPerCircle;
            tools::Polygon aPoly(nPoints);
            for (i=0; i<nPoints; i++) {
                fAng=2*3.14159265359/static_cast<double>(nPoints-1)*static_cast<double>(i);
                rTransform.Transform(
                    rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),0),
                    aPoly[i]
                );
            }
            pVirDev->DrawPolyLine(aPoly);
            if (rE.fThickness!=0) {
                tools::Polygon aPoly2(nPoints);
                for (i=0; i<nPoints; i++) {
                    fAng=2*3.14159265359/static_cast<double>(nPoints-1)*static_cast<double>(i);
                    rTransform.Transform(
                        rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),rE.fThickness),
                        aPoly2[i]
                    );

                }
                pVirDev->DrawPolyLine(aPoly2);
                for (i=0; i<nPoints-1; i++) DrawLine(aPoly[i],aPoly2[i]);
            }
        }
    }

    void DXF2GDIMetaFile::DrawLine(const Point& rA, const Point& rB)
    {
        GDIMetaFile* pMetaFile = pVirDev->GetConnectMetaFile();
        assert(pMetaFile);
        //use AddAction instead of OutputDevice::DrawLine so that we can explicitly share
        //the aDefaultLineInfo between the MetaLineActions to reduce memory use
        pMetaFile->AddAction(new MetaLineAction(rA, rB, aDefaultLineInfo));
    }

    void DXF2GDIMetaFile::DrawArcEntity(const DXFArcEntity & rE, const DXFTransform & rTransform)
    {
        double frx,fry;
        sal_uInt16 nPoints,i;
        DXFVector aC;
        Point aPS,aPE;

        if (!SetLineAttribute(rE)) return;
        double fA1=rE.fStart;
        double fdA=rE.fEnd-fA1;
        fdA = fmod(fdA, 360.0);
        if (fdA<=0) fdA+=360.0;
        rTransform.Transform(rE.aP0,aC);
        if (rE.fThickness==0 && fdA>5.0 && rTransform.TransCircleToEllipse(rE.fRadius,frx,fry)) {
            DXFVector aVS(cos(fA1/180.0*3.14159265359),sin(fA1/180.0*3.14159265359),0.0);
            aVS*=rE.fRadius;
            aVS+=rE.aP0;
            DXFVector aVE(cos((fA1+fdA)/180.0*3.14159265359),sin((fA1+fdA)/180.0*3.14159265359),0.0);
            aVE*=rE.fRadius;
            aVE+=rE.aP0;
            if (rTransform.Mirror()) {
                rTransform.Transform(aVS,aPS);
                rTransform.Transform(aVE,aPE);
            }
            else {
                rTransform.Transform(aVS,aPE);
                rTransform.Transform(aVE,aPS);
            }
            pVirDev->DrawArc(
                tools::Rectangle(static_cast<long>(aC.fx-frx+0.5),static_cast<long>(aC.fy-fry+0.5),
                          static_cast<long>(aC.fx+frx+0.5),static_cast<long>(aC.fy+fry+0.5)),
                aPS,aPE
            );
        }
        else {
            double fAng;
            nPoints=static_cast<sal_uInt16>(fdA/360.0*static_cast<double>(OptPointsPerCircle)+0.5);
            if (nPoints<2) nPoints=2;
            tools::Polygon aPoly(nPoints);
            for (i=0; i<nPoints; i++) {
                fAng=3.14159265359/180.0 * ( fA1 + fdA/static_cast<double>(nPoints-1)*static_cast<double>(i) );
                rTransform.Transform(
                    rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),0),
                    aPoly[i]
                );
            }
            pVirDev->DrawPolyLine(aPoly);
            if (rE.fThickness!=0) {
                tools::Polygon aPoly2(nPoints);
                for (i=0; i<nPoints; i++) {
                    fAng=3.14159265359/180.0 * ( fA1 + fdA/static_cast<double>(nPoints-1)*static_cast<double>(i) );
                    rTransform.Transform(
                        rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),rE.fThickness),
                        aPoly2[i]
                    );
                }
                pVirDev->DrawPolyLine(aPoly2);
                for (i=0; i<nPoints; i++)
                    DrawLine(aPoly[i], aPoly2[i]);
            }
        }
    }

    void DXF2GDIMetaFile::DrawTraceEntity(const DXFTraceEntity & rE, const DXFTransform & rTransform)
    {
        if (SetLineAttribute(rE)) {
            tools::Polygon aPoly(4);
            rTransform.Transform(rE.aP0,aPoly[0]);
            rTransform.Transform(rE.aP1,aPoly[1]);
            rTransform.Transform(rE.aP3,aPoly[2]);
            rTransform.Transform(rE.aP2,aPoly[3]);
            pVirDev->DrawPolygon(aPoly);
            if (rE.fThickness!=0) {
                sal_uInt16 i;
                tools::Polygon aPoly2(4);
                DXFVector aVAdd(0,0,rE.fThickness);
                rTransform.Transform(rE.aP0+aVAdd,aPoly2[0]);
                rTransform.Transform(rE.aP1+aVAdd,aPoly2[1]);
                rTransform.Transform(rE.aP3+aVAdd,aPoly2[2]);
                rTransform.Transform(rE.aP2+aVAdd,aPoly2[3]);
                pVirDev->DrawPolygon(aPoly2);
                for (i=0; i<4; i++) DrawLine(aPoly[i],aPoly2[i]);
            }
        }
    }

    void DXF2GDIMetaFile::DrawSolidEntity(const DXFSolidEntity & rE, const DXFTransform & rTransform)
    {
        if (SetAreaAttribute(rE)) {
            sal_uInt16 nN;
            if (rE.aP2==rE.aP3) nN=3; else nN=4;
            tools::Polygon aPoly(nN);
            rTransform.Transform(rE.aP0,aPoly[0]);
            rTransform.Transform(rE.aP1,aPoly[1]);
            rTransform.Transform(rE.aP3,aPoly[2]);
            if (nN>3) rTransform.Transform(rE.aP2,aPoly[3]);
            pVirDev->DrawPolygon(aPoly);
            if (rE.fThickness!=0) {
                tools::Polygon aPoly2(nN);
                DXFVector aVAdd(0,0,rE.fThickness);
                rTransform.Transform(rE.aP0+aVAdd,aPoly2[0]);
                rTransform.Transform(rE.aP1+aVAdd,aPoly2[1]);
                rTransform.Transform(rE.aP3+aVAdd,aPoly2[2]);
                if (nN>3) rTransform.Transform(rE.aP2+aVAdd,aPoly2[3]);
                pVirDev->DrawPolygon(aPoly2);
                if (SetLineAttribute(rE)) {
                    sal_uInt16 i;
                    for (i=0; i<nN; i++) DrawLine(aPoly[i],aPoly2[i]);
                }
            }
        }
    }

    void DXF2GDIMetaFile::DrawTextEntity(const DXFTextEntity & rE, const DXFTransform & rTransform)
    {
        DXFVector aV;
        Point aPt;
        double fA;
        sal_uInt16 nHeight;
        short nAng;
        DXFTransform aT( DXFTransform(rE.fXScale,rE.fHeight,1.0,rE.fRotAngle,rE.aP0), rTransform );
        aT.TransDir(DXFVector(0,1,0),aV);
        nHeight=static_cast<sal_uInt16>(aV.Abs()+0.5);
        fA=aT.CalcRotAngle();
        nAng=static_cast<short>(fA*10.0+0.5);
        aT.TransDir(DXFVector(1,0,0),aV);
        if ( SetFontAttribute( rE,nAng, nHeight ) )
        {
            OUString const aUString(pDXF->ToOUString(rE.m_sText));
            aT.Transform( DXFVector( 0, 0, 0 ), aPt );
            pVirDev->DrawText( aPt, aUString );
        }
    }

    void DXF2GDIMetaFile::DrawInsertEntity(const DXFInsertEntity & rE, const DXFTransform & rTransform)
    {
        const DXFBlock * pB;
        pB=pDXF->aBlocks.Search(rE.m_sName);
        if (pB!=nullptr) {
            DXFTransform aDXFTransform1(1.0,1.0,1.0,DXFVector(0.0,0.0,0.0)-pB->aBasePoint);
            DXFTransform aDXFTransform2(rE.fXScale,rE.fYScale,rE.fZScale,rE.fRotAngle,rE.aP0);
            DXFTransform aT(
                DXFTransform( aDXFTransform1, aDXFTransform2 ),
                rTransform
            );
            long nSavedBlockColor, nSavedParentLayerColor;
            DXFLineInfo aSavedBlockDXFLineInfo, aSavedParentLayerDXFLineInfo;
            nSavedBlockColor=nBlockColor;
            nSavedParentLayerColor=nParentLayerColor;
            aSavedBlockDXFLineInfo=aBlockDXFLineInfo;
            aSavedParentLayerDXFLineInfo=aParentLayerDXFLineInfo;
            nBlockColor=GetEntityColor(rE);
            aBlockDXFLineInfo=GetEntityDXFLineInfo(rE);
            if (rE.m_sLayer.getLength() > 1) {
                DXFLayer * pLayer=pDXF->aTables.SearchLayer(rE.m_sLayer);
                if (pLayer!=nullptr) {
                    nParentLayerColor=pLayer->nColor;
                    aParentLayerDXFLineInfo = LTypeToDXFLineInfo(pLayer->m_sLineType);
                }
            }
            DrawEntities(*pB,aT);
            aBlockDXFLineInfo=aSavedBlockDXFLineInfo;
            aParentLayerDXFLineInfo=aSavedParentLayerDXFLineInfo;
            nBlockColor=nSavedBlockColor;
            nParentLayerColor=nSavedParentLayerColor;
        }
    }

    void DXF2GDIMetaFile::DrawAttribEntity(const DXFAttribEntity & rE, const DXFTransform & rTransform)
    {
        if ((rE.nAttrFlags&1)==0) {
            DXFVector aV;
            Point aPt;
            double fA;
            sal_uInt16 nHeight;
            short nAng;
            DXFTransform aT( DXFTransform( rE.fXScale, rE.fHeight, 1.0, rE.fRotAngle, rE.aP0 ), rTransform );
            aT.TransDir(DXFVector(0,1,0),aV);
            nHeight=static_cast<sal_uInt16>(aV.Abs()+0.5);
            fA=aT.CalcRotAngle();
            nAng=static_cast<short>(fA*10.0+0.5);
            aT.TransDir(DXFVector(1,0,0),aV);
            if (SetFontAttribute(rE,nAng,nHeight))
            {
                OUString const aUString(pDXF->ToOUString(rE.m_sText));
                aT.Transform( DXFVector( 0, 0, 0 ), aPt );
                pVirDev->DrawText( aPt, aUString );
            }
        }
    }

    void DXF2GDIMetaFile::DrawPolyLineEntity(const DXFPolyLineEntity & rE, const DXFTransform & rTransform)
    {
        sal_uInt16 i,nPolySize;
        const DXFBasicEntity * pBE;

        nPolySize=0;
        pBE=rE.pSucc;
        while (pBE!=nullptr && pBE->eType==DXF_VERTEX) {
            nPolySize++;
            pBE=pBE->pSucc;
        }
        if (nPolySize<2) return;
        tools::Polygon aPoly(nPolySize);
        pBE=rE.pSucc;
        for (i=0; i<nPolySize; i++) {
            rTransform.Transform(static_cast<const DXFVertexEntity*>(pBE)->aP0,aPoly[i]);
            pBE=pBE->pSucc;
        }

        if (SetLineAttribute(rE)) {
            if ((rE.nFlags&1)!=0) pVirDev->DrawPolygon(aPoly);
            else pVirDev->DrawPolyLine(aPoly);
            if (rE.fThickness!=0) {
                tools::Polygon aPoly2(nPolySize);
                pBE=rE.pSucc;
                for (i=0; i<nPolySize; i++) {
                    rTransform.Transform(
                       (static_cast<const DXFVertexEntity*>(pBE)->aP0)+DXFVector(0,0,rE.fThickness),
                       aPoly2[i]
                    );
                    pBE=pBE->pSucc;
                }
                if ((rE.nFlags&1)!=0) pVirDev->DrawPolygon(aPoly2);
                else pVirDev->DrawPolyLine(aPoly2);
                for (i=0; i<nPolySize; i++) DrawLine(aPoly[i],aPoly2[i]);
            }
        }
    }

    void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const DXFTransform & rTransform )
    {
        sal_Int32 nPolySize = rE.aP.size();
        if (nPolySize)
        {
            tools::Polygon aPoly( static_cast<sal_uInt16>(nPolySize));
            for (sal_Int32 i = 0; i < nPolySize; ++i)
            {
                rTransform.Transform( rE.aP[ static_cast<sal_uInt16>(i) ], aPoly[ static_cast<sal_uInt16>(i) ] );
            }
            if ( SetLineAttribute( rE ) )
            {
                if ( ( rE.nFlags & 1 ) != 0 )
                    pVirDev->DrawPolygon( aPoly );
                else
                    pVirDev->DrawPolyLine( aPoly );
            }
        }
    }

    void DXF2GDIMetaFile::DrawHatchEntity(const DXFHatchEntity & rE, const DXFTransform & rTransform )
    {
        if ( rE.nBoundaryPathCount )
        {
            SetAreaAttribute( rE );
            sal_Int32 j = 0;
            tools::PolyPolygon aPolyPoly;
            for ( j = 0; j < rE.nBoundaryPathCount; j++ )
            {
                std::deque< Point > aPtAry;
                const DXFBoundaryPathData& rPathData = rE.pBoundaryPathData[ j ];
                if ( rPathData.bIsPolyLine )
                {
                    for (const auto& a : rPathData.aP)
                    {
                        Point aPt;
                        rTransform.Transform(a, aPt);
                        aPtAry.push_back( aPt );
                    }
                }
                else
                {
                    for ( std::deque<DXFEdgeType*>::size_type i = 0; i < rPathData.aEdges.size(); i++ )
                    {
                        const DXFEdgeType* pEdge = rPathData.aEdges[ i ].get();
                        switch( pEdge->nEdgeType )
                        {
                            case 1 :
                            {
                                Point aPt;
                                rTransform.Transform( static_cast<const DXFEdgeTypeLine*>(pEdge)->aStartPoint, aPt );
                                aPtAry.push_back( aPt );
                                rTransform.Transform( static_cast<const DXFEdgeTypeLine*>(pEdge)->aEndPoint, aPt );
                                aPtAry.push_back( aPt );
                            }
                            break;
                            case 2 :
                            case 3 :
                            case 4 :
                            break;
                        }
                    }
                }
                sal_uInt16 i, nSize = static_cast<sal_uInt16>(aPtAry.size());
                if ( nSize )
                {
                    tools::Polygon aPoly( nSize );
                    for ( i = 0; i < nSize; i++ )
                        aPoly[ i ] = aPtAry[ i ];
                    aPolyPoly.Insert( aPoly );
                }
            }
            if ( aPolyPoly.Count() )
                pVirDev->DrawPolyPolygon( aPolyPoly );
        }
    }

    void DXF2GDIMetaFile::Draw3DFaceEntity(const DXF3DFaceEntity & rE, const DXFTransform & rTransform)
    {
        sal_uInt16 nN,i;
        if (SetLineAttribute(rE)) {
            if (rE.aP2==rE.aP3) nN=3; else nN=4;
            tools::Polygon aPoly(nN);
            rTransform.Transform(rE.aP0,aPoly[0]);
            rTransform.Transform(rE.aP1,aPoly[1]);
            rTransform.Transform(rE.aP2,aPoly[2]);
            if (nN>3) rTransform.Transform(rE.aP3,aPoly[3]);
            if ((rE.nIEFlags&0x0f)==0) pVirDev->DrawPolygon(aPoly);
            else {
                for (i=0; i<nN; i++) {
                    if ( (rE.nIEFlags & (1<<i)) == 0 ) {
                        DrawLine(aPoly[i],aPoly[(i+1)%nN]);
                    }
                }
            }
        }
    }

    void DXF2GDIMetaFile::DrawDimensionEntity(const DXFDimensionEntity & rE, const DXFTransform & rTransform)
    {
        const DXFBlock * pB;
        pB=pDXF->aBlocks.Search(rE.m_sPseudoBlock);
        if (pB!=nullptr) {
            DXFTransform aT(
                DXFTransform(1.0,1.0,1.0,DXFVector(0.0,0.0,0.0)-pB->aBasePoint),
                rTransform
            );
            long nSavedBlockColor, nSavedParentLayerColor;
            DXFLineInfo aSavedBlockDXFLineInfo, aSavedParentLayerDXFLineInfo;
            nSavedBlockColor=nBlockColor;
            nSavedParentLayerColor=nParentLayerColor;
            aSavedBlockDXFLineInfo=aBlockDXFLineInfo;
            aSavedParentLayerDXFLineInfo=aParentLayerDXFLineInfo;
            nBlockColor=GetEntityColor(rE);
            aBlockDXFLineInfo=GetEntityDXFLineInfo(rE);
            if (rE.m_sLayer.getLength() > 1) {
                DXFLayer * pLayer=pDXF->aTables.SearchLayer(rE.m_sLayer);
                if (pLayer!=nullptr) {
                    nParentLayerColor=pLayer->nColor;
                    aParentLayerDXFLineInfo = LTypeToDXFLineInfo(pLayer->m_sLineType);
                }
            }
            DrawEntities(*pB,aT);
            aBlockDXFLineInfo=aSavedBlockDXFLineInfo;
            aParentLayerDXFLineInfo=aSavedParentLayerDXFLineInfo;
            nBlockColor=nSavedBlockColor;
            nParentLayerColor=nSavedParentLayerColor;
        }
    }

    void DXF2GDIMetaFile::DrawEntities(const DXFEntities & rEntities,
                                       const DXFTransform & rTransform)
    {
        if (rEntities.mbBeingDrawn)
            return;
        rEntities.mbBeingDrawn = true;

        sal_uLong nCount=0;
        DXFTransform aET;
        const DXFTransform * pT;

        const DXFBasicEntity * pE=rEntities.pFirst;

        while (pE!=nullptr && bStatus) {
            if (pE->nSpace==0) {
                if (pE->aExtrusion.fz==1.0) {
                    pT=&rTransform;
                }
                else {
                    aET=DXFTransform(DXFTransform(pE->aExtrusion),rTransform);
                    pT=&aET;
                }
                switch (pE->eType) {
                case DXF_LINE:
                    DrawLineEntity(static_cast<const DXFLineEntity&>(*pE),*pT);
                    break;
                case DXF_POINT:
                    DrawPointEntity(static_cast<const DXFPointEntity&>(*pE),*pT);
                    break;
                case DXF_CIRCLE:
                    DrawCircleEntity(static_cast<const DXFCircleEntity&>(*pE),*pT);
                    break;
                case DXF_ARC:
                    DrawArcEntity(static_cast<const DXFArcEntity&>(*pE),*pT);
                    break;
                case DXF_TRACE:
                    DrawTraceEntity(static_cast<const DXFTraceEntity&>(*pE),*pT);
                    break;
                case DXF_SOLID:
                    DrawSolidEntity(static_cast<const DXFSolidEntity&>(*pE),*pT);
                    break;
                case DXF_TEXT:
                    DrawTextEntity(static_cast<const DXFTextEntity&>(*pE),*pT);
                    break;
                case DXF_INSERT:
                    DrawInsertEntity(static_cast<const DXFInsertEntity&>(*pE),*pT);
                    break;
                case DXF_ATTRIB:
                    DrawAttribEntity(static_cast<const DXFAttribEntity&>(*pE),*pT);
                    break;
                case DXF_POLYLINE:
                    DrawPolyLineEntity(static_cast<const DXFPolyLineEntity&>(*pE),*pT);
                    break;
                case DXF_LWPOLYLINE :
                    DrawLWPolyLineEntity(static_cast<const DXFLWPolyLineEntity&>(*pE), *pT);
                    break;
                case DXF_HATCH :
                    DrawHatchEntity(static_cast<const DXFHatchEntity&>(*pE), *pT);
                    break;
                case DXF_3DFACE:
                    Draw3DFaceEntity(static_cast<const DXF3DFaceEntity&>(*pE),*pT);
                    break;
                case DXF_DIMENSION:
                    DrawDimensionEntity(static_cast<const DXFDimensionEntity&>(*pE),*pT);
                    break;
                default:
                    break;  // four other values not handled -Wall
                }
            }
            pE=pE->pSucc;
            nCount++;
        }

        rEntities.mbBeingDrawn = false;
    }

    DXF2GDIMetaFile::DXF2GDIMetaFile()
        : pVirDev(nullptr)
        , pDXF(nullptr)
        , bStatus(false)
        , OptPointsPerCircle(0)
        , nMinPercent(0)
        , nMaxPercent(0)
        , nLastPercent(0)
        , nMainEntitiesCount(0)
        , nBlockColor(0)
        , nParentLayerColor(0)
    {
    }

    DXF2GDIMetaFile::~DXF2GDIMetaFile()
    {
    }

    bool DXF2GDIMetaFile::Convert(const DXFRepresentation & rDXF, GDIMetaFile & rMTF, sal_uInt16 nminpercent, sal_uInt16 nmaxpercent)
    {
        double fWidth,fHeight,fScale(0.0);
        DXFTransform aTransform;
        Size aPrefSize;
        const DXFLayer * pLayer;
        const DXFVPort * pVPort;

        pVirDev = VclPtr<VirtualDevice>::Create();
        pDXF    = &rDXF;
        bStatus = true;

        OptPointsPerCircle=50;

        nMinPercent=static_cast<sal_uLong>(nminpercent);
        nMaxPercent=static_cast<sal_uLong>(nmaxpercent);
        nLastPercent=nMinPercent;
        nMainEntitiesCount=CountEntities(pDXF->aEntities);

        nBlockColor=7;
        aBlockDXFLineInfo.eStyle = LineStyle::Solid;
        aBlockDXFLineInfo.fWidth = 0;
        aBlockDXFLineInfo.nDashCount = 0;
        aBlockDXFLineInfo.fDashLen = 0;
        aBlockDXFLineInfo.nDotCount = 0;
        aBlockDXFLineInfo.fDotLen = 0;
        aBlockDXFLineInfo.fDistance = 0;

        pLayer=pDXF->aTables.SearchLayer("0");
        if (pLayer!=nullptr) {
            nParentLayerColor=pLayer->nColor & 0xff;
            aParentLayerDXFLineInfo = LTypeToDXFLineInfo(pLayer->m_sLineType);
        }
        else {
            nParentLayerColor=7;
            aParentLayerDXFLineInfo.eStyle = LineStyle::Solid;
            aParentLayerDXFLineInfo.fWidth = 0;
            aParentLayerDXFLineInfo.nDashCount = 0;
            aParentLayerDXFLineInfo.fDashLen = 0;
            aParentLayerDXFLineInfo.nDotCount = 0;
            aParentLayerDXFLineInfo.fDotLen = 0;
            aParentLayerDXFLineInfo.fDistance = 0;
        }

        pVirDev->EnableOutput(false);
        rMTF.Record(pVirDev);

        aActLineColor = pVirDev->GetLineColor();
        aActFillColor = pVirDev->GetFillColor();
        aActFont = pVirDev->GetFont();

        pVPort=pDXF->aTables.SearchVPort("*ACTIVE");
        if (pVPort!=nullptr) {
            if (pVPort->aDirection.fx==0 && pVPort->aDirection.fy==0)
                pVPort=nullptr;
        }

        if (pVPort==nullptr) {
            if (pDXF->aBoundingBox.bEmpty)
                bStatus=false;
            else {
                fWidth=pDXF->aBoundingBox.fMaxX-pDXF->aBoundingBox.fMinX;
                fHeight=pDXF->aBoundingBox.fMaxY-pDXF->aBoundingBox.fMinY;
                if (fWidth<=0 || fHeight<=0) {
                    bStatus=false;
                }
                else {
                    if (fWidth>fHeight)
                        fScale=10000.0/fWidth;
                    else
                        fScale=10000.0/fHeight;
                    aTransform=DXFTransform(fScale,-fScale,fScale,
                                            DXFVector(-pDXF->aBoundingBox.fMinX*fScale,
                                                       pDXF->aBoundingBox.fMaxY*fScale,
                                                      -pDXF->aBoundingBox.fMinZ*fScale));
                }
                aPrefSize.setWidth(static_cast<long>(fWidth*fScale+1.5) );
                aPrefSize.setHeight(static_cast<long>(fHeight*fScale+1.5) );
            }
        }
        else {
            fHeight=pVPort->fHeight;
            fWidth=fHeight*pVPort->fAspectRatio;
            if (fWidth<=0 || fHeight<=0) {
                bStatus=false;
            } else {
                if (fWidth>fHeight)
                    fScale=10000.0/fWidth;
                else
                    fScale=10000.0/fHeight;
                aTransform=DXFTransform(
                    DXFTransform(pVPort->aDirection,pVPort->aTarget),
                    DXFTransform(
                        DXFTransform(1.0,-1.0,1.0,DXFVector(fWidth/2-pVPort->fCenterX,fHeight/2+pVPort->fCenterY,0)),
                        DXFTransform(fScale,fScale,fScale,DXFVector(0,0,0))
                    )
                );
            }
            aPrefSize.setWidth(static_cast<long>(fWidth*fScale+1.5) );
            aPrefSize.setHeight(static_cast<long>(fHeight*fScale+1.5) );
        }

        if (bStatus)
            DrawEntities(pDXF->aEntities,aTransform);

        rMTF.Stop();

        if ( bStatus )
        {
            rMTF.SetPrefSize( aPrefSize );
            // simply set map mode to 1/100-mm (1/10-mm) if the graphic
            // does not get not too small (<0.5cm)
            if( ( aPrefSize.Width() < 500 ) && ( aPrefSize.Height() < 500 ) )
                rMTF.SetPrefMapMode( MapMode( MapUnit::Map10thMM ) );
            else
                rMTF.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
        }

        pVirDev.disposeAndClear();
        return bStatus;
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.