<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <vcl/rendergraphicrasterizer.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>
#include <vcl/unohelp.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/graph.hxx>
#include <tools/stream.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamwrap.hxx>

#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#define VCL_SERVICENAME_RASTERIZER_SVG  "com.sun.star.graphic.GraphicRasterizer_RSVG"

using namespace com::sun::star;

namespace vcl
{
// ---------------------------------------------------------
// - maximum extent in pixel for graphics to be rasterized -
// ---------------------------------------------------------

static const sal_uInt32 nRasterizerDefaultExtent = 4096;

// ---------------------------
// - RenderGraphicRasterizer -
// ---------------------------

RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphic& rRenderGraphic ) :
    maRenderGraphic( rRenderGraphic ),
    mfRotateAngle( 0.0 ),
    mfShearAngleX( 0.0 ),
    mfShearAngleY( 0.0 )
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphicRasterizer& rRenderGraphicRasterizer ) :
    maRenderGraphic( rRenderGraphicRasterizer.maRenderGraphic ),
    mxRasterizer( rRenderGraphicRasterizer.mxRasterizer ),
    maBitmapEx( rRenderGraphicRasterizer.maBitmapEx ),
    maDefaultSizePixel( rRenderGraphicRasterizer.maDefaultSizePixel ),
    mfRotateAngle( rRenderGraphicRasterizer.mfRotateAngle ),
    mfShearAngleX( rRenderGraphicRasterizer.mfShearAngleX ),
    mfShearAngleY( rRenderGraphicRasterizer.mfShearAngleY )
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer::~RenderGraphicRasterizer()
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer::RenderGraphicRasterizer& RenderGraphicRasterizer::operator=(
    const RenderGraphicRasterizer& rRenderGraphicRasterizer )
{
    maRenderGraphic = rRenderGraphicRasterizer.maRenderGraphic;
    maBitmapEx = rRenderGraphicRasterizer.maBitmapEx;
    maDefaultSizePixel = rRenderGraphicRasterizer.maDefaultSizePixel;
    mfRotateAngle = rRenderGraphicRasterizer.mfRotateAngle;
    mfShearAngleX = rRenderGraphicRasterizer.mfShearAngleX;
    mfShearAngleY = rRenderGraphicRasterizer.mfShearAngleY;
    mxRasterizer = rRenderGraphicRasterizer.mxRasterizer;

    return( *this );
}

// -------------------------------------------------------------------------

const Size& RenderGraphicRasterizer::GetDefaultSizePixel() const
{
    const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();

    return( maDefaultSizePixel );
}

// -------------------------------------------------------------------------

BitmapEx RenderGraphicRasterizer::GetReplacement() const
{
    BitmapEx aRet( Rasterize( GetDefaultSizePixel() ) );

    aRet.SetPrefSize( GetPrefSize() );
    aRet.SetPrefMapMode( GetPrefMapMode() );

    return( aRet );
}

// -------------------------------------------------------------------------

Size RenderGraphicRasterizer::GetPrefSize() const
{
    const Size                      aSizePixel( GetDefaultSizePixel() );
    std::auto_ptr< VirtualDevice >  apCompVDev;
    OutputDevice*                   pCompDev = NULL;

#ifndef NO_GETAPPWINDOW
    pCompDev = Application::GetAppWindow();
#endif

    if( !pCompDev )
    {
        apCompVDev.reset( new VirtualDevice );
        pCompDev = apCompVDev.get();
    }

    return( pCompDev->PixelToLogic( aSizePixel, GetPrefMapMode() ) );
}

// -------------------------------------------------------------------------

MapMode RenderGraphicRasterizer::GetPrefMapMode() const
{
    return( MapMode( MAP_100TH_MM ) );
}

// -------------------------------------------------------------------------

const BitmapEx& RenderGraphicRasterizer::Rasterize( const Size& rSizePixel,
                                                    double fRotateAngle,
                                                    double fShearAngleX,
                                                    double fShearAngleY,
                                                    sal_uInt32 nMaxExtent ) const
{
    const bool bRasterize = !maRenderGraphic.IsEmpty() &&
                            rSizePixel.Width() && rSizePixel.Height() &&
                            ( maBitmapEx.IsEmpty() ||
                              ( rSizePixel != maBitmapEx.GetSizePixel() ) ||
                              ( fRotateAngle != mfRotateAngle ) ||
                              ( fShearAngleX != mfShearAngleX ) ||
                              ( fShearAngleY != mfShearAngleY ) );

    if( bRasterize )
    {
        const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();

        if( mxRasterizer.is() )
        {
            sal_uInt32 nWidth = labs( rSizePixel.Width() );
            sal_uInt32 nHeight = labs( rSizePixel.Height() );

            // limiting the extent of the rastered bitmap
            if( VCL_RASTERIZER_UNLIMITED_EXTENT != nMaxExtent )
            {
                if( VCL_RASTERIZER_DEFAULT_EXTENT == nMaxExtent )
                {
                    nMaxExtent = nRasterizerDefaultExtent;
                }

                if( ( nWidth > nMaxExtent ) || ( nHeight > nMaxExtent ) )
                {
                    const double fScale = static_cast< double >( nMaxExtent ) / ::std::max( nWidth, nHeight );

                    nWidth = FRound( nWidth * fScale );
                    nHeight = FRound( nHeight * fScale );
                }
            }

            if( !ImplRasterizeFromCache( const_cast< RenderGraphicRasterizer& >( *this ),
                                         Size( nWidth, nHeight ), fRotateAngle, fShearAngleX, fShearAngleY ) )
            {
                try
                {
                    const uno::Sequence< beans::PropertyValue > aPropertySeq;
                    const Graphic aRasteredGraphic( mxRasterizer->rasterize( nWidth,
                                                                             nHeight,
                                                                             fRotateAngle,
                                                                             fShearAngleX,
                                                                             fShearAngleY,
                                                                             aPropertySeq ) );

                    maBitmapEx = aRasteredGraphic.GetBitmapEx();
                    mfRotateAngle = fRotateAngle;
                    mfShearAngleX = fShearAngleX;
                    mfShearAngleY = fShearAngleY;

                    ImplUpdateCache( *this );

//                    OSL_TRACE( "Wanted: %d x %d / Got: %d x %d", rSizePixel.Width(), rSizePixel.Height(), maBitmapEx.GetSizePixel().Width(), maBitmapEx.GetSizePixel().Height() );
                }
                catch( ... )
                {
                    OSL_TRACE( "caught exception during rasterization" );
                }
            }
        }
    }

    return( maBitmapEx );
}

// -------------------------------------------------------------------------

void RenderGraphicRasterizer::InitializeRasterizer()
{
    if( !mxRasterizer.is() && !ImplInitializeFromCache( *this ) )
    {
        uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );

        maDefaultSizePixel.Width() = maDefaultSizePixel.Height() = 0;

        if( !maRenderGraphic.IsEmpty() )
        {
            rtl::OUString aServiceName;

            if( 0 == maRenderGraphic.GetGraphicDataMimeType().compareToAscii( "image/svg+xml" ) )
            {
                aServiceName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( VCL_SERVICENAME_RASTERIZER_SVG ) );
            }

            if( aServiceName.getLength() )
            {
                mxRasterizer.set( xFactory->createInstance( aServiceName ), uno::UNO_QUERY );

                if( mxRasterizer.is() )
                {
                    std::auto_ptr< VirtualDevice > apCompVDev;
                    OutputDevice* pCompDev = NULL;

#ifndef NO_GETAPPWINDOW
                    pCompDev = Application::GetAppWindow();
#endif

                    if( !pCompDev )
                    {
                        apCompVDev.reset( new VirtualDevice );
                        pCompDev = apCompVDev.get();
                    }

                    const Size      aDPI( pCompDev->LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
                    awt::Size       aSizePixel;
                    SvMemoryStream  aMemStm( maRenderGraphic.GetGraphicData().get(),
                                             maRenderGraphic.GetGraphicDataLength(),
                                             STREAM_READ );

                    uno::Reference< io::XInputStream > xIStm( new utl::OSeekableInputStreamWrapper( aMemStm ) );

                    try
                    {
                        if( !xIStm.is() || !mxRasterizer->initializeData( xIStm, aDPI.Width(), aDPI.Height(), aSizePixel ) )
                        {
                            mxRasterizer.clear();
                        }
                        else
                        {
                            maDefaultSizePixel.Width() = aSizePixel.Width;
                            maDefaultSizePixel.Height() = aSizePixel.Height;
                        }
                    }
                    catch( ... )
                    {
                        OSL_TRACE( "caught exception during initialization of SVG rasterizer component" );
                        mxRasterizer.clear();
                    }
                }
            }
        }
    }
}

// ------------------------------------------------------------------------------

RenderGraphicRasterizer::RenderGraphicRasterizerCache& RenderGraphicRasterizer::ImplGetCache()
{
    static RenderGraphicRasterizerCache* pCache = NULL;

    if( !pCache )
    {
        pCache = new RenderGraphicRasterizerCache;
    }

    return( *pCache );
}

// ------------------------------------------------------------------------------

bool RenderGraphicRasterizer::ImplInitializeFromCache( RenderGraphicRasterizer& rRasterizer )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    bool                            bRet = false;

    for( sal_uInt32 i = 0; i < rCache.size(); ++i )
    {
        const RenderGraphicRasterizer* pCheck = &rCache[ i ];

        if( pCheck && pCheck->mxRasterizer.is() && ( pCheck->maRenderGraphic == rRasterizer.maRenderGraphic ) )
        {
//            OSL_TRACE( "Hit RenderGraphicRasterizer cache for initialization" );

            rRasterizer.mxRasterizer = pCheck->mxRasterizer;
            rRasterizer.maDefaultSizePixel = pCheck->maDefaultSizePixel;

            // put found Rasterizer at begin of deque
            const RenderGraphicRasterizer aFound( rCache[ i ] );

            rCache.erase( rCache.begin() + i );
            rCache.push_front( aFound );

            bRet = true;
        }
    }

    return( bRet );
}

