<commit_before>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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 General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 The full license is available in the file GPLv3.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

//!
//! @file   ScriptEditor.h
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2018-10-01
//! @version $Id$
//!
//! @brief Contains the script editor class
//!

#include "ScriptEditor.h"
#include "Utilities/HighlightingUtilities.h"
#include "global.h"
#include "Configuration.h"
#include "MessageHandler.h"
#include "Widgets/ProjectTabWidget.h"
#include "HcomHandler.h"
#include "Widgets/HcomWidget.h"

#include <QGridLayout>
#include <QFileDialog>
#include <QStringListModel>
#include <QAbstractItemView>
#include <QScrollBar>
#include <QTextDocumentFragment>
#include <QKeyEvent>
#include <math.h>

ScriptEditor::ScriptEditor(QFileInfo scriptFileInfo, QWidget *parent) : QWidget(parent)
{
    mScriptFileInfo = scriptFileInfo;

    mpEditor = new HcomEditor(this);
    QFont font("Monospace");
    font.setStyleHint(QFont::TypeWriter);
    mpEditor->setFont(font);

    HcomHighlighter *pHighLighter = new HcomHighlighter(mpEditor->document());

    if(mScriptFileInfo.exists())
    {
        QFile scriptFile(mScriptFileInfo.absoluteFilePath());
        if(!scriptFile.open(QFile::ReadOnly | QFile::Text))
        {
            gpMessageHandler->addErrorMessage("Unable to read from HCOM script file: "+mScriptFileInfo.absoluteFilePath());
            return;
        }
        mSavedText = scriptFile.readAll();
        mpEditor->setText(mSavedText);
        scriptFile.close();
    }

    QGridLayout *pLayout = new QGridLayout(this);
    pLayout->addWidget(mpEditor,         0,0,1,2);

    connect(mpEditor, SIGNAL(textChanged()), this, SLOT(hasChanged()));
}

void ScriptEditor::wheelEvent(QWheelEvent* event)
{
#if QT_VERSION >= 0x050000  //zoomIn() and zoomOut() not available in Qt4
   if ((event->modifiers() == Qt::ControlModifier) && (event->delta() > 0))
       mpEditor->zoomIn(2);
   else if ((event->modifiers() == Qt::ControlModifier) && (event->delta() < 0))
       mpEditor->zoomOut(2);
   else
       QWidget::wheelEvent(event);
#else
   QWidget::wheelEvent(event);
#endif
}

//! Saves the script tab to a model file.
//! @param saveAsFlag tells whether or not an already existing file name shall be used
void ScriptEditor::save(SaveTargetEnumT saveAsFlag)
{
    if(saveAsFlag == NewFile || !mScriptFileInfo.exists())
    {
        QString filePath = QFileDialog::getSaveFileName(this,
                                                        tr("Save Script File"),
                                                        mScriptFileInfo.filePath(),
                                                        tr("Hopsan Script Files (*.hcom)"));
        if(filePath.isEmpty())     //Don't save anything if user presses cancel
        {
            return;
        }
        mScriptFileInfo = QFileInfo(filePath);
    }

    QFile file(mScriptFileInfo.absoluteFilePath());
    gpConfig->setStringSetting(CFG_LOADSCRIPTDIR, mScriptFileInfo.absolutePath());

    if(!file.open(QFile::WriteOnly | QFile::Text))
    {
        gpMessageHandler->addErrorMessage("Unable to open file for writing: "+file.fileName());
        return;
    }

    file.write(mpEditor->toPlainText().toUtf8());
    file.close();

    gpCentralTabWidget->setTabText(gpCentralTabWidget->indexOf(this), mScriptFileInfo.fileName());

    mIsSaved = true;
}

void ScriptEditor::hasChanged()
{
    mIsSaved = mpEditor->toPlainText() == mSavedText;

    //Add asterisk from tab name
    QString tabName = gpCentralTabWidget->tabText(gpCentralTabWidget->indexOf(this));
    if(mIsSaved && tabName.endsWith("*"))
    {
        tabName.chop(1);
    }
    else if(!mIsSaved && !tabName.endsWith("*"))
    {
        tabName.append("*");
    }
    gpCentralTabWidget->setTabText(gpCentralTabWidget->indexOf(this), tabName);
}

//! Slot that saves current script to a new model file.
//! @see saveModel(int index)
void ScriptEditor::saveAs()
{
    save(NewFile);
}

void ScriptEditor::cut()
{
    mpEditor->cut();
}

void ScriptEditor::copy()
{
    mpEditor->copy();
}

void ScriptEditor::paste()
{
    mpEditor->paste();
}

void ScriptEditor::undo()
{
    mpEditor->undo();
}

void ScriptEditor::redo()
{
    mpEditor->redo();
}

void ScriptEditor::zoomIn()
{
#if QT_VERSION >= 0x050000
    mpEditor->zoomIn(2);
#endif
}

void ScriptEditor::zoomOut()
{
#if QT_VERSION >= 0x050000
    mpEditor->zoomOut(2);
#endif
}

void ScriptEditor::print()
{
    //! @todo Implement
}

HcomEditor::HcomEditor(QWidget* parent) : QTextEdit(parent)
{
    mpCompleter = new QCompleter(this);
    updateAutoCompleteList();

    mpCompleter->setWidget(this);
    mpCompleter->setCompletionMode(QCompleter::PopupCompletion);
    mpCompleter->setCaseSensitivity(Qt::CaseInsensitive);
    QObject::connect(mpCompleter, SIGNAL(activated(QString)),
                     this, SLOT(insertCompletion(QString)));
}

void HcomEditor::keyPressEvent(QKeyEvent* event)
{
    if (mpCompleter->popup()->isVisible())
    {
        //Ignore the following keys when the completer is visible
       switch (event->key()) {
       case Qt::Key_Enter:
       case Qt::Key_Return:
       case Qt::Key_Escape:
       case Qt::Key_Tab:
       case Qt::Key_Backtab:
            event->ignore();
            return;
       default:
           break;
       }
    }

    //Replace tabs with four whitespaces
    if(event->key() == Qt::Key_Backtab)    //Shift+tab, remove spaces to the left until next tab stop (or as many spaces as possible)
    {
        QString line = this->textCursor().block().text().toLatin1();
        int pos = textCursor().positionInBlock();
        while(pos > 0 && line.at(pos-1) == ' ')
        {
            this->textCursor().deletePreviousChar();
            line = this->textCursor().block().text().toLatin1();
            pos = textCursor().positionInBlock();
            if(pos%2 == 0)
            {
                break;
            }
        }
    }
    else if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
    {
        QString line = this->textCursor().block().text().toLatin1();
        QString newStr = "\n";
        while(line.startsWith(" "))
        {
            line.remove(0,1);
            newStr.append(" "); //Append one space to new line for each space on previous line, to keep indentation
        }
        insertPlainText(newStr);
    }
    else if(event->key() == Qt::Key_Tab)
    {
        if(textCursor().anchor() != textCursor().position())    //Selection exists, indent whole selection
        {
            QString text = textCursor().selection().toPlainText();
            text.replace("\n", "\n  ");
            text.prepend("  ");
            textCursor().beginEditBlock();
            textCursor().removeSelectedText();
            insertPlainText(text);
            textCursor().endEditBlock();
        }
        else
        {
            QString line = this->textCursor().block().text().toLatin1();
            int pos = textCursor().positionInBlock();
            qDebug() << line << ", position: " << pos;
            int nSpaces = 0;
            while(line.startsWith(" "))
            {
                nSpaces++;
                line.remove(0,1);
            }
            int nSpacesToInsert = 2;    //Insert two spaces by default
            if(pos < nSpaces)           //If at beginning of line, insert until next tab stop
            {
                while((nSpaces+nSpacesToInsert)%2 != 0)
                {
                    nSpacesToInsert--;
                }
            }
            for(int i=0; i<nSpacesToInsert; ++i)
            {
                this->insertPlainText(" ");
            }
        }
    }
    else
    {
        QTextEdit::keyPressEvent(event);

        updateAutoCompleteList();

        QTextCursor tc = textCursor();
        tc.select(QTextCursor::WordUnderCursor);
        QString prefix = tc.selectedText();
        if((event->key() != Qt::Key_Space || !event->modifiers().testFlag(Qt::ControlModifier)) && prefix.isEmpty())
            return;

        if (prefix != mpCompleter->completionPrefix()) {
            mpCompleter->setCompletionPrefix(prefix);
            mpCompleter->popup()->setCurrentIndex(mpCompleter->completionModel()->index(0, 0));
        }
        QRect cr = cursorRect();
        cr.setWidth(mpCompleter->popup()->sizeHintForColumn(0)
                    + mpCompleter->popup()->verticalScrollBar()->sizeHint().width());
        mpCompleter->complete(cr);
    }
}

//! @brief Updates list of auto complete words
void HcomEditor::updateAutoCompleteList()
{
    mpCompleter->setModel(new QStringListModel(gpTerminalWidget->mpHandler->getAutoCompleteWords(), mpCompleter));
}

void HcomEditor::insertCompletion(const QString& completion)
{
    if (mpCompleter->widget() != this)
        return;
    QTextCursor tc = textCursor();
    int extra = completion.length() - mpCompleter->completionPrefix().length();
    tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    setTextCursor(tc);
}
<commit_msg>Block comment and uncomment in HCOM editor<commit_after>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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 General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 The full license is available in the file GPLv3.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

//!
//! @file   ScriptEditor.h
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2018-10-01
//! @version $Id$
//!
//! @brief Contains the script editor class
//!

#include "ScriptEditor.h"
#include "Utilities/HighlightingUtilities.h"
#include "global.h"
#include "Configuration.h"
#include "MessageHandler.h"
#include "Widgets/ProjectTabWidget.h"
#include "HcomHandler.h"
#include "Widgets/HcomWidget.h"

#include <QGridLayout>
#include <QFileDialog>
#include <QStringListModel>
#include <QAbstractItemView>
#include <QScrollBar>
#include <QTextDocumentFragment>
#include <QKeyEvent>
#include <math.h>

ScriptEditor::ScriptEditor(QFileInfo scriptFileInfo, QWidget *parent) : QWidget(parent)
{
    mScriptFileInfo = scriptFileInfo;

    mpEditor = new HcomEditor(this);
    QFont font("Monospace");
    font.setStyleHint(QFont::TypeWriter);
    mpEditor->setFont(font);

    HcomHighlighter *pHighLighter = new HcomHighlighter(mpEditor->document());

    if(mScriptFileInfo.exists())
    {
        QFile scriptFile(mScriptFileInfo.absoluteFilePath());
        if(!scriptFile.open(QFile::ReadOnly | QFile::Text))
        {
            gpMessageHandler->addErrorMessage("Unable to read from HCOM script file: "+mScriptFileInfo.absoluteFilePath());
            return;
        }
        mSavedText = scriptFile.readAll();
        mpEditor->setText(mSavedText);
        scriptFile.close();
    }

    QGridLayout *pLayout = new QGridLayout(this);
    pLayout->addWidget(mpEditor,         0,0,1,2);

    connect(mpEditor, SIGNAL(textChanged()), this, SLOT(hasChanged()));
}

