<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (C) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (C) 2010 Keith Rusler <xzekecomax@gmail.com>
 * Copyright (C) 2010 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "newprojectdialogpage.h"

#include <core/gluon_global.h>
#include <engine/gameproject.h>
#include <engine/scene.h>
#include <engine/game.h>
#include <engine/gameobject.h>
#include <engine/component.h>

#include <KDE/KLocalizedString>
#include <KDE/KIcon>
#include <KDE/KLineEdit>
#include <KDE/KUrlRequester>
#include <KDE/KMessageBox>
#include <KDE/KSqueezedTextLabel>

#include <QtGui/QGroupBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QLabel>
#include <QtCore/QScopedPointer>

using namespace GluonCreator;

class NewProjectDialogPage::NewProjectDialogPagePrivate
{
    public:
        NewProjectDialogPagePrivate( NewProjectDialogPage* qq )
            : name( 0 )
            , location( 0 )
            , locationValidLabel( 0 )
            , q( qq )
        {
        }

    public:
        KLineEdit* name;
        KUrlRequester* location;
        KSqueezedTextLabel* locationValidLabel;

    private:
        NewProjectDialogPage* q;
};

NewProjectDialogPage::NewProjectDialogPage()
    : KPageWidgetItem( new QWidget, i18n( "New Project" ) ),
      d( new NewProjectDialogPagePrivate( this ) )
{
    setIcon( KIcon( "document-new" ) );

    QVBoxLayout* layout = new QVBoxLayout( widget() );
    QGroupBox* box = new QGroupBox( i18n( "General Information" ), widget() );

    widget()->setLayout( layout );
    layout->addWidget( box );

    QFormLayout* boxLayout = new QFormLayout( box );
    box->setLayout( boxLayout );

    d->name = new KLineEdit( box );
    d->name->setPlaceholderText( i18n( "Enter the name for a new game project" ) );
    boxLayout->addRow( i18n( "Project Name" ), d->name );

    d->location = new KUrlRequester( box );
    d->location->setMode( KFile::Directory );
    QFileInfo locInfo( QDir::currentPath() );
    if( locInfo.isWritable() )
        d->location->setUrl( KUrl( QDir::current().absolutePath() ) );
    else
        d->location->setUrl( KUrl( QDir::homePath() ) );
    boxLayout->addRow( i18n( "Project Location" ), d->location );

    d->locationValidLabel = new KSqueezedTextLabel( box );
    boxLayout->addRow( QString(), d->locationValidLabel );

    connect( d->name, SIGNAL(textEdited(QString)), SLOT(validateByProjectName()) );
    connect( d->location->lineEdit(), SIGNAL(textEdited(QString)), SLOT(validateByProjectLocation()) );

    validateData();
}

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

QString NewProjectDialogPage::createProject() const
{
    if( d->name->text().isEmpty() || d->location->url().isEmpty() )
    {
        KMessageBox::error( 0, i18n( "You need to enter a name and location to continue" ) );
        return QString();
    }

    QScopedPointer<GluonEngine::GameProject> project( new GluonEngine::GameProject( GluonEngine::Game::instance() ) );
    if( project.isNull() )
    {
        return QString();
    }

    project->setName( d->name->text() );

    GluonCore::GluonObject* scenesFolder = new GluonCore::GluonObject( "Scenes" );

    GluonEngine::Scene* root = new GluonEngine::Scene( project.data() );
    root->setGameProject( project.data() );
    root->setName( i18n( "New Scene" ) );
    root->savableDirty = true;

    scenesFolder->addChild( root );
    project->setEntryPoint( root );
    project->addChild( scenesFolder );

    GluonEngine::GameObject* camera = new GluonEngine::GameObject( root );
    camera->setName( i18n( "Camera" ) );
    camera->setPosition( 0.0f, 0.0f, 50.0f );
    root->sceneContents()->addChild( camera );

    GluonCore::GluonObject* cameraController =
        GluonCore::GluonObjectFactory::instance()->instantiateObjectByName( "GluonEngine::CameraControllerComponent" );
    cameraController->setName( "CameraController" );
    camera->addComponent( qobject_cast<GluonEngine::Component*>( cameraController ) );

    GluonEngine::GameObject* sprite = new GluonEngine::GameObject( root );
    sprite->setName( i18n( "Sprite" ) );
    sprite->setScale( 10.f, 10.f, 0.f );
    root->sceneContents()->addChild( sprite );

    GluonCore::GluonObject* spriteComponent =
        GluonCore::GluonObjectFactory::instance()->instantiateObjectByName( "GluonEngine::SpriteRendererComponent" );
    spriteComponent->setName( "SpriteRenderer" );
    sprite->addComponent( qobject_cast<GluonEngine::Component*>( spriteComponent ) );

    project->addChild( new GluonCore::GluonObject( "Assets" ) );
    project->addChild( new GluonCore::GluonObject( "Prefabs" ) );

    KUrl location = d->location->url();
    QString gameBundleDir = GluonEngine::Asset::fullyQualifiedFileName( project.data(), QFileInfo( GluonEngine::projectSuffix ).completeSuffix() );
    location.addPath( gameBundleDir );
    project->setDirname( location );
    location.addPath( GluonEngine::projectFilename );
    project->setFilename( location );

    KUrl currentLocation = d->location->url();
    currentLocation.addPath( gameBundleDir );
    QDir dir = QDir( d->location->text() );
    dir.mkpath( gameBundleDir );
    QDir::setCurrent( currentLocation.toLocalFile() );
    project->saveToFile();

    return location.toLocalFile();
}

void NewProjectDialogPage::setForeground( QLabel* label, KColorScheme::ForegroundRole role )
{
    QPalette p = label->palette();
    KColorScheme::adjustForeground( p, role, label->foregroundRole(), KColorScheme::Window );
    label->setPalette( p );
}

void NewProjectDialogPage::validateByProjectName()
{
    validateData();
}

void NewProjectDialogPage::validateByProjectLocation()
{
    validateData();
}