// ------------------------------------------------------------------------------

bool RenderGraphicRasterizer::ImplRasterizeFromCache( RenderGraphicRasterizer& rRasterizer,
                                                      const Size& rSizePixel,
                                                      double fRotateAngle,
                                                      double fShearAngleX,
                                                      double fShearAngleY )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    bool                            bRet = false;

    for( sal_uInt32 i = 0; i < rCache.size(); ++i )
    {
        const RenderGraphicRasterizer& rCheck = rCache[ i ];

        if( rCheck.mxRasterizer.is() && rRasterizer.mxRasterizer.is() &&
            ( ( rCheck.mxRasterizer == rRasterizer.mxRasterizer ) ||
              ( rRasterizer.maRenderGraphic == rCheck.maRenderGraphic ) ) &&
            ( rCheck.maBitmapEx.GetSizePixel() == rSizePixel ) &&
            ( rCheck.mfRotateAngle == fRotateAngle ) &&
            ( rCheck.mfShearAngleX == fShearAngleX ) &&
            ( rCheck.mfShearAngleY == fShearAngleY ) )
        {
//            OSL_TRACE( "Hit RenderGraphicRasterizer cache for rasterizing" );

            rRasterizer.maBitmapEx = rCheck.maBitmapEx;
            rRasterizer.mfRotateAngle = fRotateAngle;
            rRasterizer.mfShearAngleX = fShearAngleX;
            rRasterizer.mfShearAngleY = fShearAngleY;

            // put found Rasterizer at begin of deque
            const RenderGraphicRasterizer aFound( rCache[ i ] );

            rCache.erase( rCache.begin() + i );
            rCache.push_front( aFound );

            bRet = true;
        }
    }

    return( bRet );
}

// ------------------------------------------------------------------------------

void RenderGraphicRasterizer::ImplUpdateCache( const RenderGraphicRasterizer& rRasterizer )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    const sal_uInt32                nMaxCacheSize = 8;

    if( rCache.size() < nMaxCacheSize )
    {
        rCache.push_front( rRasterizer );
    }
    else
    {
        rCache.pop_back();
        rCache.push_front( rRasterizer );
    }
}

} // VCL
<commit_msg>ka102: syntax<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <vcl/rendergraphicrasterizer.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>
#include <vcl/unohelp.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/graph.hxx>
#include <tools/stream.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/streamwrap.hxx>

#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#define VCL_SERVICENAME_RASTERIZER_SVG  "com.sun.star.graphic.GraphicRasterizer_RSVG"

using namespace com::sun::star;

namespace vcl
{
// ---------------------------------------------------------
// - maximum extent in pixel for graphics to be rasterized -
// ---------------------------------------------------------

static const sal_uInt32 nRasterizerDefaultExtent = 4096;

// ---------------------------
// - RenderGraphicRasterizer -
// ---------------------------

RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphic& rRenderGraphic ) :
    maRenderGraphic( rRenderGraphic ),
    mfRotateAngle( 0.0 ),
    mfShearAngleX( 0.0 ),
    mfShearAngleY( 0.0 )
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphicRasterizer& rRenderGraphicRasterizer ) :
    maRenderGraphic( rRenderGraphicRasterizer.maRenderGraphic ),
    mxRasterizer( rRenderGraphicRasterizer.mxRasterizer ),
    maBitmapEx( rRenderGraphicRasterizer.maBitmapEx ),
    maDefaultSizePixel( rRenderGraphicRasterizer.maDefaultSizePixel ),
    mfRotateAngle( rRenderGraphicRasterizer.mfRotateAngle ),
    mfShearAngleX( rRenderGraphicRasterizer.mfShearAngleX ),
    mfShearAngleY( rRenderGraphicRasterizer.mfShearAngleY )
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer::~RenderGraphicRasterizer()
{
}

// -------------------------------------------------------------------------

RenderGraphicRasterizer& RenderGraphicRasterizer::operator=(
    const RenderGraphicRasterizer& rRenderGraphicRasterizer )
{
    maRenderGraphic = rRenderGraphicRasterizer.maRenderGraphic;
    maBitmapEx = rRenderGraphicRasterizer.maBitmapEx;
    maDefaultSizePixel = rRenderGraphicRasterizer.maDefaultSizePixel;
    mfRotateAngle = rRenderGraphicRasterizer.mfRotateAngle;
    mfShearAngleX = rRenderGraphicRasterizer.mfShearAngleX;
    mfShearAngleY = rRenderGraphicRasterizer.mfShearAngleY;
    mxRasterizer = rRenderGraphicRasterizer.mxRasterizer;

    return( *this );
}

// -------------------------------------------------------------------------

const Size& RenderGraphicRasterizer::GetDefaultSizePixel() const
{
    const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();

    return( maDefaultSizePixel );
}

// -------------------------------------------------------------------------

BitmapEx RenderGraphicRasterizer::GetReplacement() const
{
    BitmapEx aRet( Rasterize( GetDefaultSizePixel() ) );

    aRet.SetPrefSize( GetPrefSize() );
    aRet.SetPrefMapMode( GetPrefMapMode() );

    return( aRet );
}

// -------------------------------------------------------------------------

Size RenderGraphicRasterizer::GetPrefSize() const
{
    const Size                      aSizePixel( GetDefaultSizePixel() );
    std::auto_ptr< VirtualDevice >  apCompVDev;
    OutputDevice*                   pCompDev = NULL;

#ifndef NO_GETAPPWINDOW
    pCompDev = Application::GetAppWindow();
#endif

    if( !pCompDev )
    {
        apCompVDev.reset( new VirtualDevice );
        pCompDev = apCompVDev.get();
    }

    return( pCompDev->PixelToLogic( aSizePixel, GetPrefMapMode() ) );
}

// -------------------------------------------------------------------------

MapMode RenderGraphicRasterizer::GetPrefMapMode() const
{
    return( MapMode( MAP_100TH_MM ) );
}

// -------------------------------------------------------------------------

const BitmapEx& RenderGraphicRasterizer::Rasterize( const Size& rSizePixel,
                                                    double fRotateAngle,
                                                    double fShearAngleX,
                                                    double fShearAngleY,
                                                    sal_uInt32 nMaxExtent ) const
{
    const bool bRasterize = !maRenderGraphic.IsEmpty() &&
                            rSizePixel.Width() && rSizePixel.Height() &&
                            ( maBitmapEx.IsEmpty() ||
                              ( rSizePixel != maBitmapEx.GetSizePixel() ) ||
                              ( fRotateAngle != mfRotateAngle ) ||
                              ( fShearAngleX != mfShearAngleX ) ||
                              ( fShearAngleY != mfShearAngleY ) );

    if( bRasterize )
    {
        const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();

        if( mxRasterizer.is() )
        {
            sal_uInt32 nWidth = labs( rSizePixel.Width() );
            sal_uInt32 nHeight = labs( rSizePixel.Height() );

            // limiting the extent of the rastered bitmap
            if( VCL_RASTERIZER_UNLIMITED_EXTENT != nMaxExtent )
            {
                if( VCL_RASTERIZER_DEFAULT_EXTENT == nMaxExtent )
                {
                    nMaxExtent = nRasterizerDefaultExtent;
                }

                if( ( nWidth > nMaxExtent ) || ( nHeight > nMaxExtent ) )
                {
                    const double fScale = static_cast< double >( nMaxExtent ) / ::std::max( nWidth, nHeight );

                    nWidth = FRound( nWidth * fScale );
                    nHeight = FRound( nHeight * fScale );
                }
            }

            if( !ImplRasterizeFromCache( const_cast< RenderGraphicRasterizer& >( *this ),
                                         Size( nWidth, nHeight ), fRotateAngle, fShearAngleX, fShearAngleY ) )
            {
                try
                {
                    const uno::Sequence< beans::PropertyValue > aPropertySeq;
                    const Graphic aRasteredGraphic( mxRasterizer->rasterize( nWidth,
                                                                             nHeight,
                                                                             fRotateAngle,
                                                                             fShearAngleX,
                                                                             fShearAngleY,
                                                                             aPropertySeq ) );

                    maBitmapEx = aRasteredGraphic.GetBitmapEx();
                    mfRotateAngle = fRotateAngle;
                    mfShearAngleX = fShearAngleX;
                    mfShearAngleY = fShearAngleY;

                    ImplUpdateCache( *this );

//                    OSL_TRACE( "Wanted: %d x %d / Got: %d x %d", rSizePixel.Width(), rSizePixel.Height(), maBitmapEx.GetSizePixel().Width(), maBitmapEx.GetSizePixel().Height() );
                }
                catch( ... )
                {
                    OSL_TRACE( "caught exception during rasterization" );
                }
            }
        }
    }

    return( maBitmapEx );
}

// -------------------------------------------------------------------------