void ScriptEditor::wheelEvent(QWheelEvent* event)
{
#if QT_VERSION >= 0x050000  //zoomIn() and zoomOut() not available in Qt4
   if ((event->modifiers() == Qt::ControlModifier) && (event->delta() > 0))
       mpEditor->zoomIn(2);
   else if ((event->modifiers() == Qt::ControlModifier) && (event->delta() < 0))
       mpEditor->zoomOut(2);
   else
       QWidget::wheelEvent(event);
#else
   QWidget::wheelEvent(event);
#endif
}

//! Saves the script tab to a model file.
//! @param saveAsFlag tells whether or not an already existing file name shall be used
void ScriptEditor::save(SaveTargetEnumT saveAsFlag)
{
    if(saveAsFlag == NewFile || !mScriptFileInfo.exists())
    {
        QString filePath = QFileDialog::getSaveFileName(this,
                                                        tr("Save Script File"),
                                                        mScriptFileInfo.filePath(),
                                                        tr("Hopsan Script Files (*.hcom)"));
        if(filePath.isEmpty())     //Don't save anything if user presses cancel
        {
            return;
        }
        mScriptFileInfo = QFileInfo(filePath);
    }

    QFile file(mScriptFileInfo.absoluteFilePath());
    gpConfig->setStringSetting(CFG_LOADSCRIPTDIR, mScriptFileInfo.absolutePath());

    if(!file.open(QFile::WriteOnly | QFile::Text))
    {
        gpMessageHandler->addErrorMessage("Unable to open file for writing: "+file.fileName());
        return;
    }

    file.write(mpEditor->toPlainText().toUtf8());
    file.close();

    gpCentralTabWidget->setTabText(gpCentralTabWidget->indexOf(this), mScriptFileInfo.fileName());

    mIsSaved = true;
}

void ScriptEditor::hasChanged()
{
    mIsSaved = mpEditor->toPlainText() == mSavedText;

    //Add asterisk from tab name
    QString tabName = gpCentralTabWidget->tabText(gpCentralTabWidget->indexOf(this));
    if(mIsSaved && tabName.endsWith("*"))
    {
        tabName.chop(1);
    }
    else if(!mIsSaved && !tabName.endsWith("*"))
    {
        tabName.append("*");
    }
    gpCentralTabWidget->setTabText(gpCentralTabWidget->indexOf(this), tabName);
}

//! Slot that saves current script to a new model file.
//! @see saveModel(int index)
void ScriptEditor::saveAs()
{
    save(NewFile);
}

void ScriptEditor::cut()
{
    mpEditor->cut();
}

void ScriptEditor::copy()
{
    mpEditor->copy();
}

void ScriptEditor::paste()
{
    mpEditor->paste();
}

void ScriptEditor::undo()
{
    mpEditor->undo();
}

void ScriptEditor::redo()
{
    mpEditor->redo();
}

void ScriptEditor::zoomIn()
{
#if QT_VERSION >= 0x050000
    mpEditor->zoomIn(2);
#endif
}

void ScriptEditor::zoomOut()
{
#if QT_VERSION >= 0x050000
    mpEditor->zoomOut(2);
#endif
}

void ScriptEditor::print()
{
    //! @todo Implement
}

HcomEditor::HcomEditor(QWidget* parent) : QTextEdit(parent)
{
    mpCompleter = new QCompleter(this);
    updateAutoCompleteList();

    mpCompleter->setWidget(this);
    mpCompleter->setCompletionMode(QCompleter::PopupCompletion);
    mpCompleter->setCaseSensitivity(Qt::CaseInsensitive);
    QObject::connect(mpCompleter, SIGNAL(activated(QString)),
                     this, SLOT(insertCompletion(QString)));
}

void HcomEditor::keyPressEvent(QKeyEvent* event)
{
    if (mpCompleter->popup()->isVisible())
    {
        //Ignore the following keys when the completer is visible
       switch (event->key()) {
       case Qt::Key_Enter:
       case Qt::Key_Return:
       case Qt::Key_Escape:
       case Qt::Key_Tab:
       case Qt::Key_Backtab:
            event->ignore();
            return;
       default:
           break;
       }
    }

    //Replace tabs with four whitespaces
    if(event->key() == Qt::Key_Backtab)    //Shift+tab, remove spaces to the left until next tab stop (or as many spaces as possible)
    {
        QString line = this->textCursor().block().text().toLatin1();
        int pos = textCursor().positionInBlock();
        while(pos > 0 && line.at(pos-1) == ' ')
        {
            this->textCursor().deletePreviousChar();
            line = this->textCursor().block().text().toLatin1();
            pos = textCursor().positionInBlock();
            if(pos%2 == 0)
            {
                break;
            }
        }
    }
    else if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
    {
        QString line = this->textCursor().block().text().toLatin1();
        QString newStr = "\n";
        while(line.startsWith(" "))
        {
            line.remove(0,1);
            newStr.append(" "); //Append one space to new line for each space on previous line, to keep indentation
        }
        insertPlainText(newStr);
    }
    else if(event->key() == Qt::Key_Tab)
    {
        if(textCursor().anchor() != textCursor().position())    //Selection exists, indent whole selection
        {
            QString text = textCursor().selection().toPlainText();
            text.replace("\n", "\n  ");
            text.prepend("  ");
            textCursor().beginEditBlock();
            textCursor().removeSelectedText();
            insertPlainText(text);
            textCursor().endEditBlock();
        }
        else
        {
            QString line = this->textCursor().block().text().toLatin1();
            int pos = textCursor().positionInBlock();
            qDebug() << line << ", position: " << pos;
            int nSpaces = 0;
            while(line.startsWith(" "))
            {
                nSpaces++;
                line.remove(0,1);
            }
            int nSpacesToInsert = 2;    //Insert two spaces by default
            if(pos < nSpaces)           //If at beginning of line, insert until next tab stop
            {
                while((nSpaces+nSpacesToInsert)%2 != 0)
                {
                    nSpacesToInsert--;
                }
            }
            for(int i=0; i<nSpacesToInsert; ++i)
            {
                this->insertPlainText(" ");
            }
        }
    }
    else if(event->key() == Qt::Key_T && event->modifiers().testFlag(Qt::ControlModifier))     //Ctrl-T = block comment
    {
        textCursor().beginEditBlock();
        QString text = textCursor().selection().toPlainText();
        text.replace("\n", "\n//");
        if(textCursor().atBlockStart())
        {
            text.prepend("//");
        }
        else
        {
            int pos = textCursor().position();
            int stopPos = textCursor().anchor();
            QTextCursor c;
            c = textCursor();
            c.setPosition(std::min(pos,stopPos));
            setTextCursor(c);
            moveCursor(QTextCursor::StartOfBlock);
            insertPlainText("# ");

            c = textCursor();
            c.setPosition(pos+2);
            c.setPosition(stopPos+2, QTextCursor::KeepAnchor);
            setTextCursor(c);
        }
        textCursor().removeSelectedText();
        insertPlainText(text);
        textCursor().endEditBlock();
    }
    else if(event->key() == Qt::Key_U && event->modifiers().testFlag(Qt::ControlModifier))     //Ctrl-U = uncomment block
    {
        textCursor().beginEditBlock();
        QString text = textCursor().selection().toPlainText();
        text.replace("\n# ", "\n");
        text.replace("\n#", "\n");

        int pos = textCursor().position();
        int stopPos = textCursor().anchor();
        QTextCursor c;
        c = textCursor();
        c.setPosition(std::min(pos,stopPos));
        setTextCursor(c);
        moveCursor(QTextCursor::StartOfBlock);
        moveCursor(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
        moveCursor(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
        int movement = 0;
        if(textCursor().selection().toPlainText() == "//")
        {
            textCursor().removeSelectedText();
            movement = 2;
        }
        c = textCursor();
        c.setPosition(pos-movement);
        c.setPosition(stopPos-movement, QTextCursor::KeepAnchor);
        setTextCursor(c);

        textCursor().removeSelectedText();
        insertPlainText(text);

        textCursor().endEditBlock();
    }
    else
    {
        QTextEdit::keyPressEvent(event);

        updateAutoCompleteList();

        QTextCursor tc = textCursor();
        tc.select(QTextCursor::WordUnderCursor);
        QString prefix = tc.selectedText();
        if((event->key() != Qt::Key_Space || !event->modifiers().testFlag(Qt::ControlModifier)) && prefix.isEmpty())
            return;

        if (prefix != mpCompleter->completionPrefix()) {
            mpCompleter->setCompletionPrefix(prefix);
            mpCompleter->popup()->setCurrentIndex(mpCompleter->completionModel()->index(0, 0));
        }
        QRect cr = cursorRect();
        cr.setWidth(mpCompleter->popup()->sizeHintForColumn(0)
                    + mpCompleter->popup()->verticalScrollBar()->sizeHint().width());
        mpCompleter->complete(cr);
    }
}

//! @brief Updates list of auto complete words
void HcomEditor::updateAutoCompleteList()
{
    mpCompleter->setModel(new QStringListModel(gpTerminalWidget->mpHandler->getAutoCompleteWords(), mpCompleter));
}

void HcomEditor::insertCompletion(const QString& completion)
{
    if (mpCompleter->widget() != this)
        return;
    QTextCursor tc = textCursor();
    int extra = completion.length() - mpCompleter->completionPrefix().length();
    tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    setTextCursor(tc);
}
<|endoftext|>


<commit_before>/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/***************************************************************************
 * The mesh for rendering.
 ***************************************************************************/

#include "mesh.h"

#include <limits>

#include "assimp/Importer.hpp"
#include "assimp/mesh.h"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "util/gvr_log.h"
#include "util/gvr_gl.h"
#include "glm/gtc/matrix_inverse.hpp"
#include "../gl/gl_program.h"

namespace gvr {
Mesh* Mesh::createBoundingBox() {

    Mesh* mesh = new Mesh();

    getBoundingVolume(); // Make sure bounding_volume is valid

    glm::vec3 min_corner = bounding_volume.min_corner();
    glm::vec3 max_corner = bounding_volume.max_corner();

    float min_x = min_corner[0];
    float min_y = min_corner[1];
    float min_z = min_corner[2];
    float max_x = max_corner[0];
    float max_y = max_corner[1];
    float max_z = max_corner[2];

    mesh->vertices_.push_back(glm::vec3(min_x, min_y, min_z));
    mesh->vertices_.push_back(glm::vec3(max_x, min_y, min_z));
    mesh->vertices_.push_back(glm::vec3(min_x, max_y, min_z));
    mesh->vertices_.push_back(glm::vec3(max_x, max_y, min_z));
    mesh->vertices_.push_back(glm::vec3(min_x, min_y, max_z));
    mesh->vertices_.push_back(glm::vec3(max_x, min_y, max_z));
    mesh->vertices_.push_back(glm::vec3(min_x, max_y, max_z));
    mesh->vertices_.push_back(glm::vec3(max_x, max_y, max_z));

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(3);

    mesh->indices_.push_back(1);
    mesh->indices_.push_back(3);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(5);

    mesh->indices_.push_back(4);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(6);

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(0);
    mesh->indices_.push_back(4);
    mesh->indices_.push_back(6);

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(0);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(4);

    mesh->indices_.push_back(2);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(3);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(7);

    return mesh;
}

// an array of size:6 with Xmin, Ymin, Zmin and Xmax, Ymax, Zmax values
const BoundingVolume& Mesh::getBoundingVolume() {
    if (have_bounding_volume_) {
        return bounding_volume;
    }

    for (auto it = vertices_.begin(); it != vertices_.end(); ++it) {
        bounding_volume.expand(*it);
    }

    have_bounding_volume_ = true;
    return bounding_volume;
}

void Mesh::getTransformedBoundingBoxInfo(glm::mat4 *Mat,
        float *transformed_bounding_box) {

    if (have_bounding_volume_ == false) {
        getBoundingVolume();
    }

    glm::mat4 M = *Mat;
    float a, b;

    //Inspired by Graphics Gems - TransBox.c
    //Transform the AABB to the correct position in world space
    //Generate a new AABB from the non axis aligned bounding box

    transformed_bounding_box[0] = M[3].x;
    transformed_bounding_box[3] = M[3].x;

    transformed_bounding_box[1] = M[3].y;
    transformed_bounding_box[4] = M[3].y;

    transformed_bounding_box[2] = M[3].z;
    transformed_bounding_box[5] = M[3].z;

    glm::vec3 min_corner = bounding_volume.min_corner();
    glm::vec3 max_corner = bounding_volume.max_corner();

    for (int i = 0; i < 3; i++) {
        //x coord
        a = M[i].x * min_corner.x;
        b = M[i].x * max_corner.x;
        if (a < b) {
            transformed_bounding_box[0] += a;
            transformed_bounding_box[3] += b;
        } else {
            transformed_bounding_box[0] += b;
            transformed_bounding_box[3] += a;
        }

        //y coord
        a = M[i].y * min_corner.y;
        b = M[i].y * max_corner.y;
        if (a < b) {
            transformed_bounding_box[1] += a;
            transformed_bounding_box[4] += b;
        } else {
            transformed_bounding_box[1] += b;
            transformed_bounding_box[4] += a;
        }

        //z coord
        a = M[i].z * min_corner.z;
        b = M[i].z * max_corner.z;
        if (a < b) {
            transformed_bounding_box[2] += a;
            transformed_bounding_box[5] += b;
        } else {
            transformed_bounding_box[2] += b;
            transformed_bounding_box[5] += a;
        }
    }
}

void Mesh::bindVertexAttributes(GLuint programID)
{
    for (auto it = attribute_float_keys_.begin();
            it != attribute_float_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocF(loc, s);
    }
    for (auto it = attribute_vec2_keys_.begin();
            it != attribute_vec2_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV2(loc, s);
    }
    for (auto it = attribute_vec3_keys_.begin();
            it != attribute_vec3_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV3(loc, s);
    }
    for (auto it = attribute_vec4_keys_.begin();
            it != attribute_vec4_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV4(loc, s);
    }
}

// generate vertex array object
void Mesh::generateVAO() {
    GLuint tmpID;

    if (!vao_dirty_) {
         return;
    }
    obtainDeleter();
    deleteVaos();

    if (vertices_.size() == 0 && normals_.size() == 0
            && tex_coords_.size() == 0) {
        std::string error = "no vertex data yet, shouldn't call here. ";
        throw error;
        return;
    }

    glGenVertexArrays(1, &vaoID_);
    glBindVertexArray(vaoID_);

    glGenBuffers(1, &triangle_vboID_);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangle_vboID_);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
            sizeof(unsigned short) * indices_.size(), &indices_[0],
            GL_STATIC_DRAW);
    numTriangles_ = indices_.size() / 3;

    if (vertices_.size()) {
        glGenBuffers(1, &vert_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, vert_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices_.size(),
                &vertices_[0], GL_STATIC_DRAW);
        GLuint vertexLoc = GLProgram::POSITION_ATTRIBUTE_LOCATION;
        glEnableVertexAttribArray(vertexLoc);
        glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
    }

    if (normals_.size()) {
        glGenBuffers(1, &norm_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, norm_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * normals_.size(),
                &normals_[0], GL_STATIC_DRAW);
        GLuint normalLoc = GLProgram::NORMAL_ATTRIBUTE_LOCATION;
        glEnableVertexAttribArray(normalLoc);
        glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
    }

    if (tex_coords_.size()) {
        glGenBuffers(1, &tex_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, tex_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * tex_coords_.size(),
                &tex_coords_[0], GL_STATIC_DRAW);
        GLuint texCoordLoc = GLProgram::TEXCOORD_ATTRIBUT_LOCATION;
        glEnableVertexAttribArray(texCoordLoc);
        glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_float_keys_.begin();
            it != attribute_float_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(GLfloat) * getFloatVector(it->second).size(),
                getFloatVector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 1, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec2_keys_.begin();
            it != attribute_vec2_keys_.end(); ++it) {

        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec2) * getVec2Vector(it->second).size(),
                getVec2Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 2, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec3_keys_.begin();
            it != attribute_vec3_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec3) * getVec3Vector(it->second).size(),
                getVec3Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 3, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec4_keys_.begin();
            it != attribute_vec4_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec4) * getVec4Vector(it->second).size(),
                getVec4Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 4, GL_FLOAT, 0, 0, 0);
    }

    // done generation
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    vao_dirty_ = false;
}