void NewProjectDialogPage::validateData()
{
    KUrl url = d->location->url();
    if( !url.isLocalFile() || url.isEmpty() )
    {
        d->locationValidLabel->setText( i18n( "Invalid location" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    QString appName = d->name->text();

    if( appName.isEmpty() )
    {
        d->locationValidLabel->setText( i18n( "Empty project name" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    if( appName == "." || appName == ".." )
    {
        d->locationValidLabel->setText( i18n( "Invalid project name" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    QDir tDir( url.toLocalFile( KUrl::RemoveTrailingSlash ) );
    while( !tDir.exists() && !tDir.isRoot() )
        tDir.setPath( pathUp( tDir.absolutePath() ) );

    if( tDir.exists() )
    {
        QFileInfo tFileInfo( tDir.absolutePath() );
        if( !tFileInfo.isWritable() || !tFileInfo.isExecutable() )
        {
            d->locationValidLabel->setText( i18n( "Unable to create subdirectories, "
                                                  "missing permissions on: %1", tDir.absolutePath() ) );
            setForeground( d->locationValidLabel, KColorScheme::NegativeText );
            emit validationFinished( false );
            return;
        }
    }

    d->locationValidLabel->setText( QString( " " ) );
    setForeground( d->locationValidLabel, KColorScheme::NormalText );
    emit validationFinished( true );

    // Check for non-empty target directory. Not an error, but need to display a warning.
    url.addPath( encodedAppName() );
    QFileInfo fi( url.toLocalFile( KUrl::RemoveTrailingSlash ) );
    if( fi.exists() && fi.isDir() )
    {
        if( !QDir( fi.absoluteFilePath() ).entryList( QDir::NoDotAndDotDot | QDir::AllEntries ).isEmpty() )
        {
            d->locationValidLabel->setText( i18n( "Path already exists and contains files" ) );
            setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        }
    }
}

bool NewProjectDialogPage::isModified() const
{
    return ( !d->name->text().isEmpty() || !d->location->url().isEmpty() );
}

QByteArray NewProjectDialogPage::encodedAppName()
{
    // : < > * ? / \ | " are invalid on windows
    QByteArray tEncodedName = d->name->text().toUtf8();
    for( int i = 0; i < tEncodedName.size(); ++i )
    {
        QChar tChar( tEncodedName.at( i ) );
        if( tChar.isDigit() || tChar.isSpace() || tChar.isLetter() || tChar == '%' )
            continue;

        QByteArray tReplace = QUrl::toPercentEncoding( tChar );
        tEncodedName.replace( tEncodedName.at( i ) , tReplace );
        i =  i + tReplace.size() - 1;
    }
    return tEncodedName;
}

QString NewProjectDialogPage::pathUp( const QString& aPath )
{
    QString tPath = aPath;
    int tIndex = tPath.lastIndexOf( QDir::separator() );
    tPath = tPath.remove( tIndex, tPath.length() - tIndex );
    return tPath;
}

<commit_msg>Creator: Fix an endless while-statement in the new project dialog<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (C) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 * Copyright (C) 2010 Keith Rusler <xzekecomax@gmail.com>
 * Copyright (C) 2010 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "newprojectdialogpage.h"

#include <core/gluon_global.h>
#include <engine/gameproject.h>
#include <engine/scene.h>
#include <engine/game.h>
#include <engine/gameobject.h>
#include <engine/component.h>

#include <KDE/KLocalizedString>
#include <KDE/KIcon>
#include <KDE/KLineEdit>
#include <KDE/KUrlRequester>
#include <KDE/KMessageBox>
#include <KDE/KSqueezedTextLabel>

#include <QtGui/QGroupBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QLabel>
#include <QtCore/QScopedPointer>

using namespace GluonCreator;

class NewProjectDialogPage::NewProjectDialogPagePrivate
{
    public:
        NewProjectDialogPagePrivate( NewProjectDialogPage* qq )
            : name( 0 )
            , location( 0 )
            , locationValidLabel( 0 )
            , q( qq )
        {
        }

    public:
        KLineEdit* name;
        KUrlRequester* location;
        KSqueezedTextLabel* locationValidLabel;

    private:
        NewProjectDialogPage* q;
};

NewProjectDialogPage::NewProjectDialogPage()
    : KPageWidgetItem( new QWidget, i18n( "New Project" ) ),
      d( new NewProjectDialogPagePrivate( this ) )
{
    setIcon( KIcon( "document-new" ) );

    QVBoxLayout* layout = new QVBoxLayout( widget() );
    QGroupBox* box = new QGroupBox( i18n( "General Information" ), widget() );

    widget()->setLayout( layout );
    layout->addWidget( box );

    QFormLayout* boxLayout = new QFormLayout( box );
    box->setLayout( boxLayout );

    d->name = new KLineEdit( box );
    d->name->setPlaceholderText( i18n( "Enter the name for a new game project" ) );
    boxLayout->addRow( i18n( "Project Name" ), d->name );

    d->location = new KUrlRequester( box );
    d->location->setMode( KFile::Directory );
    QFileInfo locInfo( QDir::currentPath() );
    if( locInfo.isWritable() )
        d->location->setUrl( KUrl( QDir::current().absolutePath() ) );
    else
        d->location->setUrl( KUrl( QDir::homePath() ) );
    boxLayout->addRow( i18n( "Project Location" ), d->location );

    d->locationValidLabel = new KSqueezedTextLabel( box );
    boxLayout->addRow( QString(), d->locationValidLabel );

    connect( d->name, SIGNAL(textEdited(QString)), SLOT(validateByProjectName()) );
    connect( d->location->lineEdit(), SIGNAL(textEdited(QString)), SLOT(validateByProjectLocation()) );

    validateData();
}

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

QString NewProjectDialogPage::createProject() const
{
    if( d->name->text().isEmpty() || d->location->url().isEmpty() )
    {
        KMessageBox::error( 0, i18n( "You need to enter a name and location to continue" ) );
        return QString();
    }

    QScopedPointer<GluonEngine::GameProject> project( new GluonEngine::GameProject( GluonEngine::Game::instance() ) );
    if( project.isNull() )
    {
        return QString();
    }

    project->setName( d->name->text() );

    GluonCore::GluonObject* scenesFolder = new GluonCore::GluonObject( "Scenes" );

    GluonEngine::Scene* root = new GluonEngine::Scene( project.data() );
    root->setGameProject( project.data() );
    root->setName( i18n( "New Scene" ) );
    root->savableDirty = true;

    scenesFolder->addChild( root );
    project->setEntryPoint( root );
    project->addChild( scenesFolder );

    GluonEngine::GameObject* camera = new GluonEngine::GameObject( root );
    camera->setName( i18n( "Camera" ) );
    camera->setPosition( 0.0f, 0.0f, 50.0f );
    root->sceneContents()->addChild( camera );

    GluonCore::GluonObject* cameraController =
        GluonCore::GluonObjectFactory::instance()->instantiateObjectByName( "GluonEngine::CameraControllerComponent" );
    cameraController->setName( "CameraController" );
    camera->addComponent( qobject_cast<GluonEngine::Component*>( cameraController ) );

    GluonEngine::GameObject* sprite = new GluonEngine::GameObject( root );
    sprite->setName( i18n( "Sprite" ) );
    sprite->setScale( 10.f, 10.f, 0.f );
    root->sceneContents()->addChild( sprite );

    GluonCore::GluonObject* spriteComponent =
        GluonCore::GluonObjectFactory::instance()->instantiateObjectByName( "GluonEngine::SpriteRendererComponent" );
    spriteComponent->setName( "SpriteRenderer" );
    sprite->addComponent( qobject_cast<GluonEngine::Component*>( spriteComponent ) );

    project->addChild( new GluonCore::GluonObject( "Assets" ) );
    project->addChild( new GluonCore::GluonObject( "Prefabs" ) );

    KUrl location = d->location->url();
    QString gameBundleDir = GluonEngine::Asset::fullyQualifiedFileName( project.data(), QFileInfo( GluonEngine::projectSuffix ).completeSuffix() );
    location.addPath( gameBundleDir );
    project->setDirname( location );
    location.addPath( GluonEngine::projectFilename );
    project->setFilename( location );

    KUrl currentLocation = d->location->url();
    currentLocation.addPath( gameBundleDir );
    QDir dir = QDir( d->location->text() );
    dir.mkpath( gameBundleDir );
    QDir::setCurrent( currentLocation.toLocalFile() );
    project->saveToFile();

    return location.toLocalFile();
}

void NewProjectDialogPage::setForeground( QLabel* label, KColorScheme::ForegroundRole role )
{
    QPalette p = label->palette();
    KColorScheme::adjustForeground( p, role, label->foregroundRole(), KColorScheme::Window );
    label->setPalette( p );
}

void NewProjectDialogPage::validateByProjectName()
{
    validateData();
}

void NewProjectDialogPage::validateByProjectLocation()
{
    validateData();
}

void NewProjectDialogPage::validateData()
{
    KUrl url = d->location->url();
    if( !url.isLocalFile() || url.isEmpty() )
    {
        d->locationValidLabel->setText( i18n( "Invalid location" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    QString appName = d->name->text();

    if( appName.isEmpty() )
    {
        d->locationValidLabel->setText( i18n( "Empty project name" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    if( appName == "." || appName == ".." )
    {
        d->locationValidLabel->setText( i18n( "Invalid project name" ) );
        setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        emit validationFinished( false );
        return;
    }

    QDir tDir( url.toLocalFile( KUrl::RemoveTrailingSlash ) );
    while( !tDir.exists() && !tDir.isRoot() )
        tDir.setPath( pathUp( tDir.absolutePath() ) );

    if( tDir.exists() )
    {
        QFileInfo tFileInfo( tDir.absolutePath() );
        if( !tFileInfo.isWritable() || !tFileInfo.isExecutable() )
        {
            d->locationValidLabel->setText( i18n( "Unable to create subdirectories, "
                                                  "missing permissions on: %1", tDir.absolutePath() ) );
            setForeground( d->locationValidLabel, KColorScheme::NegativeText );
            emit validationFinished( false );
            return;
        }
    }

    d->locationValidLabel->setText( QString( " " ) );
    setForeground( d->locationValidLabel, KColorScheme::NormalText );
    emit validationFinished( true );

    // Check for non-empty target directory. Not an error, but need to display a warning.
    url.addPath( encodedAppName() );
    QFileInfo fi( url.toLocalFile( KUrl::RemoveTrailingSlash ) );
    if( fi.exists() && fi.isDir() )
    {
        if( !QDir( fi.absoluteFilePath() ).entryList( QDir::NoDotAndDotDot | QDir::AllEntries ).isEmpty() )
        {
            d->locationValidLabel->setText( i18n( "Path already exists and contains files" ) );
            setForeground( d->locationValidLabel, KColorScheme::NegativeText );
        }
    }
}

bool NewProjectDialogPage::isModified() const
{
    return ( !d->name->text().isEmpty() || !d->location->url().isEmpty() );
}

QByteArray NewProjectDialogPage::encodedAppName()
{
    // : < > * ? / \ | " are invalid on windows
    QByteArray tEncodedName = d->name->text().toUtf8();
    for( int i = 0; i < tEncodedName.size(); ++i )
    {
        QChar tChar( tEncodedName.at( i ) );
        if( tChar.isDigit() || tChar.isSpace() || tChar.isLetter() || tChar == '%' )
            continue;

        QByteArray tReplace = QUrl::toPercentEncoding( tChar );
        tEncodedName.replace( tEncodedName.at( i ) , tReplace );
        i =  i + tReplace.size() - 1;
    }
    return tEncodedName;
}

QString NewProjectDialogPage::pathUp( const QString& aPath )
{
    QString tPath = aPath;
    int tIndex = tPath.lastIndexOf( QDir::separator() );
    tPath = tPath.remove( tIndex, tPath.length() - tIndex );
    if( tPath == "" ) // ok, that seems to be root
        tPath = "/";

    return tPath;
}

<|endoftext|>


<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
#ifndef windows_platform
#include <sys/time.h>
#endif
#include "rodsPath.h"
#include "rodsErrorTable.h"
#include "rodsLog.h"
#include "miscUtil.h"
#include "phymvUtil.h"
#include "rcGlobalExtern.h"

int
phymvUtil( rcComm_t *conn, rodsEnv *myRodsEnv, rodsArguments_t *myRodsArgs,
           rodsPathInp_t *rodsPathInp ) {
    if ( rodsPathInp == NULL ) {
        return USER__NULL_INPUT_ERR;
    }

    dataObjInp_t dataObjInp;
    initCondForPhymv( myRodsEnv, myRodsArgs, &dataObjInp );

    int savedStatus = 0;
    for ( int i = 0; i < rodsPathInp->numSrc; i++ ) {
        if ( rodsPathInp->srcPath[i].objType == UNKNOWN_OBJ_T ) {
            getRodsObjType( conn, &rodsPathInp->srcPath[i] );
            if ( rodsPathInp->srcPath[i].objState == NOT_EXIST_ST ) {
                rodsLog( LOG_ERROR,
                         "phymvUtil: srcPath %s does not exist",
                         rodsPathInp->srcPath[i].outPath );
                savedStatus = USER_INPUT_PATH_ERR;
                continue;
            }
        }

        int status = 0;
        if ( rodsPathInp->srcPath[i].objType == DATA_OBJ_T ) {
            rmKeyVal( &dataObjInp.condInput, TRANSLATED_PATH_KW );
            status = phymvDataObjUtil( conn, rodsPathInp->srcPath[i].outPath,
                                       myRodsArgs, &dataObjInp );
        }
        else if ( rodsPathInp->srcPath[i].objType ==  COLL_OBJ_T ) {
            addKeyVal( &dataObjInp.condInput, TRANSLATED_PATH_KW, "" );
            status = phymvCollUtil( conn, rodsPathInp->srcPath[i].outPath,
                                    myRodsEnv, myRodsArgs, &dataObjInp );
        }
        else {
            /* should not be here */
            rodsLog( LOG_ERROR,
                     "phymvUtil: invalid phymv objType %d for %s",
                     rodsPathInp->srcPath[i].objType, rodsPathInp->srcPath[i].outPath );
            return USER_INPUT_PATH_ERR;
        }
        /* XXXX may need to return a global status */
        if ( status < 0 &&
                status != CAT_NO_ROWS_FOUND ) {
            rodsLogError( LOG_ERROR, status,
                          "phymvUtil: phymv error for %s, status = %d",
                          rodsPathInp->srcPath[i].outPath, status );
            savedStatus = status;
        }
    }
    return savedStatus;
}

int
phymvDataObjUtil( rcComm_t *conn, char *srcPath,
                  rodsArguments_t *rodsArgs, dataObjInp_t *dataObjInp ) {
    int status;
    struct timeval startTime, endTime;

    if ( srcPath == NULL ) {
        rodsLog( LOG_ERROR,
                 "phymvDataObjUtil: NULL srcPath input" );
        return USER__NULL_INPUT_ERR;
    }

    if ( rodsArgs->verbose == True ) {
        ( void ) gettimeofday( &startTime, ( struct timezone * )0 );
    }

    rstrcpy( dataObjInp->objPath, srcPath, MAX_NAME_LEN );

    status = rcDataObjPhymv( conn, dataObjInp );

    if ( status >= 0 && rodsArgs->verbose == True ) {
        ( void ) gettimeofday( &endTime, ( struct timezone * )0 );
        printTiming( conn, dataObjInp->objPath, conn->transStat.bytesWritten,
                     NULL, &startTime, &endTime );
    }

    return status;
}

int
initCondForPhymv( rodsEnv *myRodsEnv, rodsArguments_t *rodsArgs,
                  dataObjInp_t *dataObjInp ) {

    if ( dataObjInp == NULL ) {
        rodsLog( LOG_ERROR,
                 "initCondForPhymv: NULL dataObjInp input" );
        return USER__NULL_INPUT_ERR;
    }

    memset( dataObjInp, 0, sizeof( dataObjInp_t ) );

    if ( rodsArgs == NULL ) {
        return 0;
    }

    if ( rodsArgs->admin == True ) {
        addKeyVal( &dataObjInp->condInput, ADMIN_KW, "" );
    }

    if ( rodsArgs->replNum == True ) {
        addKeyVal( &dataObjInp->condInput, REPL_NUM_KW,
                   rodsArgs->replNumValue );
    }

    if ( rodsArgs->srcResc == True ) {
        addKeyVal( &dataObjInp->condInput, RESC_NAME_KW,
                   rodsArgs->srcRescString );
    }

    if ( rodsArgs->resource == True ) {
        if ( rodsArgs->resourceString == NULL ) {
            rodsLog( LOG_ERROR,
                     "initCondForPhymv: NULL resourceString error" );
            return USER__NULL_INPUT_ERR;
        }
        else {
            addKeyVal( &dataObjInp->condInput, DEST_RESC_NAME_KW,
                       rodsArgs->resourceString );
        }
    }
    else if ( myRodsEnv != NULL && strlen( myRodsEnv->rodsDefResource ) > 0 ) {
        addKeyVal( &dataObjInp->condInput, DEST_RESC_NAME_KW,
                   myRodsEnv->rodsDefResource );
    }

    return 0;
}

int
phymvCollUtil( rcComm_t *conn, char *srcColl, rodsEnv *myRodsEnv,
               rodsArguments_t *rodsArgs, dataObjInp_t *dataObjInp ) {
    int status;
    int savedStatus = 0;
    collHandle_t collHandle;
    collEnt_t collEnt;
    char srcChildPath[MAX_NAME_LEN];

    if ( srcColl == NULL ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: NULL srcColl input" );
        return USER__NULL_INPUT_ERR;
    }

    if ( rodsArgs->recursive != True ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: -r option must be used for getting %s collection",
                 srcColl );
        return USER_INPUT_OPTION_ERR;
    }

    if ( rodsArgs->verbose == True ) {
        fprintf( stdout, "C- %s:\n", srcColl );
    }

    status = rclOpenCollection( conn, srcColl, 0, &collHandle );
    if ( status < 0 ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: rclOpenCollection of %s error. status = %d",
                 srcColl, status );
        return status;
    }
    if ( collHandle.rodsObjStat->specColl != NULL &&
            collHandle.rodsObjStat->specColl->collClass != LINKED_COLL ) {
        /* no trim for mounted coll */
        rclCloseCollection( &collHandle );
        return 0;
    }
    while ( ( status = rclReadCollection( conn, &collHandle, &collEnt ) ) >= 0 ) {
        if ( collEnt.objType == DATA_OBJ_T ) {
            snprintf( srcChildPath, MAX_NAME_LEN, "%s/%s",
                      collEnt.collName, collEnt.dataName );

            status = phymvDataObjUtil( conn, srcChildPath,
                                       rodsArgs, dataObjInp );
            if ( status < 0 ) {
                rodsLogError( LOG_ERROR, status,
                              "phymvCollUtil: phymvDataObjUtil failed for %s. status = %d",
                              srcChildPath, status );
                /* need to set global error here */
                savedStatus = status;
                status = 0;
            }
        }
        else if ( collEnt.objType == COLL_OBJ_T ) {
            dataObjInp_t childDataObjInp;
            childDataObjInp = *dataObjInp;
            if ( collEnt.specColl.collClass != NO_SPEC_COLL ) {
                childDataObjInp.specColl = &collEnt.specColl;
            }
            status = phymvCollUtil( conn, collEnt.collName, myRodsEnv,
                                    rodsArgs, &childDataObjInp );
            if ( status < 0 && status != CAT_NO_ROWS_FOUND ) {
                savedStatus = status;
            }
        }
    }
    rclCloseCollection( &collHandle );

    if ( savedStatus < 0 ) {
        return savedStatus;
    }
    else if ( status == CAT_NO_ROWS_FOUND ) {
        return 0;
    }
    else {
        return status;
    }
}

<commit_msg>[#2815] '/' does not make sense as an argument to phymv<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
#ifndef windows_platform
#include <sys/time.h>
#endif
#include "rodsPath.h"
#include "rodsErrorTable.h"
#include "rodsLog.h"
#include "miscUtil.h"
#include "phymvUtil.h"
#include "rcGlobalExtern.h"

int
phymvUtil( rcComm_t *conn, rodsEnv *myRodsEnv, rodsArguments_t *myRodsArgs,
           rodsPathInp_t *rodsPathInp ) {
    if ( rodsPathInp == NULL ) {
        return USER__NULL_INPUT_ERR;
    }

    dataObjInp_t dataObjInp;
    initCondForPhymv( myRodsEnv, myRodsArgs, &dataObjInp );

    int savedStatus = 0;
    for ( int i = 0; i < rodsPathInp->numSrc; i++ ) {
        if ( strcmp("/", rodsPathInp->srcPath[i].outPath) == 0) {
            rodsLog(LOG_ERROR,
                    "phymvUtil: '/' does not specify a zone; "
                    "physical move only makes sense within a zone.");
            savedStatus = USER_INPUT_PATH_ERR;
            continue;
        }
        if ( rodsPathInp->srcPath[i].objType == UNKNOWN_OBJ_T ) {
            getRodsObjType( conn, &rodsPathInp->srcPath[i] );
            if ( rodsPathInp->srcPath[i].objState == NOT_EXIST_ST ) {
                rodsLog( LOG_ERROR,
                         "phymvUtil: srcPath %s does not exist",
                         rodsPathInp->srcPath[i].outPath );
                savedStatus = USER_INPUT_PATH_ERR;
                continue;
            }
        }

        int status = 0;
        if ( rodsPathInp->srcPath[i].objType == DATA_OBJ_T ) {
            rmKeyVal( &dataObjInp.condInput, TRANSLATED_PATH_KW );
            status = phymvDataObjUtil( conn, rodsPathInp->srcPath[i].outPath,
                                       myRodsArgs, &dataObjInp );
        }
        else if ( rodsPathInp->srcPath[i].objType ==  COLL_OBJ_T ) {
            addKeyVal( &dataObjInp.condInput, TRANSLATED_PATH_KW, "" );
            status = phymvCollUtil( conn, rodsPathInp->srcPath[i].outPath,
                                    myRodsEnv, myRodsArgs, &dataObjInp );
        }
        else {
            /* should not be here */
            rodsLog( LOG_ERROR,
                     "phymvUtil: invalid phymv objType %d for %s",
                     rodsPathInp->srcPath[i].objType, rodsPathInp->srcPath[i].outPath );
            return USER_INPUT_PATH_ERR;
        }
        /* XXXX may need to return a global status */
        if ( status < 0 &&
                status != CAT_NO_ROWS_FOUND ) {
            rodsLogError( LOG_ERROR, status,
                          "phymvUtil: phymv error for %s, status = %d",
                          rodsPathInp->srcPath[i].outPath, status );
            savedStatus = status;
        }
    }
    return savedStatus;
}

int
phymvDataObjUtil( rcComm_t *conn, char *srcPath,
                  rodsArguments_t *rodsArgs, dataObjInp_t *dataObjInp ) {
    int status;
    struct timeval startTime, endTime;

    if ( srcPath == NULL ) {
        rodsLog( LOG_ERROR,
                 "phymvDataObjUtil: NULL srcPath input" );
        return USER__NULL_INPUT_ERR;
    }

    if ( rodsArgs->verbose == True ) {
        ( void ) gettimeofday( &startTime, ( struct timezone * )0 );
    }

    rstrcpy( dataObjInp->objPath, srcPath, MAX_NAME_LEN );

    status = rcDataObjPhymv( conn, dataObjInp );

    if ( status >= 0 && rodsArgs->verbose == True ) {
        ( void ) gettimeofday( &endTime, ( struct timezone * )0 );
        printTiming( conn, dataObjInp->objPath, conn->transStat.bytesWritten,
                     NULL, &startTime, &endTime );
    }

    return status;
}

int
initCondForPhymv( rodsEnv *myRodsEnv, rodsArguments_t *rodsArgs,
                  dataObjInp_t *dataObjInp ) {

    if ( dataObjInp == NULL ) {
        rodsLog( LOG_ERROR,
                 "initCondForPhymv: NULL dataObjInp input" );
        return USER__NULL_INPUT_ERR;
    }

    memset( dataObjInp, 0, sizeof( dataObjInp_t ) );

    if ( rodsArgs == NULL ) {
        return 0;
    }

    if ( rodsArgs->admin == True ) {
        addKeyVal( &dataObjInp->condInput, ADMIN_KW, "" );
    }

    if ( rodsArgs->replNum == True ) {
        addKeyVal( &dataObjInp->condInput, REPL_NUM_KW,
                   rodsArgs->replNumValue );
    }

    if ( rodsArgs->srcResc == True ) {
        addKeyVal( &dataObjInp->condInput, RESC_NAME_KW,
                   rodsArgs->srcRescString );
    }

    if ( rodsArgs->resource == True ) {
        if ( rodsArgs->resourceString == NULL ) {
            rodsLog( LOG_ERROR,
                     "initCondForPhymv: NULL resourceString error" );
            return USER__NULL_INPUT_ERR;
        }
        else {
            addKeyVal( &dataObjInp->condInput, DEST_RESC_NAME_KW,
                       rodsArgs->resourceString );
        }
    }
    else if ( myRodsEnv != NULL && strlen( myRodsEnv->rodsDefResource ) > 0 ) {
        addKeyVal( &dataObjInp->condInput, DEST_RESC_NAME_KW,
                   myRodsEnv->rodsDefResource );
    }

    return 0;
}

int
phymvCollUtil( rcComm_t *conn, char *srcColl, rodsEnv *myRodsEnv,
               rodsArguments_t *rodsArgs, dataObjInp_t *dataObjInp ) {
    int status;
    int savedStatus = 0;
    collHandle_t collHandle;
    collEnt_t collEnt;
    char srcChildPath[MAX_NAME_LEN];

    if ( srcColl == NULL ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: NULL srcColl input" );
        return USER__NULL_INPUT_ERR;
    }

    if ( rodsArgs->recursive != True ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: -r option must be used for getting %s collection",
                 srcColl );
        return USER_INPUT_OPTION_ERR;
    }

    if ( rodsArgs->verbose == True ) {
        fprintf( stdout, "C- %s:\n", srcColl );
    }

    status = rclOpenCollection( conn, srcColl, 0, &collHandle );
    if ( status < 0 ) {
        rodsLog( LOG_ERROR,
                 "phymvCollUtil: rclOpenCollection of %s error. status = %d",
                 srcColl, status );
        return status;
    }
    if ( collHandle.rodsObjStat->specColl != NULL &&
            collHandle.rodsObjStat->specColl->collClass != LINKED_COLL ) {
        /* no trim for mounted coll */
        rclCloseCollection( &collHandle );
        return 0;
    }
    while ( ( status = rclReadCollection( conn, &collHandle, &collEnt ) ) >= 0 ) {
        if ( collEnt.objType == DATA_OBJ_T ) {
            snprintf( srcChildPath, MAX_NAME_LEN, "%s/%s",
                      collEnt.collName, collEnt.dataName );

            status = phymvDataObjUtil( conn, srcChildPath,
                                       rodsArgs, dataObjInp );
            if ( status < 0 ) {
                rodsLogError( LOG_ERROR, status,
                              "phymvCollUtil: phymvDataObjUtil failed for %s. status = %d",
                              srcChildPath, status );
                /* need to set global error here */
                savedStatus = status;
                status = 0;
            }
        }
        else if ( collEnt.objType == COLL_OBJ_T ) {
            dataObjInp_t childDataObjInp;
            childDataObjInp = *dataObjInp;
            if ( collEnt.specColl.collClass != NO_SPEC_COLL ) {
                childDataObjInp.specColl = &collEnt.specColl;
            }
            status = phymvCollUtil( conn, collEnt.collName, myRodsEnv,
                                    rodsArgs, &childDataObjInp );
            if ( status < 0 && status != CAT_NO_ROWS_FOUND ) {
                savedStatus = status;
            }
        }
    }
    rclCloseCollection( &collHandle );

    if ( savedStatus < 0 ) {
        return savedStatus;
    }
    else if ( status == CAT_NO_ROWS_FOUND ) {
        return 0;
    }
    else {
        return status;
    }
}

<|endoftext|>


<commit_before>/*
 * opencog/atoms/base/Link.cc
 *
 * Copyright (C) 2008-2010 OpenCog Foundation
 * Copyright (C) 2002-2007 Novamente LLC
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <stdio.h>

#include <opencog/util/exceptions.h>
#include <opencog/util/Logger.h>

#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/atomspace/AtomTable.h>

#include <boost/range/algorithm.hpp>

#include "Link.h"

//#define DPRINTF printf
#define DPRINTF(...)

using namespace opencog;

void Link::resort(void)
{
    // Caution: this comparison function MUST BE EXACTLY THE SAME as
    // the one in AtomTable.cc, used for Unordered links. Changing
    // this without changing the other one will break things!
    std::sort(_outgoing.begin(), _outgoing.end(), handle_less());
}

void Link::init(const HandleSeq& outgoingVector)
{
    if (not classserver().isA(_type, LINK)) {
        throw InvalidParamException(TRACE_INFO,
            "Link ctor: Atom type is not a Link: '%d' %s.",
            _type, classserver().getTypeName(_type).c_str());
    }

    _outgoing = outgoingVector;
    // If the link is unordered, it will be normalized by sorting the
    // elements in the outgoing list.
    if (classserver().isA(_type, UNORDERED_LINK)) {
        resort();
    }
}

Link::~Link()
{
    DPRINTF("Deleting link:\n%s\n", this->toString().c_str());
}

std::string Link::toShortString(const std::string& indent)
{
    std::stringstream answer;
    std::string more_indent = indent + "  ";

    answer << indent << "(" << classserver().getTypeName(_type);
    if (not getTruthValue()->isDefaultTV())
        answer << " " << getTruthValue()->toString();
    answer << "\n";

    // Here the target string is made. If a target is a node, its name is
    // concatenated. If it's a link, all its properties are concatenated.
    for (const Handle& h : _outgoing) {
        if (h.operator->() != NULL)
            answer << h->toShortString(more_indent);
        else
            answer << more_indent << "Undefined Atom!\n";
    }

    answer << indent << ") ; [" << _uuid << "]";

    if (_atomTable)
        answer << "[" << _atomTable->get_uuid() << "]\n";
    else
        answer << "[NULL]\n";

    return answer.str();
}

std::string Link::toString(const std::string& indent)
{
    std::string answer = indent;
    std::string more_indent = indent + "  ";

    answer += "(" + classserver().getTypeName(_type);

    // Print the TV and AV only if its not the default.
    if (not getAttentionValue()->isDefaultAV())
        answer += " (av " +
             std::to_string(getAttentionValue()->getSTI()) + " " +
             std::to_string(getAttentionValue()->getLTI()) + " " +
             std::to_string(getAttentionValue()->getVLTI()) + ")";

    if (not getTruthValue()->isDefaultTV())
        answer += " " + getTruthValue()->toString();

    answer += "\n";
    // Here, the outset string is made. If a target is a node,
    // its name is concatenated. If it's a link, then recurse.
    for (const Handle& h : _outgoing) {
        if (h.operator->() != NULL)
            answer += h->toString(more_indent);
        else
            answer += more_indent + "Undefined Atom!\n";
    }

    answer += indent + ") ; [" +
            std::to_string(_uuid) + "][" +
            std::to_string(_atomTable? _atomTable->get_uuid() : -1) +
            "]\n";

    return answer;
}

bool Link::operator==(const Atom& other) const
{
    if (getType() != other.getType()) return false;
    const Link& olink = dynamic_cast<const Link&>(other);

    Arity arity = getArity();
    if (arity != olink.getArity()) return false;

    // If the type is unordered and one of the uuids are invalid we
    // need to reorder by content to be sure that the children are
    // aligned.
    if (classserver().isA(getType(), UNORDERED_LINK) and
        (_uuid != Handle::INVALID_UUID
         or other.getUUID() != Handle::INVALID_UUID))
    {
        HandleSeq sorted_outgoing(_outgoing),
            sorted_other_outgoing(olink._outgoing);
        boost::sort(sorted_outgoing, content_based_handle_less());
        boost::sort(sorted_other_outgoing, content_based_handle_less());
        return outgoings_equal(sorted_outgoing, sorted_other_outgoing);
    }

    // No need to reorder, compare the children directly
    return outgoings_equal(_outgoing, olink._outgoing);
}

bool Link::outgoings_equal(const HandleSeq& lhs, const HandleSeq& rhs)
{
    for (Arity i = 0; i < lhs.size(); i++)
    {
        if (lhs[i]->getType() != rhs[i]->getType())
            return false;

        if (lhs[i]->isNode())
        {
            NodePtr tn(NodeCast(lhs[i]));
            NodePtr on(NodeCast(rhs[i]));
            if (*tn != *on) return false;
        }
        else if (lhs[i]->isLink())
        {
            LinkPtr tl(LinkCast(lhs[i]));
            LinkPtr ol(LinkCast(rhs[i]));
            if (*tl != *ol) return false;
        }
        // if (lhs[i] != rhs[i])
        //     return false;
    }
    return true;
}

bool Link::operator<(const Atom& other) const
{
    if (getType() == other.getType()) {
        const HandleSeq& outgoing = getOutgoingSet();
        const HandleSeq& other_outgoing = other.getOutgoingSet();
        Arity arity = outgoing.size();
        Arity other_arity = other_outgoing.size();
        if (arity == other_arity) {
            Arity i = 0;
            while (i < arity) {
                Handle ll = outgoing[i];
                Handle rl = other_outgoing[i];
                if (ll == rl)
                    i++;
                else
                    return ll->operator<(*rl.atom_ptr());
            }
            return false;
        } else
            return arity < other_arity;
    } else
        return getType() < other.getType();
}
<commit_msg>More sensible variable renaming<commit_after>/*
 * opencog/atoms/base/Link.cc
 *
 * Copyright (C) 2008-2010 OpenCog Foundation
 * Copyright (C) 2002-2007 Novamente LLC
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <stdio.h>

#include <opencog/util/exceptions.h>
#include <opencog/util/Logger.h>

#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/atomspace/AtomTable.h>

#include <boost/range/algorithm.hpp>

#include "Link.h"

//#define DPRINTF printf
#define DPRINTF(...)

using namespace opencog;

void Link::resort(void)
{
    // Caution: this comparison function MUST BE EXACTLY THE SAME as
    // the one in AtomTable.cc, used for Unordered links. Changing
    // this without changing the other one will break things!
    std::sort(_outgoing.begin(), _outgoing.end(), handle_less());
}

void Link::init(const HandleSeq& outgoingVector)
{
    if (not classserver().isA(_type, LINK)) {
        throw InvalidParamException(TRACE_INFO,
            "Link ctor: Atom type is not a Link: '%d' %s.",
            _type, classserver().getTypeName(_type).c_str());
    }

    _outgoing = outgoingVector;
    // If the link is unordered, it will be normalized by sorting the
    // elements in the outgoing list.
    if (classserver().isA(_type, UNORDERED_LINK)) {
        resort();
    }
}

Link::~Link()
{
    DPRINTF("Deleting link:\n%s\n", this->toString().c_str());
}

std::string Link::toShortString(const std::string& indent)
{
    std::stringstream answer;
    std::string more_indent = indent + "  ";

    answer << indent << "(" << classserver().getTypeName(_type);
    if (not getTruthValue()->isDefaultTV())
        answer << " " << getTruthValue()->toString();
    answer << "\n";

    // Here the target string is made. If a target is a node, its name is
    // concatenated. If it's a link, all its properties are concatenated.
    for (const Handle& h : _outgoing) {
        if (h.operator->() != NULL)
            answer << h->toShortString(more_indent);
        else
            answer << more_indent << "Undefined Atom!\n";
    }

    answer << indent << ") ; [" << _uuid << "]";

    if (_atomTable)
        answer << "[" << _atomTable->get_uuid() << "]\n";
    else
        answer << "[NULL]\n";

    return answer.str();
}

std::string Link::toString(const std::string& indent)
{
    std::string answer = indent;
    std::string more_indent = indent + "  ";

    answer += "(" + classserver().getTypeName(_type);

    // Print the TV and AV only if its not the default.
    if (not getAttentionValue()->isDefaultAV())
        answer += " (av " +
             std::to_string(getAttentionValue()->getSTI()) + " " +
             std::to_string(getAttentionValue()->getLTI()) + " " +
             std::to_string(getAttentionValue()->getVLTI()) + ")";

    if (not getTruthValue()->isDefaultTV())
        answer += " " + getTruthValue()->toString();

    answer += "\n";
    // Here, the outset string is made. If a target is a node,
    // its name is concatenated. If it's a link, then recurse.
    for (const Handle& h : _outgoing) {
        if (h.operator->() != NULL)
            answer += h->toString(more_indent);
        else
            answer += more_indent + "Undefined Atom!\n";
    }

    answer += indent + ") ; [" +
            std::to_string(_uuid) + "][" +
            std::to_string(_atomTable? _atomTable->get_uuid() : -1) +
            "]\n";

    return answer;
}

bool Link::operator==(const Atom& other) const
{
    if (getType() != other.getType()) return false;
    const Link& olink = dynamic_cast<const Link&>(other);

    Arity arity = getArity();
    if (arity != olink.getArity()) return false;

    // If the type is unordered and one of the uuids are invalid we
    // need to reorder by content to be sure that the children are
    // aligned.
    if (classserver().isA(getType(), UNORDERED_LINK) and
        (_uuid != Handle::INVALID_UUID
         or other.getUUID() != Handle::INVALID_UUID))
    {
        HandleSeq sorted_outgoing(_outgoing),
            other_sorted_outgoing(olink._outgoing);
        boost::sort(sorted_outgoing, content_based_handle_less());
        boost::sort(other_sorted_outgoing, content_based_handle_less());
        return outgoings_equal(sorted_outgoing, other_sorted_outgoing);
    }

    // No need to reorder, compare the children directly
    return outgoings_equal(_outgoing, olink._outgoing);
}

bool Link::outgoings_equal(const HandleSeq& lhs, const HandleSeq& rhs)
{
    for (Arity i = 0; i < lhs.size(); i++)
    {
        if (lhs[i]->getType() != rhs[i]->getType())
            return false;

        if (lhs[i]->isNode())
        {
            NodePtr tn(NodeCast(lhs[i]));
            NodePtr on(NodeCast(rhs[i]));
            if (*tn != *on) return false;
        }
        else if (lhs[i]->isLink())
        {
            LinkPtr tl(LinkCast(lhs[i]));
            LinkPtr ol(LinkCast(rhs[i]));
            if (*tl != *ol) return false;
        }
        // if (lhs[i] != rhs[i])
        //     return false;
    }
    return true;
}

bool Link::operator<(const Atom& other) const
{
    if (getType() == other.getType()) {
        const HandleSeq& outgoing = getOutgoingSet();
        const HandleSeq& other_outgoing = other.getOutgoingSet();
        Arity arity = outgoing.size();
        Arity other_arity = other_outgoing.size();
        if (arity == other_arity) {
            Arity i = 0;
            while (i < arity) {
                Handle ll = outgoing[i];
                Handle rl = other_outgoing[i];
                if (ll == rl)
                    i++;
                else
                    return ll->operator<(*rl.atom_ptr());
            }
            return false;
        } else
            return arity < other_arity;
    } else
        return getType() < other.getType();
}
<|endoftext|>


<commit_before>/*
 * This file is part of the statismo library.
 *
 * Author: Marcel Luethi (marcel.luethi@unibas.ch)
 *
 * Copyright (c) 2011 University of Basel
 * All rights reserved.
 *
 * Statismo is licensed under the BSD licence (3 clause) license
 */

#include "LowRankGPModelBuilder.h"
#include "StatisticalModel.h"
#include "vtkPolyDataReader.h"
#include "vtkStandardMeshRepresenter.h"
#include "Kernels.h"
#include "KernelCombinators.h"

#include <iostream>
#include <memory>

using namespace statismo;

/*
 * We use a sum of gaussian kernels as our main model.
 */
class MultiscaleGaussianKernel: public MatrixValuedKernel<vtkPoint> {
  public:

    MultiscaleGaussianKernel(float baseWidth, float baseScale, unsigned nLevels) : m_baseWidth(baseWidth), m_baseScale(baseScale), m_nLevels(nLevels), MatrixValuedKernel<vtkPoint>(3) {
    }

    inline MatrixType operator()(const vtkPoint& x, const vtkPoint& y) const {
        VectorType r(3);
        r << x[0] - y[0], x[1] - y[1], x[2] - y[2];

        const float minusRDotR = - r.dot(r);

        float kernelValue = 0.;
        for (unsigned l = 1 ; l <= m_nLevels; ++l) {
            const float scaleOnLevel = m_baseScale / static_cast< float >( l );
            const float widthOnLevel = m_baseWidth / static_cast< float >( l );
            kernelValue += scaleOnLevel * std::exp( minusRDotR / (widthOnLevel * widthOnLevel));
        }
        return statismo::MatrixType::Identity(3,3) * kernelValue;
    }

    std::string GetKernelInfo() const {
        std::ostringstream os;
        os << "Multiscale GaussianKernel";
        return os.str();
    }

  private:

    float m_baseWidth;
    float m_baseScale;
    unsigned m_nLevels;
};

// load a mesh
vtkPolyData* loadVTKPolyData(const std::string& filename) {
    vtkPolyDataReader* reader = vtkPolyDataReader::New();
    reader->SetFileName(filename.c_str());
    reader->Update();
    vtkPolyData* pd = vtkPolyData::New();
    pd->ShallowCopy(reader->GetOutput());
    reader->Delete();
    return pd;
}

// compute the center of mass for the given mesh
vtkPoint centerOfMass(const vtkPolyData* _pd) {

    // vtk is not const-correct, but we will not mutate pd here;
    vtkPolyData* pd = const_cast<vtkPolyData*>(_pd);

    vtkIdType numPoints = pd->GetNumberOfPoints();
    vtkPoint centerOfMass(0.0, 0.0, 0.0);
    for (vtkIdType i = 0; i < numPoints; ++i) {
        double *ithPoint = pd->GetPoint(i);
        for (unsigned d = 0; d < 3; ++d) {
            centerOfMass[d] += ithPoint[d];
        }
    }
    double V = 1.0 / static_cast<double>(numPoints);
    for (unsigned d = 0; d < 3; ++d) {
        centerOfMass[d] * V;
    }
    return centerOfMass;
}

// As an example of a tempering function, we use a function which is more smooth for points whose
// x-component is smaller than the x-component of the center of mass. To achieve a smooth transition between the areas, we use a sigmoid function.
// The variable a controls how fast the value of the tempering function changes from 0 to 1.
struct MyTemperingFunction : public TemperingFunction<vtkPoint> {
    MyTemperingFunction(const vtkPoint& centerOfMass) : m_centerOfMass(centerOfMass) {}

    static const double a;
    double operator() (const vtkPoint& pt) const {
        double xDiffToCenter =  m_centerOfMass[0] - pt[0];
        return  (1.0 / ( 1.0 + std::exp(-xDiffToCenter * a)) + 1.0) ;
    }

  private:
    vtkPoint m_centerOfMass;
};
const double MyTemperingFunction::a = 0.5;

//
// Computes a multi-scale gaussian model and uses spatial tempering to make the smoothness spatially varying.
//
// For mathematical details of this procedure, refer to the paper:
// T. Gerig, K. Shahim, M. Reyes, T. Vetter, M. Luethi, Spatially-varying registration using Gaussian Processes.
//
int main(int argc, char** argv) {

    if (argc < 7) {
        std::cerr << "Usage " << argv[0] << " referenceMesh baseKernelWidth baseScale numLevels numberOfComponents outputmodelName" << std::endl;
        return EXIT_FAILURE;
    }
    std::string refFilename(argv[1]);
    double baseKernelWidth = std::atof(argv[2]);
    double baseScale = std::atof(argv[3]);
    unsigned numLevels = std::atoi(argv[4]);
    int numberOfComponents = std::atoi(argv[5]);
    std::string outputModelFilename(argv[6]);

    // All the statismo classes have to be parameterized with the RepresenterType.

    typedef vtkStandardMeshRepresenter RepresenterType;
    typedef LowRankGPModelBuilder<vtkPolyData> ModelBuilderType;
    typedef StatisticalModel<vtkPolyData> StatisticalModelType;
    typedef MultiscaleGaussianKernel GaussianKernelType;
    typedef MatrixValuedKernel<vtkPoint> MatrixValuedKernelType;

    try {

        vtkPolyData* referenceMesh = loadVTKPolyData(refFilename);
        vtkStandardMeshRepresenter* representer = vtkStandardMeshRepresenter::Create(referenceMesh);

        MultiscaleGaussianKernel gk = MultiscaleGaussianKernel(baseKernelWidth, baseScale, numLevels);

        MyTemperingFunction temperingFun(centerOfMass(referenceMesh));

        SpatiallyVaryingKernel<RepresenterType::DatasetType> temperedKernel(representer, gk, temperingFun , numberOfComponents,  numberOfComponents * 2, true);

        // We create a new model using the combined kernel. The new model will be more flexible than the original statistical model.
        ModelBuilderType* modelBuilder = ModelBuilderType::Create(representer);

        StatisticalModelType* newModel = modelBuilder->BuildNewModel(referenceMesh, temperedKernel, numberOfComponents);

        // Once we have built the model, we can save it to disk.
        newModel->Save(outputModelFilename);
        std::cout << "Successfully saved shape model as " << outputModelFilename << std::endl;

        referenceMesh->Delete();
        representer->Delete();
        modelBuilder->Delete();
        newModel->Delete();

    } catch (StatisticalModelException& e) {
        std::cerr << "Exception occured while building the shape model" << std::endl;
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<commit_msg>fix the following warning<commit_after>/*
 * This file is part of the statismo library.
 *
 * Author: Marcel Luethi (marcel.luethi@unibas.ch)
 *
 * Copyright (c) 2011 University of Basel
 * All rights reserved.
 *
 * Statismo is licensed under the BSD licence (3 clause) license
 */

#include "LowRankGPModelBuilder.h"
#include "StatisticalModel.h"
#include "vtkPolyDataReader.h"
#include "vtkStandardMeshRepresenter.h"
#include "Kernels.h"
#include "KernelCombinators.h"

#include <iostream>
#include <memory>

using namespace statismo;

/*
 * We use a sum of gaussian kernels as our main model.
 */
class MultiscaleGaussianKernel: public MatrixValuedKernel<vtkPoint> {
  public:

    MultiscaleGaussianKernel(float baseWidth, float baseScale, unsigned nLevels) : m_baseWidth(baseWidth), m_baseScale(baseScale), m_nLevels(nLevels), MatrixValuedKernel<vtkPoint>(3) {
    }

    inline MatrixType operator()(const vtkPoint& x, const vtkPoint& y) const {
        VectorType r(3);
        r << x[0] - y[0], x[1] - y[1], x[2] - y[2];

        const float minusRDotR = - r.dot(r);

        float kernelValue = 0.;
        for (unsigned l = 1 ; l <= m_nLevels; ++l) {
            const float scaleOnLevel = m_baseScale / static_cast< float >( l );
            const float widthOnLevel = m_baseWidth / static_cast< float >( l );
            kernelValue += scaleOnLevel * std::exp( minusRDotR / (widthOnLevel * widthOnLevel));
        }
        return statismo::MatrixType::Identity(3,3) * kernelValue;
    }

    std::string GetKernelInfo() const {
        std::ostringstream os;
        os << "Multiscale GaussianKernel";
        return os.str();
    }

  private:

    float m_baseWidth;
    float m_baseScale;
    unsigned m_nLevels;
};

// load a mesh
vtkPolyData* loadVTKPolyData(const std::string& filename) {
    vtkPolyDataReader* reader = vtkPolyDataReader::New();
    reader->SetFileName(filename.c_str());
    reader->Update();
    vtkPolyData* pd = vtkPolyData::New();
    pd->ShallowCopy(reader->GetOutput());
    reader->Delete();
    return pd;
}

// compute the center of mass for the given mesh
vtkPoint centerOfMass(const vtkPolyData* _pd) {

    // vtk is not const-correct, but we will not mutate pd here;
    vtkPolyData* pd = const_cast<vtkPolyData*>(_pd);

    vtkIdType numPoints = pd->GetNumberOfPoints();
    vtkPoint centerOfMass(0.0, 0.0, 0.0);
    for (vtkIdType i = 0; i < numPoints; ++i) {
        double *ithPoint = pd->GetPoint(i);
        for (unsigned d = 0; d < 3; ++d) {
            centerOfMass[d] += ithPoint[d];
        }
    }
    double V = 1.0 / static_cast<double>(numPoints);
    for (unsigned d = 0; d < 3; ++d) {
        centerOfMass[d] *= V;
    }
    return centerOfMass;
}

// As an example of a tempering function, we use a function which is more smooth for points whose
// x-component is smaller than the x-component of the center of mass. To achieve a smooth transition between the areas, we use a sigmoid function.
// The variable a controls how fast the value of the tempering function changes from 0 to 1.
struct MyTemperingFunction : public TemperingFunction<vtkPoint> {
    MyTemperingFunction(const vtkPoint& centerOfMass) : m_centerOfMass(centerOfMass) {}

    static const double a;
    double operator() (const vtkPoint& pt) const {
        double xDiffToCenter =  m_centerOfMass[0] - pt[0];
        return  (1.0 / ( 1.0 + std::exp(-xDiffToCenter * a)) + 1.0) ;
    }

  private:
    vtkPoint m_centerOfMass;
};
const double MyTemperingFunction::a = 0.5;

//
// Computes a multi-scale gaussian model and uses spatial tempering to make the smoothness spatially varying.
//
// For mathematical details of this procedure, refer to the paper:
// T. Gerig, K. Shahim, M. Reyes, T. Vetter, M. Luethi, Spatially-varying registration using Gaussian Processes.
//
int main(int argc, char** argv) {

    if (argc < 7) {
        std::cerr << "Usage " << argv[0] << " referenceMesh baseKernelWidth baseScale numLevels numberOfComponents outputmodelName" << std::endl;
        return EXIT_FAILURE;
    }
    std::string refFilename(argv[1]);
    double baseKernelWidth = std::atof(argv[2]);
    double baseScale = std::atof(argv[3]);
    unsigned numLevels = std::atoi(argv[4]);
    int numberOfComponents = std::atoi(argv[5]);
    std::string outputModelFilename(argv[6]);

    // All the statismo classes have to be parameterized with the RepresenterType.

    typedef vtkStandardMeshRepresenter RepresenterType;
    typedef LowRankGPModelBuilder<vtkPolyData> ModelBuilderType;
    typedef StatisticalModel<vtkPolyData> StatisticalModelType;
    typedef MultiscaleGaussianKernel GaussianKernelType;
    typedef MatrixValuedKernel<vtkPoint> MatrixValuedKernelType;

    try {

        vtkPolyData* referenceMesh = loadVTKPolyData(refFilename);
        vtkStandardMeshRepresenter* representer = vtkStandardMeshRepresenter::Create(referenceMesh);

        MultiscaleGaussianKernel gk = MultiscaleGaussianKernel(baseKernelWidth, baseScale, numLevels);

        MyTemperingFunction temperingFun(centerOfMass(referenceMesh));

        SpatiallyVaryingKernel<RepresenterType::DatasetType> temperedKernel(representer, gk, temperingFun , numberOfComponents,  numberOfComponents * 2, true);

        // We create a new model using the combined kernel. The new model will be more flexible than the original statistical model.
        ModelBuilderType* modelBuilder = ModelBuilderType::Create(representer);

        StatisticalModelType* newModel = modelBuilder->BuildNewModel(referenceMesh, temperedKernel, numberOfComponents);

        // Once we have built the model, we can save it to disk.
        newModel->Save(outputModelFilename);
        std::cout << "Successfully saved shape model as " << outputModelFilename << std::endl;

        referenceMesh->Delete();
        representer->Delete();
        modelBuilder->Delete();
        newModel->Delete();

    } catch (StatisticalModelException& e) {
        std::cerr << "Exception occured while building the shape model" << std::endl;
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXOpenGLTextMapper.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkXOpenGLTextMapper.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include "vtkObjectFactory.h"
#include "vtkgluPickMatrix.h"

//--------------------------------------------------------------------------
vtkXOpenGLTextMapper* vtkXOpenGLTextMapper::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkXOpenGLTextMapper");
  if(ret)
    {
    return (vtkXOpenGLTextMapper*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkXOpenGLTextMapper;
}

struct vtkFontStruct
{
  vtkWindow *Window;
  int   Italic;
  int	Bold;
  int   FontSize;
  int   FontFamily;
  int   ListBase;
  GLXContext ContextId;
};

static vtkFontStruct *cache[30] = {
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL};
static int numCached = 0;

int vtkXOpenGLTextMapper::GetListBaseForFont(vtkTextMapper *tm,
					     vtkViewport *vp,
					     Font CurrentFont)
{
  int i, j;
  vtkWindow *win = vp->GetVTKWindow();

  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win &&
	cache[i]->Italic == tm->GetItalic() &&
	cache[i]->Bold == tm->GetBold() &&
	cache[i]->FontSize == tm->GetFontSize() &&
	cache[i]->FontFamily == tm->GetFontFamily())
      {
      // make this the most recently used
      if (i != 0)
	{
	vtkFontStruct *tmp = cache[i];
	for (j = i-1; j >= 0; j--)
	  {
	  cache[j+1] = cache[j];
	  }
	cache[0] = tmp;
	}
      return cache[0]->ListBase;
      }
    }

  // save the current context
  GLXContext ctx = glXGetCurrentContext();

  // OK the font is not cached
  // so we need to make room for a new font
  if (numCached == 30)
    {
    glXMakeCurrent((Display *)cache[29]->Window->GetGenericDisplayId(),
		   (Window)cache[29]->Window->GetGenericWindowId(),
		   cache[29]->ContextId);
    glDeleteLists(cache[29]->ListBase,255);
    glXMakeCurrent((Display *)win->GetGenericDisplayId(),
		   (Window)win->GetGenericWindowId(), ctx);
    numCached = 29;
    }

  // add the new font
  if (!cache[numCached])
    {
    cache[numCached] = new vtkFontStruct;
    int done = 0;
    cache[numCached]->ListBase = 1000;
    do
      {
      done = 1;
      cache[numCached]->ListBase += 260;
      for (i = 0; i < numCached; i++)
	{
	if (cache[i]->ListBase == cache[numCached]->ListBase)
	  {
	  done = 0;
	  }
	}
      }
    while (!done);
    }

  // set the other info and build the font
  cache[numCached]->Window = win;
  cache[numCached]->Italic = tm->GetItalic();
  cache[numCached]->Bold = tm->GetBold();
  cache[numCached]->FontSize = tm->GetFontSize();
  cache[numCached]->FontFamily = tm->GetFontFamily();
  cache[numCached]->ContextId = ctx;
  glXUseXFont(CurrentFont, 0, 255, cache[numCached]->ListBase);

  // now resort the list
  vtkFontStruct *tmp = cache[numCached];
  for (i = numCached-1; i >= 0; i--)
    {
    cache[i+1] = cache[i];
    }
  cache[0] = tmp;
  numCached++;
  return cache[0]->ListBase;
}

void vtkXOpenGLTextMapper::ReleaseGraphicsResources(vtkWindow *win)
{
  int i,j;

  // free up any cached font associated with this window
  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win)
      {
      glDeleteLists(cache[i]->ListBase,255);
      delete cache[i];
      // resort them
      numCached--;
      for (j = i; j < numCached; j++)
	{
	cache[j] = cache[j+1];
	}
      cache[numCached] = NULL;
      }
    }
  this->LastWindow = NULL;
}

vtkXOpenGLTextMapper::vtkXOpenGLTextMapper()
{
}

vtkXOpenGLTextMapper::~vtkXOpenGLTextMapper()
{
  if (this->LastWindow)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
}

void vtkXOpenGLTextMapper::RenderOpaqueGeometry(vtkViewport* viewport,
						vtkActor2D* actor)
{
  vtkDebugMacro (<< "RenderOpaqueGeometry");

  // turn off texturing in case it is on
  glDisable( GL_TEXTURE_2D );

  // Get the window information for display
  vtkWindow*  window = viewport->GetVTKWindow();
  if (this->LastWindow && this->LastWindow != window)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
  this->LastWindow = window;

  // Check for input
  if ( this->NumberOfLines > 1 )
    {
    this->RenderOpaqueGeometryMultipleLines(viewport, actor);
    return;
    }

  // Check for input
  if (this->Input == NULL || this->Input[0] == '\0')
    {
    vtkDebugMacro (<<"Render - No input");
    return;
    }

  int size[2];
  this->GetSize(viewport, size);

  // Get the position of the text actor
  int* actorPos =
    actor->GetPositionCoordinate()->GetComputedViewportValue(viewport);

  // Set up the font color from the text actor
  unsigned char red = 0;
  unsigned char green = 0;
  unsigned char blue = 0;
  float*  actorColor = actor->GetProperty()->GetColor();
  red = (unsigned char) (actorColor[0] * 255.0);
  green = (unsigned char) (actorColor[1] * 255.0);
  blue = (unsigned char) (actorColor[2] * 255.0);

  // Set up the shadow color
  float intensity;
  intensity = (red + green + blue)/3.0;

  unsigned char shadowRed, shadowGreen, shadowBlue;
  if (intensity > 128)
    {
    shadowRed = shadowBlue = shadowGreen = 0;
    }
  else
    {
    shadowRed = shadowBlue = shadowGreen = 255;
    }

  int pos[2];
  pos[0] = actorPos[0];
  pos[1] = (int)(actorPos[1] - this->LineOffset);

  switch (this->Justification)
    {
    case VTK_TEXT_LEFT: break;
    case VTK_TEXT_CENTERED:
      pos[0] = pos[0] - size[0]/2;
      break;
    case VTK_TEXT_RIGHT:
      pos[0] = pos[0] - size[0];
      break;
    }
  switch (this->VerticalJustification)
    {
    case VTK_TEXT_TOP:
      pos[1] = pos[1] - size[1];
      break;
    case VTK_TEXT_CENTERED:
      pos[1] = pos[1] - size[1]/2;
      break;
    case VTK_TEXT_BOTTOM:
      break;
    }

  // push a 2D matrix on the stack
  int *vsize = viewport->GetSize();
  glMatrixMode( GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  if(viewport->GetIsPicking())
    {
    vtkgluPickMatrix(viewport->GetPickX(), viewport->GetPickY(),
		     1, 1, viewport->GetOrigin(), viewport->GetSize());
    }
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();
  glDisable( GL_LIGHTING);

  int front =
    (actor->GetProperty()->GetDisplayLocation() == VTK_FOREGROUND_LOCATION);

  // When picking draw the bounds of the text as a rectangle,
  // as text only picks when the pick point is exactly on the
  // origin of the text
  if(viewport->GetIsPicking())
    {
    float x1 = (2.0*(float)actorPos[0] / vsize[0] - 1);
    float y1 = (2.0*((float)actorPos[1] - this->LineOffset) / vsize[1] - 1);
    float width = 2.0*(float)size[0]/vsize[0];
    float height = 2.0*(float)size[1]/vsize[1];
    glRectf(x1, y1, x1+width, y1+height);

    // Clean up and return after drawing the rectangle
    glMatrixMode( GL_PROJECTION);
    glPopMatrix();
    glMatrixMode( GL_MODELVIEW);
    glPopMatrix();
    glEnable( GL_LIGHTING);

    return;
    }

  glListBase(vtkXOpenGLTextMapper::GetListBaseForFont(this,viewport,
						      this->CurrentFont));

  // Set the colors for the shadow
  if (this->Shadow)
    {
    pos[0]++; pos[1]--;
    // set the colors for the foreground
    glColor3ub(shadowRed, shadowGreen, shadowBlue);
    glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		  (2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		  (front)?(-1):(.99999));

    // Draw the shadow text
    glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);
    pos[0]--;  pos[1]++;
    }

  // set the colors for the foreground
  glColor3ub(red, green, blue);

  glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		(2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		(front)?(-1):(.99999));

  // display a string: // indicate start of glyph display lists
  glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);

  glMatrixMode( GL_PROJECTION);
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW);
  glPopMatrix();
  glEnable( GL_LIGHTING);
}

<commit_msg>fixed possible GLXError<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXOpenGLTextMapper.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkXOpenGLTextMapper.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include "vtkObjectFactory.h"
#include "vtkgluPickMatrix.h"

//--------------------------------------------------------------------------
vtkXOpenGLTextMapper* vtkXOpenGLTextMapper::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkXOpenGLTextMapper");
  if(ret)
    {
    return (vtkXOpenGLTextMapper*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkXOpenGLTextMapper;
}

struct vtkFontStruct
{
  vtkWindow *Window;
  int   Italic;
  int	Bold;
  int   FontSize;
  int   FontFamily;
  int   ListBase;
  GLXContext ContextId;
};

static vtkFontStruct *cache[30] = {
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL,
  NULL,NULL,NULL,NULL,NULL};
static int numCached = 0;

int vtkXOpenGLTextMapper::GetListBaseForFont(vtkTextMapper *tm,
					     vtkViewport *vp,
					     Font CurrentFont)
{
  int i, j;
  vtkWindow *win = vp->GetVTKWindow();

  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win &&
	cache[i]->Italic == tm->GetItalic() &&
	cache[i]->Bold == tm->GetBold() &&
	cache[i]->FontSize == tm->GetFontSize() &&
	cache[i]->FontFamily == tm->GetFontFamily())
      {
      // make this the most recently used
      if (i != 0)
	{
	vtkFontStruct *tmp = cache[i];
	for (j = i-1; j >= 0; j--)
	  {
	  cache[j+1] = cache[j];
	  }
	cache[0] = tmp;
	}
      return cache[0]->ListBase;
      }
    }

  // save the current context
  GLXContext ctx = glXGetCurrentContext();

  // OK the font is not cached
  // so we need to make room for a new font
  if (numCached == 30)
    {
    glXMakeCurrent((Display *)cache[29]->Window->GetGenericDisplayId(),
		   (Window)cache[29]->Window->GetGenericWindowId(),
		   cache[29]->ContextId);
    glDeleteLists(cache[29]->ListBase,255);
    glXMakeCurrent((Display *)win->GetGenericDisplayId(),
		   (Window)win->GetGenericWindowId(), ctx);
    numCached = 29;
    }

  // add the new font
  if (!cache[numCached])
    {
    cache[numCached] = new vtkFontStruct;
    int done = 0;
    cache[numCached]->ListBase = 1000;
    do
      {
      done = 1;
      cache[numCached]->ListBase += 260;
      for (i = 0; i < numCached; i++)
	{
	if (cache[i]->ListBase == cache[numCached]->ListBase)
	  {
	  done = 0;
	  }
	}
      }
    while (!done);
    }

  // set the other info and build the font
  cache[numCached]->Window = win;
  cache[numCached]->Italic = tm->GetItalic();
  cache[numCached]->Bold = tm->GetBold();
  cache[numCached]->FontSize = tm->GetFontSize();
  cache[numCached]->FontFamily = tm->GetFontFamily();
  cache[numCached]->ContextId = ctx;
  glXUseXFont(CurrentFont, 0, 255, cache[numCached]->ListBase);

  // now resort the list
  vtkFontStruct *tmp = cache[numCached];
  for (i = numCached-1; i >= 0; i--)
    {
    cache[i+1] = cache[i];
    }
  cache[0] = tmp;
  numCached++;
  return cache[0]->ListBase;
}

void vtkXOpenGLTextMapper::ReleaseGraphicsResources(vtkWindow *win)
{
  int i,j;

  // free up any cached font associated with this window
  // has the font been cached ?
  for (i = 0; i < numCached; i++)
    {
    if (cache[i]->Window == win)
      {
      win->MakeCurrent();
      glDeleteLists(cache[i]->ListBase,255);
      delete cache[i];
      // resort them
      numCached--;
      for (j = i; j < numCached; j++)
	{
	cache[j] = cache[j+1];
	}
      cache[numCached] = NULL;
      }
    }
  this->LastWindow = NULL;
}

vtkXOpenGLTextMapper::vtkXOpenGLTextMapper()
{
}

vtkXOpenGLTextMapper::~vtkXOpenGLTextMapper()
{
  if (this->LastWindow)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
}

void vtkXOpenGLTextMapper::RenderOpaqueGeometry(vtkViewport* viewport,
						vtkActor2D* actor)
{
  vtkDebugMacro (<< "RenderOpaqueGeometry");

  // turn off texturing in case it is on
  glDisable( GL_TEXTURE_2D );

  // Get the window information for display
  vtkWindow*  window = viewport->GetVTKWindow();
  if (this->LastWindow && this->LastWindow != window)
    {
    this->ReleaseGraphicsResources(this->LastWindow);
    }
  this->LastWindow = window;

  // Check for input
  if ( this->NumberOfLines > 1 )
    {
    this->RenderOpaqueGeometryMultipleLines(viewport, actor);
    return;
    }

  // Check for input
  if (this->Input == NULL || this->Input[0] == '\0')
    {
    vtkDebugMacro (<<"Render - No input");
    return;
    }

  int size[2];
  this->GetSize(viewport, size);

  // Get the position of the text actor
  int* actorPos =
    actor->GetPositionCoordinate()->GetComputedViewportValue(viewport);

  // Set up the font color from the text actor
  unsigned char red = 0;
  unsigned char green = 0;
  unsigned char blue = 0;
  float*  actorColor = actor->GetProperty()->GetColor();
  red = (unsigned char) (actorColor[0] * 255.0);
  green = (unsigned char) (actorColor[1] * 255.0);
  blue = (unsigned char) (actorColor[2] * 255.0);

  // Set up the shadow color
  float intensity;
  intensity = (red + green + blue)/3.0;

  unsigned char shadowRed, shadowGreen, shadowBlue;
  if (intensity > 128)
    {
    shadowRed = shadowBlue = shadowGreen = 0;
    }
  else
    {
    shadowRed = shadowBlue = shadowGreen = 255;
    }

  int pos[2];
  pos[0] = actorPos[0];
  pos[1] = (int)(actorPos[1] - this->LineOffset);

  switch (this->Justification)
    {
    case VTK_TEXT_LEFT: break;
    case VTK_TEXT_CENTERED:
      pos[0] = pos[0] - size[0]/2;
      break;
    case VTK_TEXT_RIGHT:
      pos[0] = pos[0] - size[0];
      break;
    }
  switch (this->VerticalJustification)
    {
    case VTK_TEXT_TOP:
      pos[1] = pos[1] - size[1];
      break;
    case VTK_TEXT_CENTERED:
      pos[1] = pos[1] - size[1]/2;
      break;
    case VTK_TEXT_BOTTOM:
      break;
    }

  // push a 2D matrix on the stack
  int *vsize = viewport->GetSize();
  glMatrixMode( GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  if(viewport->GetIsPicking())
    {
    vtkgluPickMatrix(viewport->GetPickX(), viewport->GetPickY(),
		     1, 1, viewport->GetOrigin(), viewport->GetSize());
    }
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();
  glDisable( GL_LIGHTING);

  int front =
    (actor->GetProperty()->GetDisplayLocation() == VTK_FOREGROUND_LOCATION);

  // When picking draw the bounds of the text as a rectangle,
  // as text only picks when the pick point is exactly on the
  // origin of the text
  if(viewport->GetIsPicking())
    {
    float x1 = (2.0*(float)actorPos[0] / vsize[0] - 1);
    float y1 = (2.0*((float)actorPos[1] - this->LineOffset) / vsize[1] - 1);
    float width = 2.0*(float)size[0]/vsize[0];
    float height = 2.0*(float)size[1]/vsize[1];
    glRectf(x1, y1, x1+width, y1+height);

    // Clean up and return after drawing the rectangle
    glMatrixMode( GL_PROJECTION);
    glPopMatrix();
    glMatrixMode( GL_MODELVIEW);
    glPopMatrix();
    glEnable( GL_LIGHTING);

    return;
    }

  glListBase(vtkXOpenGLTextMapper::GetListBaseForFont(this,viewport,
						      this->CurrentFont));

  // Set the colors for the shadow
  if (this->Shadow)
    {
    pos[0]++; pos[1]--;
    // set the colors for the foreground
    glColor3ub(shadowRed, shadowGreen, shadowBlue);
    glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		  (2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		  (front)?(-1):(.99999));

    // Draw the shadow text
    glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);
    pos[0]--;  pos[1]++;
    }

  // set the colors for the foreground
  glColor3ub(red, green, blue);

  glRasterPos3f((2.0 * (GLfloat)(pos[0]) / vsize[0] - 1),
		(2.0 * (GLfloat)(pos[1]) / vsize[1] - 1),
		(front)?(-1):(.99999));

  // display a string: // indicate start of glyph display lists
  glCallLists (strlen(this->Input), GL_UNSIGNED_BYTE, this->Input);

  glMatrixMode( GL_PROJECTION);
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW);
  glPopMatrix();
  glEnable( GL_LIGHTING);
}

<|endoftext|>


<commit_before>#include "physics/kepler_orbit.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mathematica/mathematica.hpp"
#include "physics/solar_system.hpp"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using integrators::McLachlanAtela1992Order5Optimal;
using quantities::si::Degree;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;

namespace physics {

class ResonanceTest : public ::testing::Test {};

TEST_F(ResonanceTest, JoolSystem) {
  using KSP =
      Frame<serialization::Frame::TestTag, serialization::Frame::TEST, true>;
  MasslessBody test_particle;
  // Gravitational parameters from the KSP wiki.
  std::vector<not_null<std::unique_ptr<MassiveBody const>>> bodies;
  auto const add_body = [&bodies](
      GravitationalParameter const& μ) -> not_null<MassiveBody const*> {
    bodies.emplace_back(make_not_null_unique<MassiveBody>(μ));
    return bodies.back().get();
  };
  auto const sun = add_body(1.1723328E+18 * Pow<3>(Metre) / Pow<2>(Second));
  auto const jool = add_body(2.8252800E+14 * Pow<3>(Metre) / Pow<2>(Second));
  auto const laythe = add_body(1.9620000E+12 * Pow<3>(Metre) / Pow<2>(Second));
  auto const vall = add_body(2.0748150E+11 * Pow<3>(Metre) / Pow<2>(Second));
  auto const tylo = add_body(2.8252800E+12 * Pow<3>(Metre) / Pow<2>(Second));
  auto const bop = add_body(2.4868349E+09 * Pow<3>(Metre) / Pow<2>(Second));
  auto const pol = add_body(7.2170208E+08 * Pow<3>(Metre) / Pow<2>(Second));

  // Elements from the KSP wiki.
  KeplerianElements<KSP> jool_elements;
  jool_elements.eccentricity = 0.05;
  jool_elements.semimajor_axis = 68'773'560'320 * Metre;
  jool_elements.inclination = 1.304 * Degree;
  jool_elements.longitude_of_ascending_node = 52 * Degree;
  jool_elements.argument_of_periapsis =  0 * Degree;
  jool_elements.mean_anomaly = 0.1 * Radian;
  KeplerianElements<KSP> laythe_elements;
  laythe_elements.eccentricity = 0;
  laythe_elements.semimajor_axis = 27'184'000 * Metre;
  laythe_elements.inclination = 0 * Degree;
  laythe_elements.longitude_of_ascending_node = 0 * Degree;
  laythe_elements.argument_of_periapsis = 0 * Degree;
  laythe_elements.mean_anomaly = 3.14 * Radian;
  KeplerianElements<KSP> vall_elements;
  vall_elements.eccentricity = 0;
  vall_elements.semimajor_axis = 43'152'000 * Metre;
  vall_elements.inclination = 0 * Degree;
  vall_elements.longitude_of_ascending_node = 0 * Degree;
  vall_elements.argument_of_periapsis = 0 * Degree;
  vall_elements.mean_anomaly = 0.9 * Radian;
  KeplerianElements<KSP> tylo_elements;
  tylo_elements.eccentricity = 0;
  tylo_elements.semimajor_axis = 68'500'000 * Metre;
  tylo_elements.inclination = 0.025 * Degree;
  tylo_elements.longitude_of_ascending_node = 0 * Degree;
  tylo_elements.argument_of_periapsis = 0 * Degree;
  tylo_elements.mean_anomaly = 3.14 * Radian;
  KeplerianElements<KSP> bop_elements;
  bop_elements.eccentricity = 0.24;
  bop_elements.semimajor_axis = 128'500'000 * Metre;
  bop_elements.inclination = 15 * Degree;
  bop_elements.longitude_of_ascending_node = 10 * Degree;
  bop_elements.argument_of_periapsis = 25 * Degree;
  bop_elements.mean_anomaly = 0.9 * Radian;
  KeplerianElements<KSP> pol_elements;
  pol_elements.eccentricity = 0.17;
  pol_elements.semimajor_axis = 179'890'000 * Metre;
  pol_elements.inclination = 4.25 * Degree;
  pol_elements.longitude_of_ascending_node = 2 * Degree;
  pol_elements.argument_of_periapsis = 15 * Degree;
  pol_elements.mean_anomaly = 0.9 * Radian;

  Instant const game_epoch;
  auto const stock_jool_orbit =
      KeplerOrbit<KSP>(*sun, test_particle, game_epoch, jool_elements);
  auto const stock_laythe_orbit =
      KeplerOrbit<KSP>(*jool, test_particle, game_epoch, laythe_elements);
  auto const stock_vall_orbit =
      KeplerOrbit<KSP>(*jool, test_particle, game_epoch, vall_elements);
  auto const stock_tylo_orbit =
      KeplerOrbit<KSP>(*jool, test_particle, game_epoch, tylo_elements);
  auto const stock_bop_orbit =
      KeplerOrbit<KSP>(*jool, test_particle, game_epoch, bop_elements);
  auto const stock_pol_orbit =
      KeplerOrbit<KSP>(*jool, test_particle, game_epoch, pol_elements);

  DegreesOfFreedom<KSP> const origin = {KSP::origin, Velocity<KSP>()};
  auto const stock_jool_initial_state =
      origin + stock_jool_orbit.PrimocentricStateVectors(game_epoch);
  Ephemeris<KSP> stock_ephemeris(
      std::move(bodies),
      {origin,
       stock_jool_initial_state,
       stock_jool_initial_state +
           stock_laythe_orbit.PrimocentricStateVectors(game_epoch),
       stock_jool_initial_state +
           stock_vall_orbit.PrimocentricStateVectors(game_epoch),
       stock_jool_initial_state +
           stock_tylo_orbit.PrimocentricStateVectors(game_epoch),
       stock_jool_initial_state +
           stock_bop_orbit.PrimocentricStateVectors(game_epoch),
       stock_jool_initial_state +
           stock_pol_orbit.PrimocentricStateVectors(game_epoch)},
      game_epoch,
      McLachlanAtela1992Order5Optimal<Position<KSP>>(),
      45 * Minute,
      5 * Milli(Metre));
  stock_ephemeris.Prolong(game_epoch + 90 * Day);
  std::vector<Instant> times;
  std::vector<std::vector<Displacement<KSP>>> displacements;
  for (Instant t = game_epoch; t < game_epoch + 90 * Day; t += 45 * Minute) {
    auto const position = [&stock_ephemeris, t](
        not_null<MassiveBody const*> body) {
      return stock_ephemeris.trajectory(body)->EvaluatePosition(t, nullptr);
    };
    auto const barycentre =
        Barycentre<Position<KSP>, Mass>(
            {position(jool), position(laythe), position(vall), position(tylo),
             position(bop), position(pol)},
            {jool->mass(), laythe->mass(), vall->mass(), tylo->mass(),
             bop->mass(), pol->mass()});
    times.emplace_back(t);
    displacements.push_back(
        {position(jool) - barycentre, position(laythe) - barycentre,
         position(vall) - barycentre, position(tylo) - barycentre,
         position(bop) - barycentre, position(pol) - barycentre});
  }
  std::ofstream file;
  file.open("stock_jool.wl");
  file << mathematica::Assign("q", displacements);
  file << mathematica::Assign("t", times);
  file.close();
  // fails.
  stock_ephemeris.Prolong(game_epoch + 100 * Day);
}

}  // namespace physics
}  // namespace principia
<commit_msg>members<commit_after>#include "physics/kepler_orbit.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mathematica/mathematica.hpp"
#include "physics/solar_system.hpp"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using integrators::McLachlanAtela1992Order5Optimal;
using quantities::si::Degree;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;

namespace physics {

class ResonanceTest : public ::testing::Test {
 protected:
  using KSP =
      Frame<serialization::Frame::TestTag, serialization::Frame::TEST, true>;

  // Gravitational parameters from the KSP wiki.
  ResonanceTest()
      : sun_(AddBody(1.1723328E+18 * Pow<3>(Metre) / Pow<2>(Second))),
        jool_(AddBody(2.8252800E+14 * Pow<3>(Metre) / Pow<2>(Second))),
        laythe_(AddBody(1.9620000E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        vall_(AddBody(2.0748150E+11 * Pow<3>(Metre) / Pow<2>(Second))),
        tylo_(AddBody(2.8252800E+12 * Pow<3>(Metre) / Pow<2>(Second))),
        bop_(AddBody(2.4868349E+09 * Pow<3>(Metre) / Pow<2>(Second))),
        pol_(AddBody(7.2170208E+08 * Pow<3>(Metre) / Pow<2>(Second))) {
    // Elements from the KSP wiki.
    jool_elements_.eccentricity = 0.05;
    jool_elements_.semimajor_axis = 68'773'560'320 * Metre;
    jool_elements_.inclination = 1.304 * Degree;
    jool_elements_.longitude_of_ascending_node = 52 * Degree;
    jool_elements_.argument_of_periapsis =  0 * Degree;
    jool_elements_.mean_anomaly = 0.1 * Radian;
    laythe_elements_.eccentricity = 0;
    laythe_elements_.semimajor_axis = 27'184'000 * Metre;
    laythe_elements_.inclination = 0 * Degree;
    laythe_elements_.longitude_of_ascending_node = 0 * Degree;
    laythe_elements_.argument_of_periapsis = 0 * Degree;
    laythe_elements_.mean_anomaly = 3.14 * Radian;
    vall_elements_.eccentricity = 0;
    vall_elements_.semimajor_axis = 43'152'000 * Metre;
    vall_elements_.inclination = 0 * Degree;
    vall_elements_.longitude_of_ascending_node = 0 * Degree;
    vall_elements_.argument_of_periapsis = 0 * Degree;
    vall_elements_.mean_anomaly = 0.9 * Radian;
    tylo_elements_.eccentricity = 0;
    tylo_elements_.semimajor_axis = 68'500'000 * Metre;
    tylo_elements_.inclination = 0.025 * Degree;
    tylo_elements_.longitude_of_ascending_node = 0 * Degree;
    tylo_elements_.argument_of_periapsis = 0 * Degree;
    tylo_elements_.mean_anomaly = 3.14 * Radian;
    bop_elements_.eccentricity = 0.24;
    bop_elements_.semimajor_axis = 128'500'000 * Metre;
    bop_elements_.inclination = 15 * Degree;
    bop_elements_.longitude_of_ascending_node = 10 * Degree;
    bop_elements_.argument_of_periapsis = 25 * Degree;
    bop_elements_.mean_anomaly = 0.9 * Radian;
    pol_elements_.eccentricity = 0.17;
    pol_elements_.semimajor_axis = 179'890'000 * Metre;
    pol_elements_.inclination = 4.25 * Degree;
    pol_elements_.longitude_of_ascending_node = 2 * Degree;
    pol_elements_.argument_of_periapsis = 15 * Degree;
    pol_elements_.mean_anomaly = 0.9 * Radian;
  }

  std::vector<not_null<std::unique_ptr<MassiveBody const>>> bodies_;
  not_null<MassiveBody const *> const sun_, jool_, laythe_, vall_, tylo_, bop_,
      pol_;
  MasslessBody test_particle_;
  Instant const game_epoch_;
  DegreesOfFreedom<KSP> const origin_ = {KSP::origin, Velocity<KSP>()};
  KeplerianElements<KSP> jool_elements_, laythe_elements_, vall_elements_,
      tylo_elements_, bop_elements_, pol_elements_;

 private:
  not_null<MassiveBody const*> AddBody(GravitationalParameter const& μ) {
    bodies_.emplace_back(make_not_null_unique<MassiveBody>(μ));
    return bodies_.back().get();
  }
};

TEST_F(ResonanceTest, JoolSystem) {
  auto const stock_jool_orbit =
      KeplerOrbit<KSP>(*sun_, test_particle_, game_epoch_, jool_elements_);
  auto const stock_laythe_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, laythe_elements_);
  auto const stock_vall_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, vall_elements_);
  auto const stock_tylo_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, tylo_elements_);
  auto const stock_bop_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, bop_elements_);
  auto const stock_pol_orbit =
      KeplerOrbit<KSP>(*jool_, test_particle_, game_epoch_, pol_elements_);

  auto const stock_jool_initial_state =
      origin_ + stock_jool_orbit.PrimocentricStateVectors(game_epoch_);
  Ephemeris<KSP> stock_ephemeris(
      std::move(bodies_),
      {origin_,
       stock_jool_initial_state,
       stock_jool_initial_state +
           stock_laythe_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_vall_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_tylo_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_bop_orbit.PrimocentricStateVectors(game_epoch_),
       stock_jool_initial_state +
           stock_pol_orbit.PrimocentricStateVectors(game_epoch_)},
      game_epoch_,
      McLachlanAtela1992Order5Optimal<Position<KSP>>(),
      45 * Minute,
      5 * Milli(Metre));
  stock_ephemeris.Prolong(game_epoch_ + 90 * Day);
  std::vector<Instant> times;
  std::vector<std::vector<Displacement<KSP>>> displacements;
  for (Instant t = game_epoch_; t < game_epoch_ + 90 * Day; t += 45 * Minute) {
    auto const position = [&stock_ephemeris, t](
        not_null<MassiveBody const*> body) {
      return stock_ephemeris.trajectory(body)->EvaluatePosition(t, nullptr);
    };
    auto const barycentre = Barycentre<Position<KSP>, Mass>(
        {position(jool_), position(laythe_), position(vall_), position(tylo_),
         position(bop_), position(pol_)},
        {jool_->mass(), laythe_->mass(), vall_->mass(), tylo_->mass(),
         bop_->mass(), pol_->mass()});
    times.emplace_back(t);
    displacements.push_back(
        {position(jool_) - barycentre, position(laythe_) - barycentre,
         position(vall_) - barycentre, position(tylo_) - barycentre,
         position(bop_) - barycentre, position(pol_) - barycentre});
  }
  std::ofstream file;
  file.open("stock_jool.wl");
  file << mathematica::Assign("q", displacements);
  file << mathematica::Assign("t", times);
  file.close();
  // fails.
  stock_ephemeris.Prolong(game_epoch_ + 100 * Day);
}

}  // namespace physics
}  // namespace principia
<|endoftext|>