void RenderGraphicRasterizer::InitializeRasterizer()
{
    if( !mxRasterizer.is() && !ImplInitializeFromCache( *this ) )
    {
        uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );

        maDefaultSizePixel.Width() = maDefaultSizePixel.Height() = 0;

        if( !maRenderGraphic.IsEmpty() )
        {
            rtl::OUString aServiceName;

            if( 0 == maRenderGraphic.GetGraphicDataMimeType().compareToAscii( "image/svg+xml" ) )
            {
                aServiceName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( VCL_SERVICENAME_RASTERIZER_SVG ) );
            }

            if( aServiceName.getLength() )
            {
                mxRasterizer.set( xFactory->createInstance( aServiceName ), uno::UNO_QUERY );

                if( mxRasterizer.is() )
                {
                    std::auto_ptr< VirtualDevice > apCompVDev;
                    OutputDevice* pCompDev = NULL;

#ifndef NO_GETAPPWINDOW
                    pCompDev = Application::GetAppWindow();
#endif

                    if( !pCompDev )
                    {
                        apCompVDev.reset( new VirtualDevice );
                        pCompDev = apCompVDev.get();
                    }

                    const Size      aDPI( pCompDev->LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
                    awt::Size       aSizePixel;
                    SvMemoryStream  aMemStm( maRenderGraphic.GetGraphicData().get(),
                                             maRenderGraphic.GetGraphicDataLength(),
                                             STREAM_READ );

                    uno::Reference< io::XInputStream > xIStm( new utl::OSeekableInputStreamWrapper( aMemStm ) );

                    try
                    {
                        if( !xIStm.is() || !mxRasterizer->initializeData( xIStm, aDPI.Width(), aDPI.Height(), aSizePixel ) )
                        {
                            mxRasterizer.clear();
                        }
                        else
                        {
                            maDefaultSizePixel.Width() = aSizePixel.Width;
                            maDefaultSizePixel.Height() = aSizePixel.Height;
                        }
                    }
                    catch( ... )
                    {
                        OSL_TRACE( "caught exception during initialization of SVG rasterizer component" );
                        mxRasterizer.clear();
                    }
                }
            }
        }
    }
}

// ------------------------------------------------------------------------------

RenderGraphicRasterizer::RenderGraphicRasterizerCache& RenderGraphicRasterizer::ImplGetCache()
{
    static RenderGraphicRasterizerCache* pCache = NULL;

    if( !pCache )
    {
        pCache = new RenderGraphicRasterizerCache;
    }

    return( *pCache );
}

// ------------------------------------------------------------------------------

bool RenderGraphicRasterizer::ImplInitializeFromCache( RenderGraphicRasterizer& rRasterizer )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    bool                            bRet = false;

    for( sal_uInt32 i = 0; i < rCache.size(); ++i )
    {
        const RenderGraphicRasterizer* pCheck = &rCache[ i ];

        if( pCheck && pCheck->mxRasterizer.is() && ( pCheck->maRenderGraphic == rRasterizer.maRenderGraphic ) )
        {
//            OSL_TRACE( "Hit RenderGraphicRasterizer cache for initialization" );

            rRasterizer.mxRasterizer = pCheck->mxRasterizer;
            rRasterizer.maDefaultSizePixel = pCheck->maDefaultSizePixel;

            // put found Rasterizer at begin of deque
            const RenderGraphicRasterizer aFound( rCache[ i ] );

            rCache.erase( rCache.begin() + i );
            rCache.push_front( aFound );

            bRet = true;
        }
    }

    return( bRet );
}

// ------------------------------------------------------------------------------

bool RenderGraphicRasterizer::ImplRasterizeFromCache( RenderGraphicRasterizer& rRasterizer,
                                                      const Size& rSizePixel,
                                                      double fRotateAngle,
                                                      double fShearAngleX,
                                                      double fShearAngleY )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    bool                            bRet = false;

    for( sal_uInt32 i = 0; i < rCache.size(); ++i )
    {
        const RenderGraphicRasterizer& rCheck = rCache[ i ];

        if( rCheck.mxRasterizer.is() && rRasterizer.mxRasterizer.is() &&
            ( ( rCheck.mxRasterizer == rRasterizer.mxRasterizer ) ||
              ( rRasterizer.maRenderGraphic == rCheck.maRenderGraphic ) ) &&
            ( rCheck.maBitmapEx.GetSizePixel() == rSizePixel ) &&
            ( rCheck.mfRotateAngle == fRotateAngle ) &&
            ( rCheck.mfShearAngleX == fShearAngleX ) &&
            ( rCheck.mfShearAngleY == fShearAngleY ) )
        {
//            OSL_TRACE( "Hit RenderGraphicRasterizer cache for rasterizing" );

            rRasterizer.maBitmapEx = rCheck.maBitmapEx;
            rRasterizer.mfRotateAngle = fRotateAngle;
            rRasterizer.mfShearAngleX = fShearAngleX;
            rRasterizer.mfShearAngleY = fShearAngleY;

            // put found Rasterizer at begin of deque
            const RenderGraphicRasterizer aFound( rCache[ i ] );

            rCache.erase( rCache.begin() + i );
            rCache.push_front( aFound );

            bRet = true;
        }
    }

    return( bRet );
}

// ------------------------------------------------------------------------------

void RenderGraphicRasterizer::ImplUpdateCache( const RenderGraphicRasterizer& rRasterizer )
{
    RenderGraphicRasterizerCache&   rCache = ImplGetCache();
    const sal_uInt32                nMaxCacheSize = 8;

    if( rCache.size() < nMaxCacheSize )
    {
        rCache.push_front( rRasterizer );
    }
    else
    {
        rCache.pop_back();
        rCache.push_front( rRasterizer );
    }
}

} // VCL
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "RoutingManager.h"

#include "AlternativeRoutesModel.h"
#include "MarbleWidget.h"
#include "MarbleModel.h"
#include "RouteRequest.h"
#include "RoutingModel.h"
#include "RoutingProfilesModel.h"
#include "MarbleRunnerManager.h"
#include "AdjustNavigation.h"
#include "GeoWriter.h"
#include "GeoDataDocument.h"
#include "GeoDataParser.h"
#include "GeoDataFolder.h"
#include "MarbleDirs.h"
#include "MarbleDebug.h"
#include "PositionTracking.h"
#include "PluginManager.h"
#include "PositionProviderPlugin.h"

#include <QtCore/QFile>
#include <QtGui/QMessageBox>
#include <QtGui/QCheckBox>
#include <QMutexLocker>

namespace Marble
{

class RoutingManagerPrivate
{
public:
    RoutingManager* q;

    RouteRequest *m_routeRequest;

    RoutingModel *m_routingModel;

    RoutingProfilesModel *m_profilesModel;

    MarbleModel *m_marbleModel;

    AlternativeRoutesModel* m_alternativeRoutesModel;

    bool m_workOffline;

    MarbleRunnerManager* m_runnerManager;

    bool m_haveRoute;

    AdjustNavigation *m_adjustNavigation;

    bool m_guidanceModeEnabled;

    QMutex m_fileMutex;

    bool m_shutdownPositionTracking;

    bool m_guidanceModeWarning;

    RoutingManagerPrivate( MarbleModel *marbleModel, RoutingManager* manager, QObject *parent );

    GeoDataFolder* routeRequest() const;

    QString stateFile( const QString &name = QString( "route.kml" ) ) const;

    void saveRoute( const QString &filename );