void Mesh::generateBoneArrayBuffers() {
    if (!bone_data_dirty_) {
        return;
    }

    // delete
    if (boneVboID_ != GVR_INVALID) {
        deleter_->queueBuffer(boneVboID_);
        boneVboID_ = GVR_INVALID;
    }

    int nVertices = vertices().size();
    if (!vertexBoneData_.getNumBones() || !nVertices) {
        LOGV("no bones or vertices");
        return;
    }

    glBindVertexArray(vaoID_);

    // BoneID
    GLuint boneVboID;
    glGenBuffers(1, &boneVboID);
    glBindBuffer(GL_ARRAY_BUFFER, boneVboID);
    glBufferData(GL_ARRAY_BUFFER,
            sizeof(vertexBoneData_.boneData[0]) * vertexBoneData_.boneData.size(),
            &vertexBoneData_.boneData[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(getBoneIndicesLoc());
    glVertexAttribIPointer(getBoneIndicesLoc(), 4, GL_INT, sizeof(VertexBoneData::BoneData), (const GLvoid*) 0);

    // BoneWeight
    glEnableVertexAttribArray(getBoneWeightsLoc());
    glVertexAttribPointer(getBoneWeightsLoc(), 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData::BoneData),
            (const GLvoid*) (sizeof(VertexBoneData::BoneData::ids)));

    boneVboID_ = boneVboID;

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

}
<commit_msg>Clear bounding volume before calculating bounds for mesh<commit_after>/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/***************************************************************************
 * The mesh for rendering.
 ***************************************************************************/

#include "mesh.h"

#include <limits>

#include "assimp/Importer.hpp"
#include "assimp/mesh.h"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "util/gvr_log.h"
#include "util/gvr_gl.h"
#include "glm/gtc/matrix_inverse.hpp"
#include "../gl/gl_program.h"

namespace gvr {
Mesh* Mesh::createBoundingBox() {

    Mesh* mesh = new Mesh();

    getBoundingVolume(); // Make sure bounding_volume is valid

    glm::vec3 min_corner = bounding_volume.min_corner();
    glm::vec3 max_corner = bounding_volume.max_corner();

    float min_x = min_corner[0];
    float min_y = min_corner[1];
    float min_z = min_corner[2];
    float max_x = max_corner[0];
    float max_y = max_corner[1];
    float max_z = max_corner[2];

    mesh->vertices_.push_back(glm::vec3(min_x, min_y, min_z));
    mesh->vertices_.push_back(glm::vec3(max_x, min_y, min_z));
    mesh->vertices_.push_back(glm::vec3(min_x, max_y, min_z));
    mesh->vertices_.push_back(glm::vec3(max_x, max_y, min_z));
    mesh->vertices_.push_back(glm::vec3(min_x, min_y, max_z));
    mesh->vertices_.push_back(glm::vec3(max_x, min_y, max_z));
    mesh->vertices_.push_back(glm::vec3(min_x, max_y, max_z));
    mesh->vertices_.push_back(glm::vec3(max_x, max_y, max_z));

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(3);

    mesh->indices_.push_back(1);
    mesh->indices_.push_back(3);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(5);

    mesh->indices_.push_back(4);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(6);

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(0);
    mesh->indices_.push_back(4);
    mesh->indices_.push_back(6);

    mesh->indices_.push_back(0);
    mesh->indices_.push_back(1);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(0);
    mesh->indices_.push_back(5);
    mesh->indices_.push_back(4);

    mesh->indices_.push_back(2);
    mesh->indices_.push_back(7);
    mesh->indices_.push_back(3);
    mesh->indices_.push_back(2);
    mesh->indices_.push_back(6);
    mesh->indices_.push_back(7);

    return mesh;
}

// an array of size:6 with Xmin, Ymin, Zmin and Xmax, Ymax, Zmax values
const BoundingVolume& Mesh::getBoundingVolume() {
    if (have_bounding_volume_) {
        return bounding_volume;
    }
    bounding_volume.reset();
    for (auto it = vertices_.begin(); it != vertices_.end(); ++it) {
        bounding_volume.expand(*it);
    }

    have_bounding_volume_ = true;
    return bounding_volume;
}

void Mesh::getTransformedBoundingBoxInfo(glm::mat4 *Mat,
        float *transformed_bounding_box) {

    if (have_bounding_volume_ == false) {
        getBoundingVolume();
    }

    glm::mat4 M = *Mat;
    float a, b;

    //Inspired by Graphics Gems - TransBox.c
    //Transform the AABB to the correct position in world space
    //Generate a new AABB from the non axis aligned bounding box

    transformed_bounding_box[0] = M[3].x;
    transformed_bounding_box[3] = M[3].x;

    transformed_bounding_box[1] = M[3].y;
    transformed_bounding_box[4] = M[3].y;

    transformed_bounding_box[2] = M[3].z;
    transformed_bounding_box[5] = M[3].z;

    glm::vec3 min_corner = bounding_volume.min_corner();
    glm::vec3 max_corner = bounding_volume.max_corner();

    for (int i = 0; i < 3; i++) {
        //x coord
        a = M[i].x * min_corner.x;
        b = M[i].x * max_corner.x;
        if (a < b) {
            transformed_bounding_box[0] += a;
            transformed_bounding_box[3] += b;
        } else {
            transformed_bounding_box[0] += b;
            transformed_bounding_box[3] += a;
        }

        //y coord
        a = M[i].y * min_corner.y;
        b = M[i].y * max_corner.y;
        if (a < b) {
            transformed_bounding_box[1] += a;
            transformed_bounding_box[4] += b;
        } else {
            transformed_bounding_box[1] += b;
            transformed_bounding_box[4] += a;
        }

        //z coord
        a = M[i].z * min_corner.z;
        b = M[i].z * max_corner.z;
        if (a < b) {
            transformed_bounding_box[2] += a;
            transformed_bounding_box[5] += b;
        } else {
            transformed_bounding_box[2] += b;
            transformed_bounding_box[5] += a;
        }
    }
}

void Mesh::bindVertexAttributes(GLuint programID)
{
    for (auto it = attribute_float_keys_.begin();
            it != attribute_float_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocF(loc, s);
    }
    for (auto it = attribute_vec2_keys_.begin();
            it != attribute_vec2_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV2(loc, s);
    }
    for (auto it = attribute_vec3_keys_.begin();
            it != attribute_vec3_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV3(loc, s);
    }
    for (auto it = attribute_vec4_keys_.begin();
            it != attribute_vec4_keys_.end(); ++it) {
        std::string s = it->second;
        int loc = glGetAttribLocation(programID, s.c_str());
        setVertexAttribLocV4(loc, s);
    }
}

// generate vertex array object
void Mesh::generateVAO() {
    GLuint tmpID;

    if (!vao_dirty_) {
         return;
    }
    obtainDeleter();
    deleteVaos();

    if (vertices_.size() == 0 && normals_.size() == 0
            && tex_coords_.size() == 0) {
        std::string error = "no vertex data yet, shouldn't call here. ";
        throw error;
        return;
    }

    glGenVertexArrays(1, &vaoID_);
    glBindVertexArray(vaoID_);

    glGenBuffers(1, &triangle_vboID_);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangle_vboID_);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
            sizeof(unsigned short) * indices_.size(), &indices_[0],
            GL_STATIC_DRAW);
    numTriangles_ = indices_.size() / 3;

    if (vertices_.size()) {
        glGenBuffers(1, &vert_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, vert_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices_.size(),
                &vertices_[0], GL_STATIC_DRAW);
        GLuint vertexLoc = GLProgram::POSITION_ATTRIBUTE_LOCATION;
        glEnableVertexAttribArray(vertexLoc);
        glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
    }

    if (normals_.size()) {
        glGenBuffers(1, &norm_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, norm_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * normals_.size(),
                &normals_[0], GL_STATIC_DRAW);
        GLuint normalLoc = GLProgram::NORMAL_ATTRIBUTE_LOCATION;
        glEnableVertexAttribArray(normalLoc);
        glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
    }

    if (tex_coords_.size()) {
        glGenBuffers(1, &tex_vboID_);
        glBindBuffer(GL_ARRAY_BUFFER, tex_vboID_);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * tex_coords_.size(),
                &tex_coords_[0], GL_STATIC_DRAW);
        GLuint texCoordLoc = GLProgram::TEXCOORD_ATTRIBUT_LOCATION;
        glEnableVertexAttribArray(texCoordLoc);
        glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_float_keys_.begin();
            it != attribute_float_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(GLfloat) * getFloatVector(it->second).size(),
                getFloatVector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 1, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec2_keys_.begin();
            it != attribute_vec2_keys_.end(); ++it) {

        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec2) * getVec2Vector(it->second).size(),
                getVec2Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 2, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec3_keys_.begin();
            it != attribute_vec3_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec3) * getVec3Vector(it->second).size(),
                getVec3Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 3, GL_FLOAT, 0, 0, 0);
    }

    for (auto it = attribute_vec4_keys_.begin();
            it != attribute_vec4_keys_.end(); ++it) {
        glGenBuffers(1, &tmpID);
        glBindBuffer(GL_ARRAY_BUFFER, tmpID);
        glBufferData(GL_ARRAY_BUFFER,
                sizeof(glm::vec4) * getVec4Vector(it->second).size(),
                getVec4Vector(it->second).data(), GL_STATIC_DRAW);
        glEnableVertexAttribArray(it->first);
        glVertexAttribPointer(it->first, 4, GL_FLOAT, 0, 0, 0);
    }

    // done generation
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    vao_dirty_ = false;
}

void Mesh::generateBoneArrayBuffers() {
    if (!bone_data_dirty_) {
        return;
    }

    // delete
    if (boneVboID_ != GVR_INVALID) {
        deleter_->queueBuffer(boneVboID_);
        boneVboID_ = GVR_INVALID;
    }

    int nVertices = vertices().size();
    if (!vertexBoneData_.getNumBones() || !nVertices) {
        LOGV("no bones or vertices");
        return;
    }

    glBindVertexArray(vaoID_);

    // BoneID
    GLuint boneVboID;
    glGenBuffers(1, &boneVboID);
    glBindBuffer(GL_ARRAY_BUFFER, boneVboID);
    glBufferData(GL_ARRAY_BUFFER,
            sizeof(vertexBoneData_.boneData[0]) * vertexBoneData_.boneData.size(),
            &vertexBoneData_.boneData[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(getBoneIndicesLoc());
    glVertexAttribIPointer(getBoneIndicesLoc(), 4, GL_INT, sizeof(VertexBoneData::BoneData), (const GLvoid*) 0);

    // BoneWeight
    glEnableVertexAttribArray(getBoneWeightsLoc());
    glVertexAttribPointer(getBoneWeightsLoc(), 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData::BoneData),
            (const GLvoid*) (sizeof(VertexBoneData::BoneData::ids)));

    boneVboID_ = boneVboID;

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "path_util.h"

#include <stdlib.h>
//#include "zorba/zorba_string.h"
#include "zorba/util/path.h"

#include "util.h"
#include "zorbacmdproperties.h"
#include <zorba/static_context.h>

namespace zorba {

namespace PathUtil {

static std::string
getPathFromEnvironment(std::string const& aEnvVar)
{
#ifdef WIN32
  char* lBuffer;
  size_t lLen=0;
  errno_t lErr = getenv_s(&lLen, NULL, 0, aEnvVar.c_str());
  if (lErr || !lLen) return "";
  lBuffer = (char*)malloc(lLen * sizeof(char));
  if (!lBuffer) return "";
  getenv_s(&lLen, lBuffer, lLen, aEnvVar.c_str());
  std::string lRes(lBuffer);
  free(lBuffer);
  return lRes;
#else
  const char* lEnvValue = getenv(aEnvVar.c_str());
  return lEnvValue != 0 ? lEnvValue : "";
#endif
}

static void
tokenizePath(
  const std::string&    aPathStr,
  std::vector<String>&  aResult)
{
  std::vector<std::string> lPath;
#ifdef WIN32
  Util::tokenize(aPathStr, ";", lPath);
#else
  Util::tokenize(aPathStr, ":", lPath);
#endif
  for (std::vector<std::string>::iterator lIter = lPath.begin();
       lIter != lPath.end(); ++lIter) {
    aResult.push_back(*lIter);
  }
}

static String
concatenatePaths( const std::vector<String>& aPathList)
{
  String delimiter(filesystem_path::get_path_separator());

  String lResult;
  for (std::vector<String>::const_iterator lIter = aPathList.begin();
       lIter != aPathList.end(); ++lIter)
  {
    lResult += delimiter + *lIter;
  }

  return lResult;
}

void
setPathsOnContext(
  const ZorbaCMDProperties& aProperties,
  StaticContext_t& aStaticCtx)
{
  std::vector<String> lPath;
  std::string lPathStr, lEnvStr;

  // Compute the current working directory to append to all paths.
  filesystem_path lCWD;

  // setModulePaths() *overwrites* the URI path and lib path, so there's no
  // sense in calling both. So if either --module-path or ZORBA_MODULE_PATH
  // exists, just use those.
  aProperties.getModulePath(lPathStr);
  lEnvStr = getPathFromEnvironment("ZORBA_MODULE_PATH");
  if (lPathStr.length() > 0 || lEnvStr.length() > 0) {
    tokenizePath(lPathStr, lPath);
    tokenizePath(lEnvStr, lPath);
    lPath.push_back(lCWD.get_path());
    aStaticCtx->setModulePaths(lPath);
  }
  else {
    // Compute and set URI path
    aProperties.getURIPath(lPathStr);
    tokenizePath(lPathStr, lPath);
    lEnvStr = getPathFromEnvironment("ZORBA_URI_PATH");
    tokenizePath(lEnvStr, lPath);
    lPath.push_back(lCWD.get_path());
    aStaticCtx->setURIPath(lPath);
    lPath.clear();

    // Compute and set lib path
    aProperties.getLibPath(lPathStr);
    tokenizePath(lPathStr, lPath);
    lEnvStr = getPathFromEnvironment("ZORBA_LIB_PATH");
    lPath.push_back(lCWD.get_path());
    tokenizePath(lEnvStr, lPath);
    aStaticCtx->setLibPath(lPath);
  }

  // Compute and set JVM class path
  aProperties.getJVMClassPath(lPathStr);
  tokenizePath(lPathStr, lPath);
  lEnvStr = getPathFromEnvironment("CLASSPATH");
  lPath.push_back(lCWD.get_path());
  tokenizePath(lEnvStr, lPath);
  aStaticCtx->setJVMClassPath(lPath);
}

} /* namespace ModulePath */

} /* namespace zorba */
<commit_msg>Start moving --classpath commandline onto library path.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "path_util.h"

#include <stdlib.h>
//#include "zorba/zorba_string.h"
#include "zorba/util/path.h"

#include "util.h"
#include "zorbacmdproperties.h"
#include <zorba/static_context.h>

namespace zorba {

namespace PathUtil {

static std::string
getPathFromEnvironment(std::string const& aEnvVar)
{
#ifdef WIN32
  char* lBuffer;
  size_t lLen=0;
  errno_t lErr = getenv_s(&lLen, NULL, 0, aEnvVar.c_str());
  if (lErr || !lLen) return "";
  lBuffer = (char*)malloc(lLen * sizeof(char));
  if (!lBuffer) return "";
  getenv_s(&lLen, lBuffer, lLen, aEnvVar.c_str());
  std::string lRes(lBuffer);
  free(lBuffer);
  return lRes;
#else
  const char* lEnvValue = getenv(aEnvVar.c_str());
  return lEnvValue != 0 ? lEnvValue : "";
#endif
}

static void
tokenizePath(
  const std::string&    aPathStr,
  std::vector<String>&  aResult)
{
  std::vector<std::string> lPath;
#ifdef WIN32
  Util::tokenize(aPathStr, ";", lPath);
#else
  Util::tokenize(aPathStr, ":", lPath);
#endif
  for (std::vector<std::string>::iterator lIter = lPath.begin();
       lIter != lPath.end(); ++lIter) {
    aResult.push_back(*lIter);
  }
}

static String
concatenatePaths( const std::vector<String>& aPathList)
{
  String delimiter(filesystem_path::get_path_separator());

  String lResult;
  for (std::vector<String>::const_iterator lIter = aPathList.begin();
       lIter != aPathList.end(); ++lIter)
  {
    lResult += delimiter + *lIter;
  }

  return lResult;
}

void
setPathsOnContext(
  const ZorbaCMDProperties& aProperties,
  StaticContext_t& aStaticCtx)
{
  std::vector<String> lPath;
  std::string lPathStr, lEnvStr;

  // Compute the current working directory to append to all paths.
  filesystem_path lCWD;

  // setModulePaths() *overwrites* the URI path and lib path, so there's no
  // sense in calling both. So if either --module-path or ZORBA_MODULE_PATH
  // exists, just use those.
  aProperties.getModulePath(lPathStr);
  lEnvStr = getPathFromEnvironment("ZORBA_MODULE_PATH");
  if (lPathStr.length() > 0 || lEnvStr.length() > 0) {
    tokenizePath(lPathStr, lPath);
    tokenizePath(lEnvStr, lPath);
    lPath.push_back(lCWD.get_path());
    aStaticCtx->setModulePaths(lPath);
  }
  else {
    // Compute and set URI path
    aProperties.getURIPath(lPathStr);
    tokenizePath(lPathStr, lPath);
    lEnvStr = getPathFromEnvironment("ZORBA_URI_PATH");
    tokenizePath(lEnvStr, lPath);
    lPath.push_back(lCWD.get_path());
    aStaticCtx->setURIPath(lPath);
    lPath.clear();

    // Compute and set lib path
    aProperties.getLibPath(lPathStr);
    tokenizePath(lPathStr, lPath);
    lPath.push_back(lCWD.get_path());
    lEnvStr = getPathFromEnvironment("ZORBA_LIB_PATH");
    tokenizePath(lEnvStr, lPath);
    aStaticCtx->setLibPath(lPath);
  }

  // Compute and set JVM class path
//  aProperties.getJVMClassPath(lPathStr);
//  tokenizePath(lPathStr, lPath);
//  lEnvStr = getPathFromEnvironment("CLASSPATH");
//  lPath.push_back(lCWD.get_path());
//  tokenizePath(lEnvStr, lPath);
//  aStaticCtx->setJVMClassPath(lPath);

  lPath.clear();
  aStaticCtx->getLibPath(lPath);
  aProperties.getJVMClassPath(lPathStr);
  tokenizePath(lPathStr, lPath);
  lEnvStr = getPathFromEnvironment("CLASSPATH");
  tokenizePath(lEnvStr, lPath);
  aStaticCtx->setLibPath(lPath);
}

} /* namespace ModulePath */

} /* namespace zorba */
<|endoftext|>


<commit_before>// @(#) $Id: AliHLTTPCCANeighboursFinder1.cxx 27042 2008-07-02 12:06:02Z richterm $
// **************************************************************************
// This file is property of and copyright by the ALICE HLT Project          *
// ALICE Experiment at CERN, All rights reserved.                           *
//                                                                          *
// Primary Authors: Sergey Gorbunov <sergey.gorbunov@kip.uni-heidelberg.de> *
//                  Ivan Kisel <kisel@kip.uni-heidelberg.de>                *
//                  for The ALICE HLT Project.                              *
//                                                                          *
// Permission to use, copy, modify and distribute this software and its     *
// documentation strictly for non-commercial purposes is hereby granted     *
// without fee, provided that the above copyright notice appears in all     *
// copies and that both the copyright notice and this permission notice     *
// appear in the supporting documentation. The authors make no claims       *
// about the suitability of this software for any purpose. It is            *
// provided "as is" without express or implied warranty.                    *
//                                                                          *
//***************************************************************************

#include "AliHLTTPCCANeighboursFinder.h"
#include "AliHLTTPCCAMath.h"
#include "AliHLTTPCCAHitArea.h"
#include "AliHLTTPCCATracker.h"

//#define DRAW

#ifdef DRAW
#include "AliHLTTPCCADisplay.h"
#endif

GPUd() void AliHLTTPCCANeighboursFinder::Thread
( Int_t /*nBlocks*/, Int_t nThreads, Int_t iBlock, Int_t iThread, Int_t iSync,
  AliHLTTPCCASharedMemory &s, AliHLTTPCCATracker &tracker )
{
  //* find neighbours

  if( iSync==0 )
    {
      if( iThread==0 ){
	s.fNRows = tracker.Param().NRows();
	s.fIRow = iBlock;
	if( s.fIRow < s.fNRows ){
	  const AliHLTTPCCARow &row = tracker.Row(s.fIRow);
	  s.fFirst = row.FirstHit();
	  s.fNHits = row.NHits();

	  s.fHitLinkUp = ((Short_t*)(tracker.RowData() + row.FullOffset())) + row.FullLinkOffset();
	  s.fHitLinkDn = s.fHitLinkUp + row.NHits();

	  if( (s.fIRow>=2) && (s.fIRow<=s.fNRows-3) ){
	    s.fIRowUp = s.fIRow+2;
	    s.fIRowDn = s.fIRow-2;
	    s.fFirstDn = tracker.Row(s.fIRowDn).FirstHit();
	    s.fFirstUp = tracker.Row(s.fIRowUp).FirstHit();
	    float xDn = tracker.Row(s.fIRowDn).X();
	    float x = tracker.Row(s.fIRow).X();
	    float xUp = tracker.Row(s.fIRowUp).X();
	    s.fUpNHits = tracker.Row(s.fIRowUp).NHits();
	    s.fDnNHits = s.fFirst - s.fFirstDn;
	    s.fUpDx = xUp - x;
	    s.fDnDx = xDn - x;
	    s.fUpTx = xUp/x;
	    s.fDnTx = xDn/x;
	    s.fGridUp = tracker.Row(s.fIRowUp).Grid();
	    s.fGridDn = tracker.Row(s.fIRowDn).Grid();
	  }
	}
      }
    }
  else if( iSync==1 )
    {
      if( s.fIRow < s.fNRows ){
	if( (s.fIRow==0) || (s.fIRow==s.fNRows-1) || (s.fIRow==1) || (s.fIRow==s.fNRows-2) ){
	  for( Int_t ih=iThread; ih<s.fNHits; ih+=nThreads ){
	    s.fHitLinkUp[ih] = -1;
	    s.fHitLinkDn[ih] = -1;
	  }
	}else {
	  const AliHLTTPCCARow &rowUp = tracker.Row(s.fIRowUp);
	  const AliHLTTPCCARow &rowDn = tracker.Row(s.fIRowDn);
	  const UShort_t *gContentUp = (reinterpret_cast<const UShort_t*>(tracker.RowData() + rowUp.FullOffset())) + rowUp.FullGridOffset();
	  const UShort_t *gContentDn = (reinterpret_cast<const UShort_t*>(tracker.RowData() + rowDn.FullOffset())) + rowDn.FullGridOffset();

	  for( UInt_t ih=iThread; ih<s.fGridUp.N()+s.fGridUp.Ny()+2; ih+=nThreads ){
	    s.fGridContentUp[ih] = gContentUp[ih];
	  }
	  for( UInt_t ih=iThread; ih<s.fGridDn.N()+s.fGridDn.Ny()+2; ih+=nThreads ){
	    s.fGridContentDn[ih] = gContentDn[ih];
	  }
	}
      }
    }
  else if( iSync==2 )
    {
      if( (s.fIRow<=1) || (s.fIRow >= s.fNRows-2) ) return;

      //const float kAreaSize = 3;
      float chi2Cut = 3.*3.*4*(s.fUpDx*s.fUpDx + s.fDnDx*s.fDnDx );
      const float kAreaSize = 3;
      //float chi2Cut = 3.*3.*(s.fUpDx*s.fUpDx + s.fDnDx*s.fDnDx ); //SG
      const Int_t kMaxN = 20;

      const AliHLTTPCCARow &row = tracker.Row(s.fIRow);
      const AliHLTTPCCARow &rowUp = tracker.Row(s.fIRowUp);
      const AliHLTTPCCARow &rowDn = tracker.Row(s.fIRowDn);
      float y0 = row.Grid().YMin();
      float z0 = row.Grid().ZMin();
      float stepY = row.HstepY();
      float stepZ = row.HstepZ();
      const uint4* tmpint4 = tracker.RowData() + row.FullOffset();
      const ushort2 *hits = reinterpret_cast<const ushort2*>(tmpint4);

      for( Int_t ih=iThread; ih<s.fNHits; ih+=nThreads ){

	UShort_t *neighUp = s.fB[iThread];
	float2 *yzUp = s.fA[iThread];
	//UShort_t neighUp[5];
	//float2 yzUp[5];

	Int_t linkUp = -1;
	Int_t linkDn = -1;

	if( s.fDnNHits>0 && s.fUpNHits>0 ){

	  Int_t nNeighUp = 0;
	  AliHLTTPCCAHit h0;
	  {
	    ushort2 hh = hits[ih];
	    h0.SetY( y0 + hh.x*stepY );
	    h0.SetZ( z0 + hh.y*stepZ );
	  }
	  //h0 = tracker.Hits()[ s.fFirst + ih ];

	  float y = h0.Y();
	  float z = h0.Z();

	  AliHLTTPCCAHitArea areaDn, areaUp;
	  areaUp.Init( s.fGridUp,  s.fGridContentUp,s.fFirstUp, y*s.fUpTx, z*s.fUpTx, kAreaSize, kAreaSize );
	  areaDn.Init( s.fGridDn,  s.fGridContentDn,s.fFirstDn, y*s.fDnTx, z*s.fDnTx, kAreaSize, kAreaSize );

	  if( linkUp>=0 ){
	    AliHLTTPCCAHit h;
	    float y0Up = rowUp.Grid().YMin();
	    float z0Up = rowUp.Grid().ZMin();
	    float stepYUp  = rowUp.HstepY();
	    float stepZUp  = rowUp.HstepZ();
	    const uint4* tmpint4Up  = tracker.RowData() + rowUp.FullOffset();
	    const ushort2 *hitsUp  = reinterpret_cast<const ushort2*>(tmpint4Up );
	    ushort2 hh = hitsUp[linkUp];
	    h.SetY( y0Up  + hh.x*stepYUp  );
	    h.SetZ( z0Up  + hh.y*stepZUp  );
	    neighUp[0] = linkUp;
	    yzUp[0] = CAMath::MakeFloat2( s.fDnDx*(h.Y()-y), s.fDnDx*(h.Z()-z) );
	    nNeighUp = 1;
	  } else {
	    do{
	      AliHLTTPCCAHit h;
	      Int_t i = areaUp.GetNext( tracker, rowUp,s.fGridContentUp, h );
	      if( i<0 ) break;
	      neighUp[nNeighUp] = (UShort_t) i;
	      yzUp[nNeighUp] = CAMath::MakeFloat2( s.fDnDx*(h.Y()-y), s.fDnDx*(h.Z()-z) );
	      if( ++nNeighUp>=kMaxN ) break;
	    }while(1);
	  }

	  Int_t nNeighDn=0;

	  if( nNeighUp>0 ){

	    Int_t bestDn=-1, bestUp=-1;
	    float bestD=1.e10;

	    if( linkDn>=0 ){
	      AliHLTTPCCAHit h;
	      float y0Dn = rowDn.Grid().YMin();
	      float z0Dn  = rowDn.Grid().ZMin();
	      float stepYDn  = rowDn.HstepY();
	      float stepZDn  = rowDn.HstepZ();
	      const uint4* tmpint4Dn  = tracker.RowData() + rowDn.FullOffset();
	      const ushort2 *hitsDn  = reinterpret_cast<const ushort2*>(tmpint4Dn );
	      ushort2 hh = hitsDn [linkDn];
	      h.SetY( y0Dn  + hh.x*stepYDn  );
	      h.SetZ( z0Dn  + hh.y*stepZDn  );

	      nNeighDn = 1;

	      float2 yzdn = CAMath::MakeFloat2( s.fUpDx*(h.Y()-y), s.fUpDx*(h.Z()-z) );

	      for( Int_t iUp=0; iUp<nNeighUp; iUp++ ){
		float2 yzup = yzUp[iUp];
		float dy = yzdn.x - yzup.x;
		float dz = yzdn.y - yzup.y;
		float d = dy*dy + dz*dz;
		if( d<bestD ){
		  bestD = d;
		  bestDn = linkDn;
		  bestUp = iUp;
		}
	      }
	    } else {
	      do{
		AliHLTTPCCAHit h;
		Int_t i = areaDn.GetNext( tracker, rowDn,s.fGridContentDn,h );
		if( i<0 ) break;

		nNeighDn++;
		float2 yzdn = CAMath::MakeFloat2( s.fUpDx*(h.Y()-y), s.fUpDx*(h.Z()-z) );

		for( Int_t iUp=0; iUp<nNeighUp; iUp++ ){
		  float2 yzup = yzUp[iUp];
		  float dy = yzdn.x - yzup.x;
		  float dz = yzdn.y - yzup.y;
		  float d = dy*dy + dz*dz;
		  if( d<bestD ){
		    bestD = d;
		    bestDn = i;
		    bestUp = iUp;
		  }
		}
	      }while(1);
	    }

	    if( bestD <= chi2Cut ){
	      linkUp = neighUp[bestUp];
	      linkDn = bestDn;
	    }
	  }
#ifdef DRAW
	  std::cout<<"n NeighUp = "<<nNeighUp<<", n NeighDn = "<<nNeighDn<<std::endl;
#endif

	}

	s.fHitLinkUp[ih] = linkUp;
	s.fHitLinkDn[ih] = linkDn;
#ifdef DRAW
	std::cout<<"Links for row "<<s.fIRow<<", hit "<<ih<<": "<<linkUp<<" "<<linkDn<<std::endl;
	if( s.fIRow==22 && ih==5 )
	  {
	  AliHLTTPCCADisplay::Instance().DrawSliceLink(s.fIRow, ih, -1, -1, 1);
	  AliHLTTPCCADisplay::Instance().DrawSliceHit(s.fIRow, ih, kBlue, 1.);
	  AliHLTTPCCADisplay::Instance().Ask();
	}
#endif
      }
    }
}

<commit_msg>old code removed<commit_after>// @(#) $Id: AliHLTTPCCANeighboursFinder1.cxx 27042 2008-07-02 12:06:02Z richterm $
// **************************************************************************
// This file is property of and copyright by the ALICE HLT Project          *
// ALICE Experiment at CERN, All rights reserved.                           *
//                                                                          *
// Primary Authors: Sergey Gorbunov <sergey.gorbunov@kip.uni-heidelberg.de> *
//                  Ivan Kisel <kisel@kip.uni-heidelberg.de>                *
//                  for The ALICE HLT Project.                              *
//                                                                          *
// Permission to use, copy, modify and distribute this software and its     *
// documentation strictly for non-commercial purposes is hereby granted     *
// without fee, provided that the above copyright notice appears in all     *
// copies and that both the copyright notice and this permission notice     *
// appear in the supporting documentation. The authors make no claims       *
// about the suitability of this software for any purpose. It is            *
// provided "as is" without express or implied warranty.                    *
//                                                                          *
//***************************************************************************

#include "AliHLTTPCCANeighboursFinder.h"
#include "AliHLTTPCCAMath.h"
#include "AliHLTTPCCAHitArea.h"
#include "AliHLTTPCCATracker.h"

//#define DRAW

#ifdef DRAW
#include "AliHLTTPCCADisplay.h"
#endif

GPUd() void AliHLTTPCCANeighboursFinder::Thread
( Int_t /*nBlocks*/, Int_t nThreads, Int_t iBlock, Int_t iThread, Int_t iSync,
  AliHLTTPCCASharedMemory &s, AliHLTTPCCATracker &tracker )
{
  //* find neighbours

  if( iSync==0 )
    {
      if( iThread==0 ){
	s.fNRows = tracker.Param().NRows();
	s.fIRow = iBlock;
	if( s.fIRow < s.fNRows ){
	  const AliHLTTPCCARow &row = tracker.Row(s.fIRow);
	  s.fFirst = row.FirstHit();
	  s.fNHits = row.NHits();

	  s.fHitLinkUp = ((Short_t*)(tracker.RowData() + row.FullOffset())) + row.FullLinkOffset();
	  s.fHitLinkDn = s.fHitLinkUp + row.NHits();

	  if( (s.fIRow>=2) && (s.fIRow<=s.fNRows-3) ){
	    s.fIRowUp = s.fIRow+2;
	    s.fIRowDn = s.fIRow-2;
	    s.fFirstDn = tracker.Row(s.fIRowDn).FirstHit();
	    s.fFirstUp = tracker.Row(s.fIRowUp).FirstHit();
	    float xDn = tracker.Row(s.fIRowDn).X();
	    float x = tracker.Row(s.fIRow).X();
	    float xUp = tracker.Row(s.fIRowUp).X();
	    s.fUpNHits = tracker.Row(s.fIRowUp).NHits();
	    s.fDnNHits = s.fFirst - s.fFirstDn;
	    s.fUpDx = xUp - x;
	    s.fDnDx = xDn - x;
	    s.fUpTx = xUp/x;
	    s.fDnTx = xDn/x;
	    s.fGridUp = tracker.Row(s.fIRowUp).Grid();
	    s.fGridDn = tracker.Row(s.fIRowDn).Grid();
	  }
	}
      }
    }
  else if( iSync==1 )
    {
      if( s.fIRow < s.fNRows ){
	if( (s.fIRow==0) || (s.fIRow==s.fNRows-1) || (s.fIRow==1) || (s.fIRow==s.fNRows-2) ){
	  for( Int_t ih=iThread; ih<s.fNHits; ih+=nThreads ){
	    s.fHitLinkUp[ih] = -1;
	    s.fHitLinkDn[ih] = -1;
	  }
	}else {
	  const AliHLTTPCCARow &rowUp = tracker.Row(s.fIRowUp);
	  const AliHLTTPCCARow &rowDn = tracker.Row(s.fIRowDn);
	  const UShort_t *gContentUp = (reinterpret_cast<const UShort_t*>(tracker.RowData() + rowUp.FullOffset())) + rowUp.FullGridOffset();
	  const UShort_t *gContentDn = (reinterpret_cast<const UShort_t*>(tracker.RowData() + rowDn.FullOffset())) + rowDn.FullGridOffset();

	  for( UInt_t ih=iThread; ih<s.fGridUp.N()+s.fGridUp.Ny()+2; ih+=nThreads ){
	    s.fGridContentUp[ih] = gContentUp[ih];
	  }
	  for( UInt_t ih=iThread; ih<s.fGridDn.N()+s.fGridDn.Ny()+2; ih+=nThreads ){
	    s.fGridContentDn[ih] = gContentDn[ih];
	  }
	}
      }
    }
  else if( iSync==2 )
    {
      if( (s.fIRow<=1) || (s.fIRow >= s.fNRows-2) ) return;

      //const float kAreaSize = 3;
      float chi2Cut = 3.*3.*4*(s.fUpDx*s.fUpDx + s.fDnDx*s.fDnDx );
      const float kAreaSize = 3;
      //float chi2Cut = 3.*3.*(s.fUpDx*s.fUpDx + s.fDnDx*s.fDnDx ); //SG
      const Int_t kMaxN = 20;

      const AliHLTTPCCARow &row = tracker.Row(s.fIRow);
      const AliHLTTPCCARow &rowUp = tracker.Row(s.fIRowUp);
      const AliHLTTPCCARow &rowDn = tracker.Row(s.fIRowDn);
      float y0 = row.Grid().YMin();
      float z0 = row.Grid().ZMin();
      float stepY = row.HstepY();
      float stepZ = row.HstepZ();
      const uint4* tmpint4 = tracker.RowData() + row.FullOffset();
      const ushort2 *hits = reinterpret_cast<const ushort2*>(tmpint4);

      for( Int_t ih=iThread; ih<s.fNHits; ih+=nThreads ){

	UShort_t *neighUp = s.fB[iThread];
	float2 *yzUp = s.fA[iThread];
	//UShort_t neighUp[5];
	//float2 yzUp[5];

	Int_t linkUp = -1;
	Int_t linkDn = -1;

	if( s.fDnNHits>0 && s.fUpNHits>0 ){

	  Int_t nNeighUp = 0;
	  AliHLTTPCCAHit h0;
	  {
	    ushort2 hh = hits[ih];
	    h0.SetY( y0 + hh.x*stepY );
	    h0.SetZ( z0 + hh.y*stepZ );
	  }
	  //h0 = tracker.Hits()[ s.fFirst + ih ];

	  float y = h0.Y();
	  float z = h0.Z();

	  AliHLTTPCCAHitArea areaDn, areaUp;
	  areaUp.Init( s.fGridUp,  s.fGridContentUp,s.fFirstUp, y*s.fUpTx, z*s.fUpTx, kAreaSize, kAreaSize );
	  areaDn.Init( s.fGridDn,  s.fGridContentDn,s.fFirstDn, y*s.fDnTx, z*s.fDnTx, kAreaSize, kAreaSize );

	  do{
	    AliHLTTPCCAHit h;
	    Int_t i = areaUp.GetNext( tracker, rowUp,s.fGridContentUp, h );
	    if( i<0 ) break;
	    neighUp[nNeighUp] = (UShort_t) i;
	    yzUp[nNeighUp] = CAMath::MakeFloat2( s.fDnDx*(h.Y()-y), s.fDnDx*(h.Z()-z) );
	    if( ++nNeighUp>=kMaxN ) break;
	  }while(1);

	  Int_t nNeighDn=0;

	  if( nNeighUp>0 ){

	    Int_t bestDn=-1, bestUp=-1;
	    float bestD=1.e10;

	    do{
	      AliHLTTPCCAHit h;
	      Int_t i = areaDn.GetNext( tracker, rowDn,s.fGridContentDn,h );
	      if( i<0 ) break;

	      nNeighDn++;
	      float2 yzdn = CAMath::MakeFloat2( s.fUpDx*(h.Y()-y), s.fUpDx*(h.Z()-z) );

	      for( Int_t iUp=0; iUp<nNeighUp; iUp++ ){
		float2 yzup = yzUp[iUp];
		float dy = yzdn.x - yzup.x;
		float dz = yzdn.y - yzup.y;
		float d = dy*dy + dz*dz;
		if( d<bestD ){
		  bestD = d;
		  bestDn = i;
		  bestUp = iUp;
		}
	      }
	    }while(1);

	    if( bestD <= chi2Cut ){
	      linkUp = neighUp[bestUp];
	      linkDn = bestDn;
	    }
	  }
#ifdef DRAW
	  std::cout<<"n NeighUp = "<<nNeighUp<<", n NeighDn = "<<nNeighDn<<std::endl;
#endif

	}

	s.fHitLinkUp[ih] = linkUp;
	s.fHitLinkDn[ih] = linkDn;
#ifdef DRAW
	std::cout<<"Links for row "<<s.fIRow<<", hit "<<ih<<": "<<linkUp<<" "<<linkDn<<std::endl;
	if( s.fIRow==22 && ih==5 )
	  {
	  AliHLTTPCCADisplay::Instance().DrawSliceLink(s.fIRow, ih, -1, -1, 1);
	  AliHLTTPCCADisplay::Instance().DrawSliceHit(s.fIRow, ih, kBlue, 1.);
	  AliHLTTPCCADisplay::Instance().Ask();
	}
#endif
      }
    }
}

<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    TestRandomPKMeansStatisticsMPI.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*
 * Copyright 2011 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
// .SECTION Thanks
// Thanks to Janine Bennett, Philippe Pebay, and David Thompson from Sandia National Laboratories
// for implementing this test.

#include <mpi.h>

#include "vtkPKMeansStatistics.h"

#include "vtkMath.h"
#include "vtkMPIController.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkStdString.h"
#include "vtkTable.h"
#include "vtkTimerLog.h"
#include "vtkVariantArray.h"
#include "vtkIdTypeArray.h"
#include "vtkDoubleArray.h"

struct RandomSampleStatisticsArgs
{
  int nVals;
  int nProcs;
  int* retVal;
  int ioRank;
};

// This will be called by all processes
void RandomSampleStatistics( vtkMultiProcessController* controller, void* arg )
{
  // Get test parameters
  RandomSampleStatisticsArgs* args = reinterpret_cast<RandomSampleStatisticsArgs*>( arg );
  *(args->retVal) = 0;

  // Get MPI communicator
  vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast( controller->GetCommunicator() );

  // Get local rank
  int myRank = com->GetLocalProcessId();

  // Seed random number generator
  vtkMath::RandomSeed( static_cast<int>( vtkTimerLog::GetUniversalTime() ) * ( myRank + 1 ) );

  // Generate an input table that contains samples of mutually independent random variables over [0, 1]
  int nVariables = 6;

  vtkTable* inputData = vtkTable::New();
  vtkDoubleArray* doubleArray;
  vtkStdString columnNames[] = { "Normal 0",
                                 "Normal 1",
                                 "Normal 2",
                                 "Normal 3",
                                 "Normal 4",
                                 "Normal 5"};

  int numClusters = 8;
  int observationsPerCluster = args->nVals/numClusters;

  // Generate samples
  for ( int v = 0; v < nVariables; ++ v )
    {
    doubleArray = vtkDoubleArray::New();
    doubleArray->SetNumberOfComponents( 1 );
    doubleArray->SetName( columnNames[v] );

    for ( int c = 0; c < numClusters; ++ c )
      {
      double x;
      for ( int r = 0; r < observationsPerCluster; ++ r )
        {
        x = vtkMath::Gaussian(c*7.0, 1.0);
        doubleArray->InsertNextValue( x );
        }
      }

    inputData->AddColumn( doubleArray );
    doubleArray->Delete();
    }

  // set up a single set of param data - send out to all and make tables...
  vtkTable* paramData = vtkTable::New();
  vtkIdTypeArray* paramCluster;
  vtkDoubleArray* paramArray;
  paramCluster = vtkIdTypeArray::New();
  paramCluster->SetName( "K" );

  for( int nInRun = 0; nInRun < numClusters; nInRun++ )
    {
    paramCluster->InsertNextValue( numClusters );
    }

  paramData->AddColumn( paramCluster );
  paramCluster->Delete();

  int nClusterCoords = (numClusters)*nVariables;
  double* clusterCoords = new double[nClusterCoords];

  // generate data on one node only
  if( myRank == args->ioRank )
    {
    int cIndex = 0;
    for ( int v = 0; v < nVariables; ++ v )
      {
      for ( int c = 0; c < (numClusters); ++ c )
        {
        double x = inputData->GetValue((c%numClusters)*observationsPerCluster, v).ToDouble();
        clusterCoords[cIndex++] = x;
        }
      }
    }

  // broadcast data to all nodes
  if( !com->Broadcast( clusterCoords, nClusterCoords, args->ioRank) )
    {
    vtkGenericWarningMacro("Could not broadcast initial cluster coordinates.");
    *(args->retVal) = 1;
    return;
    }

  for ( int c = 0; c < nVariables; ++ c )
    {
    paramArray = vtkDoubleArray::New();
    paramArray->SetName( columnNames[c] );
    paramArray->SetNumberOfTuples( numClusters );
    memcpy( paramArray->GetPointer( 0 ), &(clusterCoords[c*(numClusters)]), (numClusters)*sizeof( double ) );
    paramData->AddColumn( paramArray );
    paramArray->Delete();
    }

  delete [] clusterCoords;

  // ************************** KMeans Statistics **************************

  // Synchronize and start clock
  com->Barrier();
  vtkTimerLog *timer=vtkTimerLog::New();
  timer->StartTimer();

  // Instantiate a parallel KMeans statistics engine and set its ports
  vtkPKMeansStatistics* pks = vtkPKMeansStatistics::New();
  pks->SetInput( vtkStatisticsAlgorithm::INPUT_DATA, inputData );
  pks->SetMaxNumIterations( 10 );
  pks->SetInput( vtkStatisticsAlgorithm::LEARN_PARAMETERS, paramData );

  // Select columns for testing
  pks->SetColumnStatus( inputData->GetColumnName( 0 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 1 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 2 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 3 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 4 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 5 ) , 1 );
  pks->RequestSelectedColumns();

  // Test (in parallel) with Learn, Derive, and Assess options turned on
  pks->SetLearnOption( true );
  pks->SetDeriveOption( true );
  pks->SetAssessOption( true );
  pks->Update();

  // Synchronize and stop clock
  com->Barrier();
  timer->StopTimer();

  if ( myRank == args->ioRank )
    {
    vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast( pks->GetOutputDataObject( vtkStatisticsAlgorithm::OUTPUT_MODEL ) );

    cout << "\n## Completed parallel calculation of kmeans statistics (with assessment):\n"
         << "   Wall time: "
         << timer->GetElapsedTime()
         << " sec.\n";
    for ( unsigned int b = 0; b < outputMetaDS->GetNumberOfBlocks(); ++ b )
      {
      vtkTable* outputMeta = vtkTable::SafeDownCast( outputMetaDS->GetBlock( b ) );
      if ( b == 0 )
        {
        vtkIdType testIntValue = 0;
        for( vtkIdType r = 0; r < outputMeta->GetNumberOfRows(); r++ )
          {
          testIntValue += outputMeta->GetValueByName( r, "Cardinality" ).ToInt();
          }

        cout << "## Computed clusters (cardinality: "
             << testIntValue
             << " / run):\n";

        if ( testIntValue != args->nVals*args->nProcs )
          {
          vtkGenericWarningMacro("Sum of cluster cardinalities is incorrect: "
                               << testIntValue
                               << " != "
                               << args->nVals * args->nProcs
                               << ".");
          *(args->retVal) = 1;
          }
        }
      else
        {
        cout << "   Ranked cluster: " << "\n";
        }
        outputMeta->Dump();
      }
    }
  // Clean up
  pks->Delete();
  inputData->Delete();
  timer->Delete();
  paramData->Delete();

}

//----------------------------------------------------------------------------
int main( int argc, char** argv )
{
  // **************************** MPI Initialization ***************************
  vtkMPIController* controller = vtkMPIController::New();
  controller->Initialize( &argc, &argv );

  // If an MPI controller was not created, terminate in error.
  if ( ! controller->IsA( "vtkMPIController" ) )
    {
    vtkGenericWarningMacro("Failed to initialize a MPI controller.");
    controller->Delete();
    return 1;
    }

  vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast( controller->GetCommunicator() );

  // ************************** Find an I/O node ********************************
  int* ioPtr;
  int ioRank;
  int flag;

  MPI_Attr_get( MPI_COMM_WORLD,
                MPI_IO,
                &ioPtr,
                &flag );

  if ( ( ! flag ) || ( *ioPtr == MPI_PROC_NULL ) )
    {
    // Getting MPI attributes did not return any I/O node found.
    ioRank = MPI_PROC_NULL;
    vtkGenericWarningMacro("No MPI I/O nodes found.");

    // As no I/O node was found, we need an unambiguous way to report the problem.
    // This is the only case when a testValue of -1 will be returned
    controller->Finalize();
    controller->Delete();

    return -1;
    }
  else
    {
    if ( *ioPtr == MPI_ANY_SOURCE )
      {
      // Anyone can do the I/O trick--just pick node 0.
      ioRank = 0;
      }
    else
      {
      // Only some nodes can do I/O. Make sure everyone agrees on the choice (min).
      com->AllReduce( ioPtr,
                      &ioRank,
                      1,
                      vtkCommunicator::MIN_OP );
      }
    }

  // ************************** Initialize test *********************************
  if ( com->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Process "
         << ioRank
         << " will be the I/O node.\n";
    }

  // Check how many processes have been made available
  int numProcs = controller->GetNumberOfProcesses();
  if ( controller->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Running test with "
         << numProcs
         << " processes...\n";
    }

  // Parameters for regression test.
  int testValue = 0;
  RandomSampleStatisticsArgs args;
  args.nVals = 10000;
  args.nProcs = numProcs;
  args.retVal = &testValue;
  args.ioRank = ioRank;

  // Execute the function named "process" on both processes
  controller->SetSingleMethod( RandomSampleStatistics, &args );
  controller->SingleMethodExecute();

  // Clean up and exit
  if ( com->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Test completed.\n\n";
    }

  controller->Finalize();
  controller->Delete();

  return testValue;
}
<commit_msg>Make input cluster means a parameter (for parametric testing)<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestRandomPKMeansStatisticsMPI.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*
 * Copyright 2011 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
// .SECTION Thanks
// Thanks to Janine Bennett, Philippe Pebay, and David Thompson from Sandia National Laboratories
// for implementing this test.

#include <mpi.h>

#include "vtkPKMeansStatistics.h"

#include "vtkMath.h"
#include "vtkMPIController.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkStdString.h"
#include "vtkTable.h"
#include "vtkTimerLog.h"
#include "vtkVariantArray.h"
#include "vtkIdTypeArray.h"
#include "vtkDoubleArray.h"

struct RandomSampleStatisticsArgs
{
  int nVals;
  int nProcs;
  double meanFactor;
  int* retVal;
  int ioRank;
};

// This will be called by all processes
void RandomSampleStatistics( vtkMultiProcessController* controller, void* arg )
{
  // Get test parameters
  RandomSampleStatisticsArgs* args = reinterpret_cast<RandomSampleStatisticsArgs*>( arg );
  *(args->retVal) = 0;

  // Get MPI communicator
  vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast( controller->GetCommunicator() );

  // Get local rank
  int myRank = com->GetLocalProcessId();

  // Seed random number generator
  vtkMath::RandomSeed( static_cast<int>( vtkTimerLog::GetUniversalTime() ) * ( myRank + 1 ) );

  // Generate an input table that contains samples of mutually independent random variables over [0, 1]
  int nVariables = 6;

  vtkTable* inputData = vtkTable::New();
  vtkDoubleArray* doubleArray;
  vtkStdString columnNames[] = { "Normal 0",
                                 "Normal 1",
                                 "Normal 2",
                                 "Normal 3",
                                 "Normal 4",
                                 "Normal 5"};

  int numClusters = 8;
  int observationsPerCluster = args->nVals/numClusters;

  // Generate samples
  for ( int v = 0; v < nVariables; ++ v )
    {
    doubleArray = vtkDoubleArray::New();
    doubleArray->SetNumberOfComponents( 1 );
    doubleArray->SetName( columnNames[v] );

    for ( int c = 0; c < numClusters; ++ c )
      {
      double x;
      for ( int r = 0; r < observationsPerCluster; ++ r )
        {
        x = vtkMath::Gaussian( c * args->meanFactor, 1.0 );
        doubleArray->InsertNextValue( x );
        }
      }

    inputData->AddColumn( doubleArray );
    doubleArray->Delete();
    }

  // set up a single set of param data - send out to all and make tables...
  vtkTable* paramData = vtkTable::New();
  vtkIdTypeArray* paramCluster;
  vtkDoubleArray* paramArray;
  paramCluster = vtkIdTypeArray::New();
  paramCluster->SetName( "K" );

  for( int nInRun = 0; nInRun < numClusters; nInRun++ )
    {
    paramCluster->InsertNextValue( numClusters );
    }

  paramData->AddColumn( paramCluster );
  paramCluster->Delete();

  int nClusterCoords = (numClusters)*nVariables;
  double* clusterCoords = new double[nClusterCoords];

  // generate data on one node only
  if( myRank == args->ioRank )
    {
    int cIndex = 0;
    for ( int v = 0; v < nVariables; ++ v )
      {
      for ( int c = 0; c < (numClusters); ++ c )
        {
        double x = inputData->GetValue((c%numClusters)*observationsPerCluster, v).ToDouble();
        clusterCoords[cIndex++] = x;
        }
      }
    }

  // broadcast data to all nodes
  if( !com->Broadcast( clusterCoords, nClusterCoords, args->ioRank) )
    {
    vtkGenericWarningMacro("Could not broadcast initial cluster coordinates.");
    *(args->retVal) = 1;
    return;
    }

  for ( int c = 0; c < nVariables; ++ c )
    {
    paramArray = vtkDoubleArray::New();
    paramArray->SetName( columnNames[c] );
    paramArray->SetNumberOfTuples( numClusters );
    memcpy( paramArray->GetPointer( 0 ), &(clusterCoords[c*(numClusters)]), (numClusters)*sizeof( double ) );
    paramData->AddColumn( paramArray );
    paramArray->Delete();
    }

  delete [] clusterCoords;

  // ************************** KMeans Statistics **************************

  // Synchronize and start clock
  com->Barrier();
  vtkTimerLog *timer=vtkTimerLog::New();
  timer->StartTimer();

  // Instantiate a parallel KMeans statistics engine and set its ports
  vtkPKMeansStatistics* pks = vtkPKMeansStatistics::New();
  pks->SetInput( vtkStatisticsAlgorithm::INPUT_DATA, inputData );
  pks->SetMaxNumIterations( 10 );
  pks->SetInput( vtkStatisticsAlgorithm::LEARN_PARAMETERS, paramData );

  // Select columns for testing
  pks->SetColumnStatus( inputData->GetColumnName( 0 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 1 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 2 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 3 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 4 ) , 1 );
  pks->SetColumnStatus( inputData->GetColumnName( 5 ) , 1 );
  pks->RequestSelectedColumns();

  // Test (in parallel) with Learn, Derive, and Assess options turned on
  pks->SetLearnOption( true );
  pks->SetDeriveOption( true );
  pks->SetAssessOption( true );
  pks->Update();

  // Synchronize and stop clock
  com->Barrier();
  timer->StopTimer();

  if ( myRank == args->ioRank )
    {
    vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast( pks->GetOutputDataObject( vtkStatisticsAlgorithm::OUTPUT_MODEL ) );

    cout << "\n## Completed parallel calculation of kmeans statistics (with assessment):\n"
         << "   Wall time: "
         << timer->GetElapsedTime()
         << " sec.\n";
    for ( unsigned int b = 0; b < outputMetaDS->GetNumberOfBlocks(); ++ b )
      {
      vtkTable* outputMeta = vtkTable::SafeDownCast( outputMetaDS->GetBlock( b ) );
      if ( b == 0 )
        {
        vtkIdType testIntValue = 0;
        for( vtkIdType r = 0; r < outputMeta->GetNumberOfRows(); r++ )
          {
          testIntValue += outputMeta->GetValueByName( r, "Cardinality" ).ToInt();
          }

        cout << "## Computed clusters (cardinality: "
             << testIntValue
             << " / run):\n";

        if ( testIntValue != args->nVals*args->nProcs )
          {
          vtkGenericWarningMacro("Sum of cluster cardinalities is incorrect: "
                               << testIntValue
                               << " != "
                               << args->nVals * args->nProcs
                               << ".");
          *(args->retVal) = 1;
          }
        }
      else
        {
        cout << "   Ranked cluster: " << "\n";
        }
        outputMeta->Dump();
      }
    }
  // Clean up
  pks->Delete();
  inputData->Delete();
  timer->Delete();
  paramData->Delete();

}

//----------------------------------------------------------------------------
int main( int argc, char** argv )
{
  // **************************** MPI Initialization ***************************
  vtkMPIController* controller = vtkMPIController::New();
  controller->Initialize( &argc, &argv );

  // If an MPI controller was not created, terminate in error.
  if ( ! controller->IsA( "vtkMPIController" ) )
    {
    vtkGenericWarningMacro("Failed to initialize a MPI controller.");
    controller->Delete();
    return 1;
    }

  vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast( controller->GetCommunicator() );

  // ************************** Find an I/O node ********************************
  int* ioPtr;
  int ioRank;
  int flag;

  MPI_Attr_get( MPI_COMM_WORLD,
                MPI_IO,
                &ioPtr,
                &flag );

  if ( ( ! flag ) || ( *ioPtr == MPI_PROC_NULL ) )
    {
    // Getting MPI attributes did not return any I/O node found.
    ioRank = MPI_PROC_NULL;
    vtkGenericWarningMacro("No MPI I/O nodes found.");

    // As no I/O node was found, we need an unambiguous way to report the problem.
    // This is the only case when a testValue of -1 will be returned
    controller->Finalize();
    controller->Delete();

    return -1;
    }
  else
    {
    if ( *ioPtr == MPI_ANY_SOURCE )
      {
      // Anyone can do the I/O trick--just pick node 0.
      ioRank = 0;
      }
    else
      {
      // Only some nodes can do I/O. Make sure everyone agrees on the choice (min).
      com->AllReduce( ioPtr,
                      &ioRank,
                      1,
                      vtkCommunicator::MIN_OP );
      }
    }

  // ************************** Initialize test *********************************
  if ( com->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Process "
         << ioRank
         << " will be the I/O node.\n";
    }

  // Check how many processes have been made available
  int numProcs = controller->GetNumberOfProcesses();
  if ( controller->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Running test with "
         << numProcs
         << " processes...\n";
    }

  // Parameters for regression test.
  int testValue = 0;
  RandomSampleStatisticsArgs args;
  args.nVals = 10000;
  args.nProcs = numProcs;
  args.meanFactor = 7.;
  args.retVal = &testValue;
  args.ioRank = ioRank;

  // Execute the function named "process" on both processes
  controller->SetSingleMethod( RandomSampleStatistics, &args );
  controller->SingleMethodExecute();

  // Clean up and exit
  if ( com->GetLocalProcessId() == ioRank )
    {
    cout << "\n# Test completed.\n\n";
    }

  controller->Finalize();
  controller->Delete();

  return testValue;
}
<|endoftext|>