    void loadRoute( const QString &filename );
};

RoutingManagerPrivate::RoutingManagerPrivate( MarbleModel *model, RoutingManager* manager, QObject *parent ) :
        q( manager ),
        m_routeRequest( new RouteRequest( manager ) ),
        m_routingModel( new RoutingModel( m_routeRequest, model ) ),
        m_profilesModel( new RoutingProfilesModel( model->pluginManager() ) ),
        m_marbleModel( model ),
        m_alternativeRoutesModel(new AlternativeRoutesModel( model, parent ) ),
        m_workOffline( false ),
        m_runnerManager( new MarbleRunnerManager( model->pluginManager(), q ) ),
        m_haveRoute( false ), m_adjustNavigation( 0 ),
        m_guidanceModeEnabled( false ),
        m_shutdownPositionTracking( false ),
        m_guidanceModeWarning( true )
{
    // nothing to do
}

GeoDataFolder* RoutingManagerPrivate::routeRequest() const
{
    GeoDataFolder* result = new GeoDataFolder;
    result->setName( "Route Request" );
    for ( int i=0; i<m_routeRequest->size(); ++i ) {
        GeoDataPlacemark* placemark = new GeoDataPlacemark;
        placemark->setName( m_routeRequest->name( i ) );
        placemark->setCoordinate( GeoDataPoint( m_routeRequest->at( i ) ) );
        result->append( placemark );
    }

    return result;
}

QString RoutingManagerPrivate::stateFile( const QString &name) const
{
    QString const subdir = "routing";
    QDir dir( MarbleDirs::localPath() );
    if ( !dir.exists( subdir ) ) {
        if ( !dir.mkdir( subdir ) ) {
            mDebug() << "Unable to create dir " << dir.absoluteFilePath( subdir );
            return dir.absolutePath();
        }
    }

    if ( !dir.cd( subdir ) ) {
        mDebug() << "Cannot change into " << dir.absoluteFilePath( subdir );
    }

    return dir.absoluteFilePath( name );
}

void RoutingManagerPrivate::saveRoute(const QString &filename)
{
    GeoWriter writer;
    writer.setDocumentType( "http://earth.google.com/kml/2.2" );

    QMutexLocker locker( &m_fileMutex );
    QFile file( filename );
    if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
    {
        mDebug() << "Cannot write to " << file.fileName();
        return;
    }

    GeoDataDocument container;
    GeoDataFolder* request = routeRequest();
    if ( request ) {
        container.append( request );
    }

    GeoDataDocument *route = m_alternativeRoutesModel->currentRoute();
    if ( route ) {
        container.append( new GeoDataDocument( *route ) );
    }

    if ( !writer.write( &file, &container ) ) {
        mDebug() << "Can not write route state to " << file.fileName();
    }
    file.close();
}

void RoutingManagerPrivate::loadRoute(const QString &filename)
{
    QFile file( filename );
    if ( !file.open( QIODevice::ReadOnly ) ) {
        mDebug() << "Can not read route from " << file.fileName();
        return;
    }

    GeoDataParser parser( GeoData_KML );
    if ( !parser.read( &file ) ) {
        mDebug() << "Could not parse file: " << parser.errorString();
        return;
    }

    GeoDocument *doc = parser.releaseDocument();
    GeoDataDocument* container = dynamic_cast<GeoDataDocument*>( doc );
    if ( container && container->size() == 2 ) {
        GeoDataFolder* viaPoints = dynamic_cast<GeoDataFolder*>( &container->first() );
        if ( viaPoints ) {
            QVector<GeoDataPlacemark*> placemarks = viaPoints->placemarkList();
            for( int i=0; i<placemarks.size(); ++i ) {
                if ( i < m_routeRequest->size() ) {
                    m_routeRequest->setPosition( i, placemarks[i]->coordinate() );
                } else {
                    m_routeRequest->append( placemarks[i]->coordinate() );
                }
                m_routeRequest->setName( m_routeRequest->size()-1, placemarks[i]->name() );
            }

            for ( int i=placemarks.size(); i<m_routeRequest->size(); ++i ) {
                m_routeRequest->remove( i );
            }
        } else {
            mDebug() << "Expected a GeoDataDocument with two children, didn't get one though";
        }

        GeoDataDocument* route = dynamic_cast<GeoDataDocument*>(&container->last());
        if ( route ) {
            m_alternativeRoutesModel->addRoute( route, AlternativeRoutesModel::Instant );
            m_alternativeRoutesModel->setCurrentRoute( 0 );
        } else {
            mDebug() << "Expected a GeoDataDocument child, didn't get one though";
            delete doc;
            doc = 0;
        }
    } else {
        mDebug() << "Expected a GeoDataDocument, didn't get one though";
        delete doc;
        doc = 0;
    }

    file.close();
    if ( !doc ) {
        m_marbleModel->addGeoDataFile( filename );
    }
}

RoutingManager::RoutingManager( MarbleModel *marbleModel, QObject *parent ) : QObject( parent ),
        d( new RoutingManagerPrivate( marbleModel, this, this ) )
{
    connect( d->m_runnerManager, SIGNAL( routeRetrieved( GeoDataDocument* ) ),
             this, SLOT( retrieveRoute( GeoDataDocument* ) ) );
    connect( d->m_alternativeRoutesModel, SIGNAL( currentRouteChanged( GeoDataDocument* ) ),
             d->m_routingModel, SLOT( setCurrentRoute( GeoDataDocument* ) ) );
    connect( d->m_routingModel, SIGNAL( deviatedFromRoute( bool ) ),
             this, SLOT( recalculateRoute( bool ) ) );
}

RoutingManager::~RoutingManager()
{
    delete d;
}

RoutingProfilesModel *RoutingManager::profilesModel()
{
    return d->m_profilesModel;
}

RoutingModel *RoutingManager::routingModel()
{
    return d->m_routingModel;
}

void RoutingManager::retrieveRoute( RouteRequest *route )
{
    d->m_routeRequest = route;
    updateRoute();
}

RouteRequest* RoutingManager::routeRequest()
{
    return d->m_routeRequest;
}

void RoutingManager::updateRoute()
{
    if ( !d->m_routeRequest ) {
        return;
    }

    d->m_haveRoute = false;

    int realSize = 0;
    for ( int i = 0; i < d->m_routeRequest->size(); ++i ) {
        // Sort out dummy targets
        if ( d->m_routeRequest->at( i ).longitude() != 0.0 && d->m_routeRequest->at( i ).latitude() != 0.0 ) {
            ++realSize;
        }
    }

    d->m_alternativeRoutesModel->newRequest( d->m_routeRequest );
    if ( realSize > 1 ) {
        emit stateChanged( RoutingManager::Downloading, d->m_routeRequest );
        d->m_runnerManager->setWorkOffline( d->m_workOffline );
        d->m_runnerManager->retrieveRoute( d->m_routeRequest );
    } else {
        d->m_routingModel->clear();
        emit stateChanged( RoutingManager::Retrieved, d->m_routeRequest );
    }
}

void RoutingManager::setWorkOffline( bool offline )
{
    d->m_workOffline = offline;
}

void RoutingManager::retrieveRoute( GeoDataDocument* route )
{
    if ( route ) {
        d->m_alternativeRoutesModel->addRoute( route );
    }

    if ( !d->m_haveRoute ) {
        d->m_haveRoute = route != 0;
        emit stateChanged( Retrieved, d->m_routeRequest );
    }

    emit routeRetrieved( route );
}

AlternativeRoutesModel* RoutingManager::alternativeRoutesModel()
{
    return d->m_alternativeRoutesModel;
}

void RoutingManager::setAdjustNavigation( AdjustNavigation* adjustNavigation )
{
    d->m_adjustNavigation = adjustNavigation;
}

AdjustNavigation* RoutingManager::adjustNavigation()
{
    return d->m_adjustNavigation;
}

void RoutingManager::writeSettings() const
{
    d->saveRoute( d->stateFile() );
}

void RoutingManager::saveRoute( const QString &filename ) const
{
    d->saveRoute( filename );
}

void RoutingManager::loadRoute( const QString &filename )
{
    d->loadRoute( filename );
}

void RoutingManager::readSettings()
{
    d->loadRoute( d->stateFile() );
    if ( d->m_routeRequest && d->m_profilesModel->rowCount() ) {
        d->m_routeRequest->setRoutingProfile( d->m_profilesModel->profiles().at( 0 ) );
    }
}

void RoutingManager::setGuidanceModeEnabled( bool enabled )
{
    d->m_guidanceModeEnabled = enabled;

    if ( enabled ) {
        d->saveRoute( d->stateFile( "guidance.kml" ) );

        if ( d->m_guidanceModeWarning ) {
            QString text = "
" + tr( "Caution: Driving instructions may be incomplete or wrong." );
            text += " " + tr( "Road construction, weather and other unforeseen variables can result in the suggested route not to be the most expedient or safest route to your destination." );
            text += " " + tr( "Please use common sense while navigating." ) + "
";
            text += "
" + tr( "The Marble development team wishes you a pleasant and safe journey." ) + "
";
            QMessageBox messageBox( QMessageBox::Information, tr( "Guidance Mode - Marble" ), text, QMessageBox::Ok );
            QCheckBox showAgain( tr( "Show again" ) );
            showAgain.setChecked( true );
            showAgain.blockSignals( true ); // otherwise it'd close the dialog
            messageBox.addButton( &showAgain, QMessageBox::ActionRole );
            bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
            messageBox.resize( 380, smallScreen ? 400 : 240 );
            messageBox.exec();
            d->m_guidanceModeWarning = showAgain.isChecked();
        }
    } else {
        d->loadRoute( d->stateFile( "guidance.kml" ) );
    }

    PositionTracking* tracking = d->m_marbleModel->positionTracking();
    PositionProviderPlugin* plugin = tracking->positionProviderPlugin();
    if ( !plugin && enabled ) {
        PluginManager* pluginManager = d->m_marbleModel->pluginManager();
        QList<PositionProviderPlugin*> plugins = pluginManager->createPositionProviderPlugins();
        if ( plugins.size() > 0 ) {
            plugin = plugins.takeFirst();
        }
        qDeleteAll( plugins );
        tracking->setPositionProviderPlugin( plugin );
        d->m_shutdownPositionTracking = true;
    } else if ( plugin && !enabled && d->m_shutdownPositionTracking ) {
        d->m_shutdownPositionTracking = false;
        tracking->setPositionProviderPlugin( 0 );
    }

    adjustNavigation()->setAutoZoom( enabled );
    adjustNavigation()->setRecenter( enabled ? AdjustNavigation::RecenterOnBorder : AdjustNavigation::DontRecenter );
}

void RoutingManager::recalculateRoute( bool deviated )
{
    if ( d->m_guidanceModeEnabled && deviated && d->m_routeRequest ) {
        for ( int i=d->m_routeRequest->size()-3; i>=0; --i ) {
            if ( d->m_routeRequest->visited( i ) ) {
                d->m_routeRequest->remove( i );
            }
        }

        if ( d->m_routeRequest->size() == 2 && d->m_routeRequest->visited( 0 ) && !d->m_routeRequest->visited( 1 ) ) {
            d->m_routeRequest->setPosition( 0, d->m_marbleModel->positionTracking()->currentLocation() );
            updateRoute();
        } else if ( d->m_routeRequest->size() != 0 && !d->m_routeRequest->visited( d->m_routeRequest->size()-1 ) ) {
            d->m_routeRequest->insert( 0, d->m_marbleModel->positionTracking()->currentLocation() );
            updateRoute();
        }
    }
}

void RoutingManager::reverseRoute()
{
    d->m_routeRequest->reverse();
    updateRoute();
}

void RoutingManager::clearRoute()
{
    d->m_routeRequest->clear();
    updateRoute();
}

void RoutingManager::setShowGuidanceModeStartupWarning( bool show )
{
    d->m_guidanceModeWarning = show;
}

bool RoutingManager::showGuidanceModeStartupWarning() const
{
    return d->m_guidanceModeWarning;
}

} // namespace Marble

#include "RoutingManager.moc"
<commit_msg>Correctly restore routes consisting only of via points.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "RoutingManager.h"

#include "AlternativeRoutesModel.h"
#include "MarbleWidget.h"
#include "MarbleModel.h"
#include "RouteRequest.h"
#include "RoutingModel.h"
#include "RoutingProfilesModel.h"
#include "MarbleRunnerManager.h"
#include "AdjustNavigation.h"
#include "GeoWriter.h"
#include "GeoDataDocument.h"
#include "GeoDataParser.h"
#include "GeoDataFolder.h"
#include "MarbleDirs.h"
#include "MarbleDebug.h"
#include "PositionTracking.h"
#include "PluginManager.h"
#include "PositionProviderPlugin.h"

#include <QtCore/QFile>
#include <QtGui/QMessageBox>
#include <QtGui/QCheckBox>
#include <QMutexLocker>

namespace Marble
{

class RoutingManagerPrivate
{
public:
    RoutingManager* q;

    RouteRequest *m_routeRequest;

    RoutingModel *m_routingModel;

    RoutingProfilesModel *m_profilesModel;

    MarbleModel *m_marbleModel;

    AlternativeRoutesModel* m_alternativeRoutesModel;

    bool m_workOffline;

    MarbleRunnerManager* m_runnerManager;

    bool m_haveRoute;

    AdjustNavigation *m_adjustNavigation;

    bool m_guidanceModeEnabled;

    QMutex m_fileMutex;

    bool m_shutdownPositionTracking;

    bool m_guidanceModeWarning;

    RoutingManagerPrivate( MarbleModel *marbleModel, RoutingManager* manager, QObject *parent );

    GeoDataFolder* routeRequest() const;

    QString stateFile( const QString &name = QString( "route.kml" ) ) const;

    void saveRoute( const QString &filename );

    void loadRoute( const QString &filename );
};

RoutingManagerPrivate::RoutingManagerPrivate( MarbleModel *model, RoutingManager* manager, QObject *parent ) :
        q( manager ),
        m_routeRequest( new RouteRequest( manager ) ),
        m_routingModel( new RoutingModel( m_routeRequest, model ) ),
        m_profilesModel( new RoutingProfilesModel( model->pluginManager() ) ),
        m_marbleModel( model ),
        m_alternativeRoutesModel(new AlternativeRoutesModel( model, parent ) ),
        m_workOffline( false ),
        m_runnerManager( new MarbleRunnerManager( model->pluginManager(), q ) ),
        m_haveRoute( false ), m_adjustNavigation( 0 ),
        m_guidanceModeEnabled( false ),
        m_shutdownPositionTracking( false ),
        m_guidanceModeWarning( true )
{
    // nothing to do
}

GeoDataFolder* RoutingManagerPrivate::routeRequest() const
{
    GeoDataFolder* result = new GeoDataFolder;
    result->setName( "Route Request" );
    for ( int i=0; i<m_routeRequest->size(); ++i ) {
        GeoDataPlacemark* placemark = new GeoDataPlacemark;
        placemark->setName( m_routeRequest->name( i ) );
        placemark->setCoordinate( GeoDataPoint( m_routeRequest->at( i ) ) );
        result->append( placemark );
    }

    return result;
}

QString RoutingManagerPrivate::stateFile( const QString &name) const
{
    QString const subdir = "routing";
    QDir dir( MarbleDirs::localPath() );
    if ( !dir.exists( subdir ) ) {
        if ( !dir.mkdir( subdir ) ) {
            mDebug() << "Unable to create dir " << dir.absoluteFilePath( subdir );
            return dir.absolutePath();
        }
    }

    if ( !dir.cd( subdir ) ) {
        mDebug() << "Cannot change into " << dir.absoluteFilePath( subdir );
    }

    return dir.absoluteFilePath( name );
}

void RoutingManagerPrivate::saveRoute(const QString &filename)
{
    GeoWriter writer;
    writer.setDocumentType( "http://earth.google.com/kml/2.2" );

    QMutexLocker locker( &m_fileMutex );
    QFile file( filename );
    if ( !file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
    {
        mDebug() << "Cannot write to " << file.fileName();
        return;
    }

    GeoDataDocument container;
    GeoDataFolder* request = routeRequest();
    if ( request ) {
        container.append( request );
    }

    GeoDataDocument *route = m_alternativeRoutesModel->currentRoute();
    if ( route ) {
        container.append( new GeoDataDocument( *route ) );
    }

    if ( !writer.write( &file, &container ) ) {
        mDebug() << "Can not write route state to " << file.fileName();
    }
    file.close();
}

void RoutingManagerPrivate::loadRoute(const QString &filename)
{
    QFile file( filename );
    if ( !file.open( QIODevice::ReadOnly ) ) {
        mDebug() << "Can not read route from " << file.fileName();
        return;
    }

    GeoDataParser parser( GeoData_KML );
    if ( !parser.read( &file ) ) {
        mDebug() << "Could not parse file: " << parser.errorString();
        return;
    }

    GeoDocument *doc = parser.releaseDocument();
    file.close();
    bool loaded = false;

    GeoDataDocument* container = dynamic_cast<GeoDataDocument*>( doc );
    if ( container && container->size() > 0 ) {
        GeoDataFolder* viaPoints = dynamic_cast<GeoDataFolder*>( &container->first() );
        if ( viaPoints ) {
            loaded = true;
            QVector<GeoDataPlacemark*> placemarks = viaPoints->placemarkList();
            for( int i=0; i<placemarks.size(); ++i ) {
                if ( i < m_routeRequest->size() ) {
                    m_routeRequest->setPosition( i, placemarks[i]->coordinate() );
                } else {
                    m_routeRequest->append( placemarks[i]->coordinate() );
                }
                m_routeRequest->setName( m_routeRequest->size()-1, placemarks[i]->name() );
            }

            for ( int i=placemarks.size(); i<m_routeRequest->size(); ++i ) {
                m_routeRequest->remove( i );
            }
        } else {
            mDebug() << "Expected a GeoDataDocument with at least one child, didn't get one though";
        }
    }

    if ( container && container->size() == 2 ) {
        GeoDataDocument* route = dynamic_cast<GeoDataDocument*>(&container->last());
        if ( route ) {
            loaded = true;
            m_alternativeRoutesModel->addRoute( route, AlternativeRoutesModel::Instant );
            m_alternativeRoutesModel->setCurrentRoute( 0 );
        } else {
            mDebug() << "Expected a GeoDataDocument child, didn't get one though";
        }
    }

    if ( !loaded ) {
        mDebug() << "File " << filename << " is not a valid Marble route .kml file";
        delete doc;
        m_marbleModel->addGeoDataFile( filename );
    }
}

RoutingManager::RoutingManager( MarbleModel *marbleModel, QObject *parent ) : QObject( parent ),
        d( new RoutingManagerPrivate( marbleModel, this, this ) )
{
    connect( d->m_runnerManager, SIGNAL( routeRetrieved( GeoDataDocument* ) ),
             this, SLOT( retrieveRoute( GeoDataDocument* ) ) );
    connect( d->m_alternativeRoutesModel, SIGNAL( currentRouteChanged( GeoDataDocument* ) ),
             d->m_routingModel, SLOT( setCurrentRoute( GeoDataDocument* ) ) );
    connect( d->m_routingModel, SIGNAL( deviatedFromRoute( bool ) ),
             this, SLOT( recalculateRoute( bool ) ) );
}

RoutingManager::~RoutingManager()
{
    delete d;
}

RoutingProfilesModel *RoutingManager::profilesModel()
{
    return d->m_profilesModel;
}

RoutingModel *RoutingManager::routingModel()
{
    return d->m_routingModel;
}

void RoutingManager::retrieveRoute( RouteRequest *route )
{
    d->m_routeRequest = route;
    updateRoute();
}

RouteRequest* RoutingManager::routeRequest()
{
    return d->m_routeRequest;
}

void RoutingManager::updateRoute()
{
    if ( !d->m_routeRequest ) {
        return;
    }

    d->m_haveRoute = false;

    int realSize = 0;
    for ( int i = 0; i < d->m_routeRequest->size(); ++i ) {
        // Sort out dummy targets
        if ( d->m_routeRequest->at( i ).longitude() != 0.0 && d->m_routeRequest->at( i ).latitude() != 0.0 ) {
            ++realSize;
        }
    }

    d->m_alternativeRoutesModel->newRequest( d->m_routeRequest );
    if ( realSize > 1 ) {
        emit stateChanged( RoutingManager::Downloading, d->m_routeRequest );
        d->m_runnerManager->setWorkOffline( d->m_workOffline );
        d->m_runnerManager->retrieveRoute( d->m_routeRequest );
    } else {
        d->m_routingModel->clear();
        emit stateChanged( RoutingManager::Retrieved, d->m_routeRequest );
    }
}

void RoutingManager::setWorkOffline( bool offline )
{
    d->m_workOffline = offline;
}

void RoutingManager::retrieveRoute( GeoDataDocument* route )
{
    if ( route ) {
        d->m_alternativeRoutesModel->addRoute( route );
    }

    if ( !d->m_haveRoute ) {
        d->m_haveRoute = route != 0;
        emit stateChanged( Retrieved, d->m_routeRequest );
    }

    emit routeRetrieved( route );
}

AlternativeRoutesModel* RoutingManager::alternativeRoutesModel()
{
    return d->m_alternativeRoutesModel;
}

void RoutingManager::setAdjustNavigation( AdjustNavigation* adjustNavigation )
{
    d->m_adjustNavigation = adjustNavigation;
}

AdjustNavigation* RoutingManager::adjustNavigation()
{
    return d->m_adjustNavigation;
}

void RoutingManager::writeSettings() const
{
    d->saveRoute( d->stateFile() );
}

void RoutingManager::saveRoute( const QString &filename ) const
{
    d->saveRoute( filename );
}

void RoutingManager::loadRoute( const QString &filename )
{
    d->loadRoute( filename );
}

void RoutingManager::readSettings()
{
    d->loadRoute( d->stateFile() );
    if ( d->m_routeRequest && d->m_profilesModel->rowCount() ) {
        d->m_routeRequest->setRoutingProfile( d->m_profilesModel->profiles().at( 0 ) );
    }
}

void RoutingManager::setGuidanceModeEnabled( bool enabled )
{
    d->m_guidanceModeEnabled = enabled;

    if ( enabled ) {
        d->saveRoute( d->stateFile( "guidance.kml" ) );

        if ( d->m_guidanceModeWarning ) {
            QString text = "
" + tr( "Caution: Driving instructions may be incomplete or wrong." );
            text += " " + tr( "Road construction, weather and other unforeseen variables can result in the suggested route not to be the most expedient or safest route to your destination." );
            text += " " + tr( "Please use common sense while navigating." ) + "
";
            text += "
" + tr( "The Marble development team wishes you a pleasant and safe journey." ) + "
";
            QMessageBox messageBox( QMessageBox::Information, tr( "Guidance Mode - Marble" ), text, QMessageBox::Ok );
            QCheckBox showAgain( tr( "Show again" ) );
            showAgain.setChecked( true );
            showAgain.blockSignals( true ); // otherwise it'd close the dialog
            messageBox.addButton( &showAgain, QMessageBox::ActionRole );
            bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
            messageBox.resize( 380, smallScreen ? 400 : 240 );
            messageBox.exec();
            d->m_guidanceModeWarning = showAgain.isChecked();
        }
    } else {
        d->loadRoute( d->stateFile( "guidance.kml" ) );
    }

    PositionTracking* tracking = d->m_marbleModel->positionTracking();
    PositionProviderPlugin* plugin = tracking->positionProviderPlugin();
    if ( !plugin && enabled ) {
        PluginManager* pluginManager = d->m_marbleModel->pluginManager();
        QList<PositionProviderPlugin*> plugins = pluginManager->createPositionProviderPlugins();
        if ( plugins.size() > 0 ) {
            plugin = plugins.takeFirst();
        }
        qDeleteAll( plugins );
        tracking->setPositionProviderPlugin( plugin );
        d->m_shutdownPositionTracking = true;
    } else if ( plugin && !enabled && d->m_shutdownPositionTracking ) {
        d->m_shutdownPositionTracking = false;
        tracking->setPositionProviderPlugin( 0 );
    }

    adjustNavigation()->setAutoZoom( enabled );
    adjustNavigation()->setRecenter( enabled ? AdjustNavigation::RecenterOnBorder : AdjustNavigation::DontRecenter );
}

void RoutingManager::recalculateRoute( bool deviated )
{
    if ( d->m_guidanceModeEnabled && deviated && d->m_routeRequest ) {
        for ( int i=d->m_routeRequest->size()-3; i>=0; --i ) {
            if ( d->m_routeRequest->visited( i ) ) {
                d->m_routeRequest->remove( i );
            }
        }

        if ( d->m_routeRequest->size() == 2 && d->m_routeRequest->visited( 0 ) && !d->m_routeRequest->visited( 1 ) ) {
            d->m_routeRequest->setPosition( 0, d->m_marbleModel->positionTracking()->currentLocation() );
            updateRoute();
        } else if ( d->m_routeRequest->size() != 0 && !d->m_routeRequest->visited( d->m_routeRequest->size()-1 ) ) {
            d->m_routeRequest->insert( 0, d->m_marbleModel->positionTracking()->currentLocation() );
            updateRoute();
        }
    }
}

void RoutingManager::reverseRoute()
{
    d->m_routeRequest->reverse();
    updateRoute();
}

void RoutingManager::clearRoute()
{
    d->m_routeRequest->clear();
    updateRoute();
}

void RoutingManager::setShowGuidanceModeStartupWarning( bool show )
{
    d->m_guidanceModeWarning = show;
}

bool RoutingManager::showGuidanceModeStartupWarning() const
{
    return d->m_guidanceModeWarning;
}

} // namespace Marble

#include "RoutingManager.moc"
<|endoftext|>


<commit_before>#include "parallel.h"
#include <iostream>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include "cmdLineOptions.h"
#include "h5test.h"

void printVersion(const char* execName)
{
  if (P.myProc == 0)
    std::cerr << execName << " Version: " << H5TEST_VERSION << std::endl;
}

void printUsage(const char* execName)
{
  printVersion(execName);

  if (P.myProc == 0)
    std::cerr << "\nUsage:\n"
              << execName << " [options]\n\n"
              << "Options:\n"
              << " -h, -?        : Print Usage\n"
              << " -v            : Print Version\n"
              << " -C            : use h5 chunk\n"
              << " -S            : use h5 slab (default)\n"
              << " -n nvar       : nvar  (default=4)\n"
              << " -l num        : local size is num (default=10)\n"
              << " -g num        : global size is num\n"
              << " -f factor     : number of stripes per writer (default=2)\n"
              << " -s num        : maximum number of stripes\n"
              << " -p num        : maximum number of writers per node\n"
              << " -w num        : Total number of writers\n"
              << std::endl;
}

CmdLineOptions::CmdLineOptions(int argc, char* argv[])
  : m_state(iBAD)
{
  int  opt;
  bool version, help, illegal;

  maxWritersPer  = INT_MAX;

  maxWriters     = -1
  version        = false;
  help           = false;
  localSz        = -1;
  globalSz       = -1;
  h5chunk        = false;
  h5slab         = false;
  factor         = 1;
  stripes        = -1;
  h5style        = "h5slab";
  luaStyleOutput = false;

  while ( (opt = getopt(argc, argv, "s:hCSLf:p:w:l:g:n:?v")) != -1)
    {
      switch (opt)
        {
        case 'v':
          version = true;
          break;
        case '?':
        case 'h':
          help = true;
          break;
        case 'C':
          h5chunk = true;
          break;
        case 'L':
          luaStyleOutput = true;
          break;
        case 'f':
          factor  = strtol(optarg, (char **) NULL, 10);
          break;
        case 's':
          stripes = strtol(optarg, (char **) NULL, 10);
          break;
        case 'g':
          globalSz = strtoll(optarg, (char **) NULL, 10);
          break;
        case 'l':
          localSz = strtoll(optarg, (char **) NULL, 10);
          break;
        case 'n':
          nvar =    strtol(optarg, (char **) NULL, 10);
          break;
        case 'p':
          maxWritersPer = strtol(optarg, (char **) NULL, 10);
          break;
        case 'w':
          maxWriters    = strtol(optarg, (char **) NULL, 10);
          break;
        case 'S':
          h5slab = true;
          break;
        default:
          illegal = true;
          ;
        }
    }

  if (version)
    {
      m_state = iHELP;
      printVersion(argv[0]);
      return;
    }

  if (help)
    {
      m_state = iHELP;
      printUsage(argv[0]);
      return;
    }

  if (! h5chunk && ! h5slab)
    h5slab = true;

  if ( h5chunk )
    h5style = "h5chunk";

  if (localSz < 0)
    {
      if (globalSz < 0)
        localSz = 10;
      else
        {
          int rem = globalSz % P.nProcs;
          localSz = globalSz/P.nProcs + (P.myProc < rem);
        }
    }

  if (globalSz < 0)
    globalSz = localSz * P.nProcs;

  m_state = iGOOD;
}

<commit_msg>more debug foo<commit_after>#include "parallel.h"
#include <iostream>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include "cmdLineOptions.h"
#include "h5test.h"

void printVersion(const char* execName)
{
  if (P.myProc == 0)
    std::cerr << execName << " Version: " << H5TEST_VERSION << std::endl;
}

void printUsage(const char* execName)
{
  printVersion(execName);

  if (P.myProc == 0)
    std::cerr << "\nUsage:\n"
              << execName << " [options]\n\n"
              << "Options:\n"
              << " -h, -?        : Print Usage\n"
              << " -v            : Print Version\n"
              << " -C            : use h5 chunk\n"
              << " -S            : use h5 slab (default)\n"
              << " -n nvar       : nvar  (default=4)\n"
              << " -l num        : local size is num (default=10)\n"
              << " -g num        : global size is num\n"
              << " -f factor     : number of stripes per writer (default=2)\n"
              << " -s num        : maximum number of stripes\n"
              << " -p num        : maximum number of writers per node\n"
              << " -w num        : Total number of writers\n"
              << std::endl;
}

CmdLineOptions::CmdLineOptions(int argc, char* argv[])
  : m_state(iBAD)
{
  int  opt;
  bool version, help, illegal;

  maxWritersPer  = INT_MAX;

  maxWriters     = -1;
  version        = false;
  help           = false;
  localSz        = -1;
  globalSz       = -1;
  h5chunk        = false;
  h5slab         = false;
  factor         = 1;
  stripes        = -1;
  h5style        = "h5slab";
  luaStyleOutput = false;

  while ( (opt = getopt(argc, argv, "s:hCSLf:p:w:l:g:n:?v")) != -1)
    {
      switch (opt)
        {
        case 'v':
          version = true;
          break;
        case '?':
        case 'h':
          help = true;
          break;
        case 'C':
          h5chunk = true;
          break;
        case 'L':
          luaStyleOutput = true;
          break;
        case 'f':
          factor  = strtol(optarg, (char **) NULL, 10);
          break;
        case 's':
          stripes = strtol(optarg, (char **) NULL, 10);
          break;
        case 'g':
          globalSz = strtoll(optarg, (char **) NULL, 10);
          break;
        case 'l':
          localSz = strtoll(optarg, (char **) NULL, 10);
          break;
        case 'n':
          nvar =    strtol(optarg, (char **) NULL, 10);
          break;
        case 'p':
          maxWritersPer = strtol(optarg, (char **) NULL, 10);
          break;
        case 'w':
          maxWriters    = strtol(optarg, (char **) NULL, 10);
          break;
        case 'S':
          h5slab = true;
          break;
        default:
          illegal = true;
          ;
        }
    }

  if (version)
    {
      m_state = iHELP;
      printVersion(argv[0]);
      return;
    }

  if (help)
    {
      m_state = iHELP;
      printUsage(argv[0]);
      return;
    }

  if (! h5chunk && ! h5slab)
    h5slab = true;

  if ( h5chunk )
    h5style = "h5chunk";

  if (localSz < 0)
    {
      if (globalSz < 0)
        localSz = 10;
      else
        {
          int rem = globalSz % P.nProcs;
          localSz = globalSz/P.nProcs + (P.myProc < rem);
        }
    }

  if (globalSz < 0)
    globalSz = localSz * P.nProcs;

  m_state = iGOOD;
}

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Chen-Pang He <jdh8@ms63.hinet.net>
//
// 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/.

#include "matrix_functions.h"

// for complex matrices, any matrix is fine
template<typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
struct generateSingularMatrix
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    result = MatrixType::Random(size, size);
    result.col(0).fill(0);
  }
};

// for real matrices, make sure none of the eigenvalues are negative
template<typename MatrixType>
struct generateSingularMatrix<MatrixType,0>
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    MatrixType mat = MatrixType::Random(size, size);
    mat.col(0).fill(0);
    ComplexSchur<MatrixType> schur(mat);
    typename ComplexSchur<MatrixType>::ComplexMatrixType T = schur.matrixT();

    for (typename MatrixType::Index i = 0; i < size; ++i) {
      if (T.coeff(i,i).imag() == 0 && T.coeff(i,i).real() < 0)
	T.coeffRef(i,i) = -T.coeff(i,i);
    }
    result = (schur.matrixU() * (T.template triangularView<Upper>() * schur.matrixU().adjoint())).real();
  }
};

template<typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle, c, s;

  A << 0, 1, -1, 0;
  MatrixPower<Matrix<T,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = pow(10, (i-10) / 5.);
    c = std::cos(angle);
    s = std::sin(angle);
    B << c, s, -s, c;

    C = Apow(std::ldexp(angle,1) / M_PI);
    std::cout << "test2dRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  T angle, ch = std::cosh((T)1);
  std::complex<T> ish(0, std::sinh((T)1));

  A << ch, ish, -ish, ch;
  MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = std::ldexp(static_cast<T>(i-10), -1);
    ch = std::cosh(angle);
    ish = std::complex<T>(0, std::sinh(angle));
    B << ch, ish, -ish, ch;

    C = Apow(angle);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename MatrixType>
void testGeneral(const MatrixType& m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>();
    y = internal::random<RealScalar>();
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (std::abs(x) * m1).pow(y);
    m5 = std::pow(std::abs(x), y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testSingular(MatrixType m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>(0, 1);
    y = internal::random<RealScalar>(0, 1);
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (x * m1).pow(y);
    m5 = std::pow(x, y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testLogThenExp(MatrixType m, double tol)
{
  typedef typename MatrixType::Scalar Scalar;
  Scalar x;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m, m.rows());
    x = internal::random<Scalar>();
    VERIFY(m.pow(x).isApprox((x * m.log()).exp(), tol));
  }
}

typedef Matrix<double,3,3,RowMajor>         Matrix3dRowMajor;
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;

void test_matrix_power()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(2e-5));  // was 1e-5, relaxed for clang 2.8 / linux / x86-64
  CALL_SUBTEST_9(test2dRotation<long double>(1e-13));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));

  CALL_SUBTEST_2(testGeneral(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testGeneral(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testGeneral(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testGeneral(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testGeneral(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testGeneral(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testGeneral(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testGeneral(MatrixXf(2,2),      1e-3)); // see bug 614
  CALL_SUBTEST_9(testGeneral(MatrixXe(7,7),      1e-13));

  CALL_SUBTEST_2(testSingular(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testSingular(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testSingular(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testSingular(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testSingular(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testSingular(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testSingular(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testSingular(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testSingular(MatrixXe(7,7),      1e-13));

  CALL_SUBTEST_2(testLogThenExp(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testLogThenExp(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testLogThenExp(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testLogThenExp(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testLogThenExp(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testLogThenExp(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testLogThenExp(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testLogThenExp(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testLogThenExp(MatrixXe(7,7),      1e-13));
}
<commit_msg>Add test3dRotation.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Chen-Pang He <jdh8@ms63.hinet.net>
//
// 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/.

#include "matrix_functions.h"

// for complex matrices, any matrix is fine
template<typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
struct generateSingularMatrix
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    result = MatrixType::Random(size, size);
    result.col(0).fill(0);
  }
};

// for real matrices, make sure none of the eigenvalues are negative
template<typename MatrixType>
struct generateSingularMatrix<MatrixType,0>
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    MatrixType mat = MatrixType::Random(size, size);
    mat.col(0).fill(0);
    ComplexSchur<MatrixType> schur(mat);
    typename ComplexSchur<MatrixType>::ComplexMatrixType T = schur.matrixT();

    for (typename MatrixType::Index i = 0; i < size; ++i) {
      if (T.coeff(i,i).imag() == 0 && T.coeff(i,i).real() < 0)
	T.coeffRef(i,i) = -T.coeff(i,i);
    }
    result = (schur.matrixU() * (T.template triangularView<Upper>() * schur.matrixU().adjoint())).real();
  }
};

template<typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle, c, s;

  A << 0, 1, -1, 0;
  MatrixPower<Matrix<T,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = pow(10, (i-10) / 5.);
    c = std::cos(angle);
    s = std::sin(angle);
    B << c, s, -s, c;

    C = Apow(std::ldexp(angle,1) / M_PI);
    std::cout << "test2dRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  T angle, ch = std::cosh((T)1);
  std::complex<T> ish(0, std::sinh((T)1));

  A << ch, ish, -ish, ch;
  MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = std::ldexp(static_cast<T>(i-10), -1);
    ch = std::cosh(angle);
    ish = std::complex<T>(0, std::sinh(angle));
    B << ch, ish, -ish, ch;

    C = Apow(angle);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test3dRotation(double tol)
{
  Matrix<T,3,1> v;
  T angle;

  for (int i=0; i<=20; ++i) {
    v = Matrix<T,3,1>::Random();
    v.normalize();
    angle = pow(10, (i-10) / 5.);
    VERIFY(AngleAxis<T>(angle, v).matrix().isApprox(AngleAxis<T>(1,v).matrix().pow(angle), tol));
  }
}

template<typename MatrixType>
void testGeneral(const MatrixType& m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>();
    y = internal::random<RealScalar>();
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (std::abs(x) * m1).pow(y);
    m5 = std::pow(std::abs(x), y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testSingular(MatrixType m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>(0, 1);
    y = internal::random<RealScalar>(0, 1);
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (x * m1).pow(y);
    m5 = std::pow(x, y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testLogThenExp(MatrixType m, double tol)
{
  typedef typename MatrixType::Scalar Scalar;
  Scalar x;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m, m.rows());
    x = internal::random<Scalar>();
    VERIFY(m.pow(x).isApprox((x * m.log()).exp(), tol));
  }
}

typedef Matrix<double,3,3,RowMajor>         Matrix3dRowMajor;
typedef Matrix<long double,3,3>             Matrix3e;
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;

void test_matrix_power()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(2e-5));  // was 1e-5, relaxed for clang 2.8 / linux / x86-64
  CALL_SUBTEST_9(test2dRotation<long double>(1e-13));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));

  CALL_SUBTEST_10(test3dRotation<double>(1e-13));
  CALL_SUBTEST_11(test3dRotation<float>(1e-5));
  CALL_SUBTEST_12(test3dRotation<long double>(1e-13));

  CALL_SUBTEST_2(testGeneral(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testGeneral(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testGeneral(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testGeneral(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testGeneral(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testGeneral(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testGeneral(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testGeneral(MatrixXf(2,2),      1e-3)); // see bug 614
  CALL_SUBTEST_9(testGeneral(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testGeneral(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testGeneral(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testGeneral(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testSingular(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testSingular(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testSingular(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testSingular(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testSingular(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testSingular(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testSingular(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testSingular(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testSingular(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testSingular(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testSingular(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testSingular(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testLogThenExp(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testLogThenExp(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testLogThenExp(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testLogThenExp(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testLogThenExp(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testLogThenExp(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testLogThenExp(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testLogThenExp(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testLogThenExp(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testLogThenExp(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testLogThenExp(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testLogThenExp(Matrix3e(),        1e-13));
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Chen-Pang He <jdh8@ms63.hinet.net>
//
// 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/.

#include "matrix_functions.h"

// for complex matrices, any matrix is fine
template<typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
struct generateSingularMatrix
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    result = MatrixType::Random(size, size);
    result.col(0).fill(0);
  }
};

// for real matrices, make sure none of the eigenvalues are negative
template<typename MatrixType>
struct generateSingularMatrix<MatrixType,0>
{
  static void run(MatrixType& result, typename MatrixType::Index size)
  {
    MatrixType mat = MatrixType::Random(size, size);
    mat.col(0).fill(0);
    ComplexSchur<MatrixType> schur(mat);
    typename ComplexSchur<MatrixType>::ComplexMatrixType T = schur.matrixT();

    for (typename MatrixType::Index i = 0; i < size; ++i) {
      if (T.coeff(i,i).imag() == 0 && T.coeff(i,i).real() < 0)
	T.coeffRef(i,i) = -T.coeff(i,i);
    }
    result = (schur.matrixU() * (T.template triangularView<Upper>() * schur.matrixU().adjoint())).real();
  }
};

template<typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle, c, s;

  A << 0, 1, -1, 0;
  MatrixPower<Matrix<T,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = pow(10, (i-10) / 5.);
    c = std::cos(angle);
    s = std::sin(angle);
    B << c, s, -s, c;

    C = Apow(std::ldexp(angle,1) / M_PI);
    std::cout << "test2dRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  T angle, ch = std::cosh((T)1);
  std::complex<T> ish(0, std::sinh((T)1));

  A << ch, ish, -ish, ch;
  MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = std::ldexp(static_cast<T>(i-10), -1);
    ch = std::cosh(angle);
    ish = std::complex<T>(0, std::sinh(angle));
    B << ch, ish, -ish, ch;

    C = Apow(angle);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test3dRotation(double tol)
{
  Matrix<T,3,1> v;
  T angle;

  for (int i=0; i<=20; ++i) {
    v = Matrix<T,3,1>::Random();
    v.normalize();
    angle = pow(10, (i-10) / 5.);
    VERIFY(AngleAxis<T>(angle, v).matrix().isApprox(AngleAxis<T>(1,v).matrix().pow(angle), tol));
  }
}

template<typename MatrixType>
void testGeneral(const MatrixType& m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>();
    y = internal::random<RealScalar>();
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (std::abs(x) * m1).pow(y);
    m5 = std::pow(std::abs(x), y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testSingular(MatrixType m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateSingularMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>(0, 1);
    y = internal::random<RealScalar>(0, 1);
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (x * m1).pow(y);
    m5 = std::pow(x, y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

template<typename MatrixType>
void testLogThenExp(MatrixType m, double tol)
{
  typedef typename MatrixType::Scalar Scalar;
  Scalar x;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m, m.rows());
    x = internal::random<Scalar>();
    VERIFY(m.pow(x).isApprox((x * m.log()).exp(), tol));
  }
}

typedef Matrix<double,3,3,RowMajor>         Matrix3dRowMajor;
typedef Matrix<long double,3,3>             Matrix3e;
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;

void test_matrix_power()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(2e-5));  // was 1e-5, relaxed for clang 2.8 / linux / x86-64
  CALL_SUBTEST_9(test2dRotation<long double>(1e-13));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));

  CALL_SUBTEST_10(test3dRotation<double>(1e-13));
  CALL_SUBTEST_11(test3dRotation<float>(1e-5));
  CALL_SUBTEST_12(test3dRotation<long double>(1e-13));

  CALL_SUBTEST_2(testGeneral(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testGeneral(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testGeneral(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testGeneral(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testGeneral(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testGeneral(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testGeneral(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testGeneral(MatrixXf(2,2),      1e-3)); // see bug 614
  CALL_SUBTEST_9(testGeneral(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testGeneral(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testGeneral(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testGeneral(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testSingular(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testSingular(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testSingular(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testSingular(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testSingular(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testSingular(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testSingular(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testSingular(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testSingular(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testSingular(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testSingular(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testSingular(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testLogThenExp(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testLogThenExp(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testLogThenExp(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testLogThenExp(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testLogThenExp(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testLogThenExp(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testLogThenExp(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testLogThenExp(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testLogThenExp(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testLogThenExp(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testLogThenExp(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testLogThenExp(Matrix3e(),        1e-13));
}
<commit_msg>Test singular matrix power with square roots. Exponent laws are too unstable.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012, 2013 Chen-Pang He <jdh8@ms63.hinet.net>
//
// 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/.

#include "matrix_functions.h"

template<typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle, c, s;

  A << 0, 1, -1, 0;
  MatrixPower<Matrix<T,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = pow(10, (i-10) / 5.);
    c = std::cos(angle);
    s = std::sin(angle);
    B << c, s, -s, c;

    C = Apow(std::ldexp(angle,1) / M_PI);
    std::cout << "test2dRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  T angle, ch = std::cosh((T)1);
  std::complex<T> ish(0, std::sinh((T)1));

  A << ch, ish, -ish, ch;
  MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A);

  for (int i=0; i<=20; ++i) {
    angle = std::ldexp(static_cast<T>(i-10), -1);
    ch = std::cosh(angle);
    ish = std::complex<T>(0, std::sinh(angle));
    B << ch, ish, -ish, ch;

    C = Apow(angle);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error powerm = " << relerr(C,B) << '\n';
    VERIFY(C.isApprox(B, tol));
  }
}

template<typename T>
void test3dRotation(double tol)
{
  Matrix<T,3,1> v;
  T angle;

  for (int i=0; i<=20; ++i) {
    v = Matrix<T,3,1>::Random();
    v.normalize();
    angle = pow(10, (i-10) / 5.);
    VERIFY(AngleAxis<T>(angle, v).matrix().isApprox(AngleAxis<T>(1,v).matrix().pow(angle), tol));
  }
}

template<typename MatrixType>
void testGeneral(const MatrixType& m, double tol)
{
  typedef typename MatrixType::RealScalar RealScalar;
  MatrixType m1, m2, m3, m4, m5;
  RealScalar x, y;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m1, m.rows());
    MatrixPower<MatrixType> mpow(m1);

    x = internal::random<RealScalar>();
    y = internal::random<RealScalar>();
    m2 = mpow(x);
    m3 = mpow(y);

    m4 = mpow(x+y);
    m5.noalias() = m2 * m3;
    VERIFY(m4.isApprox(m5, tol));

    m4 = mpow(x*y);
    m5 = m2.pow(y);
    VERIFY(m4.isApprox(m5, tol));

    m4 = (std::abs(x) * m1).pow(y);
    m5 = std::pow(std::abs(x), y) * m3;
    VERIFY(m4.isApprox(m5, tol));
  }
}

// For complex matrices, any matrix is fine.
template<typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
struct processTriangularMatrix
{
  static void run(MatrixType&, MatrixType&, const MatrixType&)
  { }
};

// For real matrices, make sure none of the eigenvalues are negative.
template<typename MatrixType>
struct processTriangularMatrix<MatrixType,0>
{
  static void run(MatrixType& m, MatrixType& T, const MatrixType& U)
  {
    typedef typename MatrixType::Index Index;
    const Index size = m.cols();

    for (Index i=0; i < size; ++i) {
      if (i == size - 1 || T.coeff(i+1,i) == 0)
        T.coeffRef(i,i) = std::abs(T.coeff(i,i));
      else
        ++i;
    }
    m = U * T * U.adjoint();
  }
};

template<typename MatrixType>
void testSingular(MatrixType m, double tol)
{
  const int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex;
  typedef typename internal::conditional< IsComplex, MatrixSquareRootTriangular<MatrixType>,
          MatrixSquareRootQuasiTriangular<MatrixType> >::type SquareRootType;
  typedef typename internal::conditional<IsComplex, TriangularView<MatrixType,Upper>, const MatrixType&>::type TriangularType;
  typename internal::conditional< IsComplex, ComplexSchur<MatrixType>, RealSchur<MatrixType> >::type schur;
  MatrixType T;

  for (int i=0; i < g_repeat; ++i) {
    m.setRandom();
    m.col(0).fill(0);

    schur.compute(m);
    T = schur.matrixT();
    const MatrixType& U = schur.matrixU();
    processTriangularMatrix<MatrixType>::run(m, T, U);
    MatrixPower<MatrixType> mpow(m);

    SquareRootType(T).compute(T);
    VERIFY(mpow(0.5).isApprox(U * (TriangularType(T) * U.adjoint()), tol));

    SquareRootType(T).compute(T);
    VERIFY(mpow(0.25).isApprox(U * (TriangularType(T) * U.adjoint()), tol));

    SquareRootType(T).compute(T);
    VERIFY(mpow(0.125).isApprox(U * (TriangularType(T) * U.adjoint()), tol));
  }
}

template<typename MatrixType>
void testLogThenExp(MatrixType m, double tol)
{
  typedef typename MatrixType::Scalar Scalar;
  Scalar x;

  for (int i=0; i < g_repeat; ++i) {
    generateTestMatrix<MatrixType>::run(m, m.rows());
    x = internal::random<Scalar>();
    VERIFY(m.pow(x).isApprox((x * m.log()).exp(), tol));
  }
}

typedef Matrix<double,3,3,RowMajor>         Matrix3dRowMajor;
typedef Matrix<long double,3,3>             Matrix3e;
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;

void test_matrix_power()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(2e-5));  // was 1e-5, relaxed for clang 2.8 / linux / x86-64
  CALL_SUBTEST_9(test2dRotation<long double>(1e-13));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));

  CALL_SUBTEST_10(test3dRotation<double>(1e-13));
  CALL_SUBTEST_11(test3dRotation<float>(1e-5));
  CALL_SUBTEST_12(test3dRotation<long double>(1e-13));

  CALL_SUBTEST_2(testGeneral(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testGeneral(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testGeneral(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testGeneral(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testGeneral(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testGeneral(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testGeneral(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testGeneral(MatrixXf(2,2),      1e-3)); // see bug 614
  CALL_SUBTEST_9(testGeneral(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testGeneral(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testGeneral(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testGeneral(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testSingular(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testSingular(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testSingular(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testSingular(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testSingular(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testSingular(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testSingular(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testSingular(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testSingular(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testSingular(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testSingular(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testSingular(Matrix3e(),        1e-13));

  CALL_SUBTEST_2(testLogThenExp(Matrix2d(),         1e-13));
  CALL_SUBTEST_7(testLogThenExp(Matrix3dRowMajor(), 1e-13));
  CALL_SUBTEST_3(testLogThenExp(Matrix4cd(),        1e-13));
  CALL_SUBTEST_4(testLogThenExp(MatrixXd(8,8),      2e-12));
  CALL_SUBTEST_1(testLogThenExp(Matrix2f(),         1e-4));
  CALL_SUBTEST_5(testLogThenExp(Matrix3cf(),        1e-4));
  CALL_SUBTEST_8(testLogThenExp(Matrix4f(),         1e-4));
  CALL_SUBTEST_6(testLogThenExp(MatrixXf(2,2),      1e-3));
  CALL_SUBTEST_9(testLogThenExp(MatrixXe(7,7),      1e-13));
  CALL_SUBTEST_10(testLogThenExp(Matrix3d(),        1e-13));
  CALL_SUBTEST_11(testLogThenExp(Matrix3f(),        1e-4));
  CALL_SUBTEST_12(testLogThenExp(Matrix3e(),        1e-13));
}
<|endoftext|>