<commit_before>//==============================================================================
// CellML annotation view details widget
//==============================================================================

#include "cellmlannotationviewdetailswidget.h"
#include "cellmlannotationviewwidget.h"
#include "treeview.h"

//==============================================================================

#include "ui_cellmlannotationviewdetailswidget.h"

//==============================================================================

#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QScrollBar>

//==============================================================================

namespace OpenCOR {
namespace CellMLAnnotationView {

//==============================================================================

CellmlAnnotationViewDetailsWidget::CellmlAnnotationViewDetailsWidget(CellmlAnnotationViewWidget *pParent) :
    QScrollArea(pParent),
    Core::CommonWidget(pParent),
    mParent(pParent),
    mGui(new Ui::CellmlAnnotationViewDetailsWidget),
    mCellmlItems(CellmlItems()),
    mRdfTriples(CellMLSupport::CellmlFileRdfTriples()),
    mCellmlWidget(0),
    mCellmlFormLayout(0),
    mCellmlCmetaIdValue(0),
    mMetadataWidget(0),
    mMetadataFormLayout(0),
    mMetadataTreeView(0),
    mMetadataDataModel(0)
{
    // Set up the GUI

    mGui->setupUi(this);
}

//==============================================================================

CellmlAnnotationViewDetailsWidget::~CellmlAnnotationViewDetailsWidget()
{
    // Delete the GUI

    delete mGui;
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::retranslateUi()
{
    // Retranslate our GUI

    mGui->retranslateUi(this);

    // Update the GUI (since some widgets get reinitialised as a result of the
    // retranslation)

    delete takeWidget();   // This will force the GUI to be recreated from
                            // scratch and everything to be retranslated

    updateGui(mCellmlItems, mRdfTriples);
}

//==============================================================================

CellmlAnnotationViewDetailsWidget::CellmlItem CellmlAnnotationViewDetailsWidget::cellmlItem(const Type &pType,
                                                                                CellMLSupport::CellmlFileElement *pElement,
                                                                                const int &pNumber)
{
    // Return a formatted CellmlItem 'object'

    CellmlItem res;

    res.type    = pType;
    res.element = pElement;
    res.number  = pNumber;

    return res;
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellmlItems &pCellmlItems,
                                                  const CellMLSupport::CellmlFileRdfTriples &pRdfTriples)
{
    // Hide ourselves (since we may potentially update ourselves quite a bit and
    // we want to avoid any flickering)
    // Note #1: one would normally use setUpdatesEnabled(), but it still results
    //          in bad flickering on Mac OS X, so...
    // Note #2: it's surprising that setVisible() doesn't cause any flickering
    //          on any of the platforms we are targetting, but let's not
    //          complain...

    setVisible(false);

    // Keep track of the CellML items and metadata group name

    mCellmlItems = pCellmlItems;
    mRdfTriples  = pRdfTriples;

    // Check whether we are dealing with some metadata or not

    if (pCellmlItems.count()) {
        // We are not dealing with some metadata, so enable the CellML side of
        // the GUI

        if (!widget() || (widget() != mCellmlWidget)) {
            mCellmlWidget = new QWidget(this);
            mCellmlFormLayout = new QFormLayout(mCellmlWidget);

            mCellmlWidget->setLayout(mCellmlFormLayout);

            setWidget(mCellmlWidget);
        }

        // Remove everything from our form layout

        for (int i = 0, iMax = mCellmlFormLayout->count(); i < iMax; ++i) {
            QLayoutItem *item = mCellmlFormLayout->takeAt(0);

            delete item->widget();
            delete item;
        }

        mCellmlCmetaIdValue = 0;

        // Go through the different items which properties we want to add to the
        // GUI

        for (int i = 0, iLast = pCellmlItems.count()-1; i <= iLast; ++i) {
            CellmlItem cellmlItem = pCellmlItems.at(i);

            // Determine which widget should be shown/hidden

            bool showName = false;
            bool showXlinkHref = false;
            bool showUnitReference = false;
            bool showComponentReference = false;
            bool showUnit = false;
            bool showInitialValue = false;
            bool showPublicInterface = false;
            bool showPrivateInterface = false;
            bool showRelationship = false;
            bool showRelationshipNamespace = false;
            bool showComponent = false;
            bool showFirstComponent = false;
            bool showSecondComponent = false;
            bool showFirstVariable = false;
            bool showSecondVariable = false;

            switch (cellmlItem.type) {
            case Model:
            case Unit:
            case UnitElement:
            case Component:
            case Group:
            case Connection:
                showName = true;

                break;
            case Import:
                showXlinkHref = true;

                break;
            case ImportUnit:
                showName = true;
                showUnitReference = true;

                break;
            case ImportComponent:
                showName = true;
                showComponentReference = true;

                break;
            case Variable:
                showName = true;
                showUnit = true;
                showInitialValue = true;
                showPublicInterface = true;
                showPrivateInterface = true;

                break;
            case RelationshipReference:
                showRelationship = true;
                showRelationshipNamespace = true;

                break;
            case ComponentReference:
                showComponent = true;

                break;
            case ComponentMapping:
                showFirstComponent = true;
                showSecondComponent = true;

                break;
            case VariableMapping:
                showFirstVariable = true;
                showSecondVariable = true;

                break;
            };

            // Add whatever we need
            // Note: as long as all of the widgets' parent is our scroll area's
            //       widget, then they will get automatically deleted, so no need to
            //       delete them in ~CellmlAnnotationViewDetailsWidget()...

            // Add a bold centered label as a header to let the user know what type
            // of item we are talking about

            QLabel *header = new QLabel(typeAsString(cellmlItem.type),
                                        mCellmlWidget);

            QFont headerFont = header->font();

            headerFont.setBold(true);

            header->setAlignment(Qt::AlignCenter);
            header->setFont(headerFont);

            mCellmlFormLayout->addRow(header);

            // Show the item's cmeta:id, keeping in mind that we only want to
            // allow the editing of the cmeta:id of the very first item

            QString cmetaId = cellmlItem.element->cmetaId();

            if (i == iLast) {
                // This is our 'main' current item, so we want to allow the user
                // to edit its cmeta:id

                mCellmlCmetaIdValue = new QLineEdit(cmetaId, mCellmlWidget);

                mCellmlFormLayout->addRow(new QLabel(tr("cmeta:id:"), mCellmlWidget),
                                          mCellmlCmetaIdValue);
            } else {
                // Not our 'main' current item, so just display its cmeta:id

                addRowToCellmlFormLayout(tr("cmeta:id:"),
                                         cmetaId.isEmpty()?"/":cmetaId);
            }

            // Show the item's remaining properties

            if (showName) {
                // Retrieve the name of the CellML element
                // Note: in the case of a group or a connection, there won't be a
                //       name, so we use the item's name, hoping one was provided...

                QString name = ((cellmlItem.type == Group) || (cellmlItem.type == Connection))?
                                   (cellmlItem.number == -1)?
                                       "/":
                                       (cellmlItem.type == Group)?
                                           tr("Group #%1").arg(cellmlItem.number):
                                           tr("Connection #%1").arg(cellmlItem.number):
                                   static_cast<CellMLSupport::CellmlFileNamedElement *>(cellmlItem.element)->name();

                addRowToCellmlFormLayout(tr("Name:"), name);
            }

            if (showXlinkHref)
                addRowToCellmlFormLayout(tr("xlink:href:"),
                                         static_cast<CellMLSupport::CellmlFileImport *>(cellmlItem.element)->xlinkHref());

            if (showUnitReference)
                addRowToCellmlFormLayout(tr("Unit reference:"),
                                         static_cast<CellMLSupport::CellmlFileImportUnit *>(cellmlItem.element)->unitReference());

            if (showComponentReference)
                addRowToCellmlFormLayout(tr("Component reference:"),
                                         static_cast<CellMLSupport::CellmlFileImportComponent *>(cellmlItem.element)->componentReference());

            if (showUnit)
                addRowToCellmlFormLayout(tr("Unit:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->unit());

            if (showInitialValue) {
                QString initialValue = static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->initialValue();

                addRowToCellmlFormLayout(tr("Initial value:"),
                                         initialValue.isEmpty()?"/":initialValue);
            }

            if (showPublicInterface)
                addRowToCellmlFormLayout(tr("Public interface:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->publicInterfaceAsString());

            if (showPrivateInterface)
                addRowToCellmlFormLayout(tr("Private interface:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->privateInterfaceAsString());

            if (showRelationship)
                addRowToCellmlFormLayout(tr("Relationship:"),
                                         static_cast<CellMLSupport::CellmlFileRelationshipReference *>(cellmlItem.element)->relationship());

            if (showRelationshipNamespace) {
                QString relationshipNamespace = static_cast<CellMLSupport::CellmlFileRelationshipReference *>(cellmlItem.element)->relationshipNamespace();

                addRowToCellmlFormLayout(tr("Relationship namespace:"),
                                         relationshipNamespace.isEmpty()?"/":relationshipNamespace);
            }

            if (showComponent)
                addRowToCellmlFormLayout(tr("Component:"),
                                         static_cast<CellMLSupport::CellmlFileComponentReference *>(cellmlItem.element)->component());

            if (showFirstComponent)
                addRowToCellmlFormLayout(tr("First component:"),
                                         static_cast<CellMLSupport::CellmlFileMapComponents *>(cellmlItem.element)->firstComponent());

            if (showSecondComponent)
                addRowToCellmlFormLayout(tr("Second component:"),
                                         static_cast<CellMLSupport::CellmlFileMapComponents *>(cellmlItem.element)->secondComponent());

            if (showFirstVariable)
                addRowToCellmlFormLayout(tr("First variable:"),
                                         static_cast<CellMLSupport::CellmlFileMapVariablesItem *>(cellmlItem.element)->firstVariable());

            if (showSecondVariable)
                addRowToCellmlFormLayout(tr("Second variable:"),
                                         static_cast<CellMLSupport::CellmlFileMapVariablesItem *>(cellmlItem.element)->secondVariable());
        }
    } else {
        // We are dealing with some metadata, so enable the metadata ML side of
        // the GUI

        if (!widget() || (widget() != mMetadataWidget)) {
            mMetadataWidget = new QWidget(this);
            mMetadataFormLayout = new QVBoxLayout(mMetadataWidget);

            mMetadataFormLayout->setMargin(0);

            mMetadataWidget->setLayout(mMetadataFormLayout);

            mMetadataTreeView  = new Core::TreeView(mMetadataWidget);
            mMetadataDataModel = new QStandardItemModel(mMetadataTreeView);

            mMetadataTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
            mMetadataTreeView->setFrameShape(QFrame::NoFrame);
            mMetadataTreeView->setModel(mMetadataDataModel);
            mMetadataTreeView->setRootIsDecorated(false);
            mMetadataTreeView->setSelectionMode(QAbstractItemView::SingleSelection);

            mMetadataDataModel->setHorizontalHeaderLabels(QStringList() << tr("#")
                                                                        << tr("Subject")
                                                                        << tr("Predicate")
                                                                        << tr("Object"));

            mMetadataFormLayout->addWidget(mMetadataTreeView);

            setWidget(mMetadataWidget);
        }

        // Remove all previous triples from our tree view

        while (mMetadataDataModel->rowCount())
            foreach (QStandardItem *item, mMetadataDataModel->takeRow(0))
                delete item;

        // Add the 'new' triples to our tree view
        // Note: for the triple's subject, we try to remove the CellML file's
        //       URI base, thus only leaving the equivalent of a CellML element
        //       cmeta:id which will speak more to the user than a possible long
        //       URI reference...

        QString uriBase = mParent->cellmlFile()->uriBase();
        int rdfTripleCounter = 0;

        foreach (CellMLSupport::CellmlFileRdfTriple *rdfTriple, pRdfTriples)
            mMetadataDataModel->invisibleRootItem()->appendRow(QList<QStandardItem *>() << new QStandardItem(QString::number(++rdfTripleCounter))
                                                                                << new QStandardItem(rdfTriple->subject()->asString().remove(QRegExp("^"+QRegExp::escape(uriBase)+"#?")))
                                                                                << new QStandardItem(rdfTriple->predicate()->asString())
                                                                                << new QStandardItem(rdfTriple->object()->asString()));

        // Make sure that all the columns have their contents fit

        mMetadataTreeView->resizeColumnToContents(0);
        mMetadataTreeView->resizeColumnToContents(1);
        mMetadataTreeView->resizeColumnToContents(2);
        mMetadataTreeView->resizeColumnToContents(3);
    }

    // Re-show ourselves

    setVisible(true);

    // Scroll down to the bottom of ourselves, just in case things don't fit
    // within the viewport
    // Note: for this, we need to be up-to-date, hence we make a call to
    //       qApp->processEvents() and this can only be done when we are once
    //       again visible...

    qApp->processEvents();

    verticalScrollBar()->setValue(verticalScrollBar()->maximum());

    // Give the focus to the cmeta:id value field
    // Note: indeed, to have the cmeta:id value field as a focus proxy widget
    //       for CellmlAnnotationViewWidget isn't good enough to have it get the
    //       focus after selecting a 'new' CellML element in
    //       CellmlAnnotationViewWidget (while it's when we switch from one
    //       CellML file to another), so...

    if ((widget() == mCellmlWidget) && mCellmlCmetaIdValue)
        mCellmlCmetaIdValue->setFocus();
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellmlItems &pCellmlItems)
{
    // Call our generic updateGui()

    updateGui(pCellmlItems, CellMLSupport::CellmlFileRdfTriples());
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellMLSupport::CellmlFileRdfTriples &pRdfTriples)
{
    // Call our generic updateGui()

    updateGui(CellmlItems(), pRdfTriples);
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::addRowToCellmlFormLayout(const QString &pLabel,
                                                                 const QString &pValue)
{
    // Add a row to our form layout

    mCellmlFormLayout->addRow(new QLabel(pLabel, mCellmlWidget),
                              new QLabel(pValue, mCellmlWidget));
}

//==============================================================================

QString CellmlAnnotationViewDetailsWidget::typeAsString(const Type &pType) const
{
    switch (pType) {
    case Import:
        return tr("Import");
    case ImportUnit:
        return tr("Imported unit");
    case ImportComponent:
        return tr("Imported component");
    case Unit:
        return tr("Unit");
    case UnitElement:
        return tr("Unit element");
    case Component:
        return tr("Component");
    case Variable:
        return tr("Variable");
    case Group:
        return tr("Group");
    case RelationshipReference:
        return tr("Relationshop reference");
    case ComponentReference:
        return tr("Component reference");
    case Connection:
        return tr("Connection");
    case ComponentMapping:
        return tr("Component mapping");
    case VariableMapping:
        return tr("Variable mapping");
    default:
        // Model

        return tr("Model");
    }
}

//==============================================================================

QWidget * CellmlAnnotationViewDetailsWidget::focusProxyWidget()
{
    // If anything, we want our cmeta:id value widget to be a focus proxy widget

    return (widget() == mCellmlWidget)?mCellmlCmetaIdValue:0;
}

//==============================================================================

}   // namespace CellMLAnnotationView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up (#57).<commit_after>//==============================================================================
// CellML annotation view details widget
//==============================================================================

#include "cellmlannotationviewdetailswidget.h"
#include "cellmlannotationviewwidget.h"
#include "treeview.h"

//==============================================================================

#include "ui_cellmlannotationviewdetailswidget.h"

//==============================================================================

#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QScrollBar>

//==============================================================================

namespace OpenCOR {
namespace CellMLAnnotationView {

//==============================================================================

CellmlAnnotationViewDetailsWidget::CellmlAnnotationViewDetailsWidget(CellmlAnnotationViewWidget *pParent) :
    QScrollArea(pParent),
    Core::CommonWidget(pParent),
    mParent(pParent),
    mGui(new Ui::CellmlAnnotationViewDetailsWidget),
    mCellmlItems(CellmlItems()),
    mRdfTriples(CellMLSupport::CellmlFileRdfTriples()),
    mCellmlWidget(0),
    mCellmlFormLayout(0),
    mCellmlCmetaIdValue(0),
    mMetadataWidget(0),
    mMetadataFormLayout(0),
    mMetadataTreeView(0),
    mMetadataDataModel(0)
{
    // Set up the GUI

    mGui->setupUi(this);
}

//==============================================================================

CellmlAnnotationViewDetailsWidget::~CellmlAnnotationViewDetailsWidget()
{
    // Delete the GUI

    delete mGui;
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::retranslateUi()
{
    // Retranslate our GUI

    mGui->retranslateUi(this);

    // Update the GUI (since some widgets get reinitialised as a result of the
    // retranslation)

    delete takeWidget();   // This will force the GUI to be recreated from
                           // scratch and everything to be retranslated

    updateGui(mCellmlItems, mRdfTriples);
}

//==============================================================================

CellmlAnnotationViewDetailsWidget::CellmlItem CellmlAnnotationViewDetailsWidget::cellmlItem(const Type &pType,
                                                                                CellMLSupport::CellmlFileElement *pElement,
                                                                                const int &pNumber)
{
    // Return a formatted CellmlItem 'object'

    CellmlItem res;

    res.type    = pType;
    res.element = pElement;
    res.number  = pNumber;

    return res;
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellmlItems &pCellmlItems,
                                                  const CellMLSupport::CellmlFileRdfTriples &pRdfTriples)
{
    // Hide ourselves (since we may potentially update ourselves quite a bit and
    // we want to avoid any flickering)
    // Note #1: one would normally use setUpdatesEnabled(), but it still results
    //          in bad flickering on Mac OS X, so...
    // Note #2: it's surprising that setVisible() doesn't cause any flickering
    //          on any of the platforms we are targetting, but let's not
    //          complain...

    setVisible(false);

    // Keep track of the CellML items and metadata group name

    mCellmlItems = pCellmlItems;
    mRdfTriples  = pRdfTriples;

    // Check whether we are dealing with some metadata or not

    if (pCellmlItems.count()) {
        // We are not dealing with some metadata, so enable the CellML side of
        // the GUI

        if (!widget() || (widget() != mCellmlWidget)) {
            mCellmlWidget = new QWidget(this);
            mCellmlFormLayout = new QFormLayout(mCellmlWidget);

            mCellmlWidget->setLayout(mCellmlFormLayout);

            setWidget(mCellmlWidget);
        }

        // Remove everything from our form layout

        for (int i = 0, iMax = mCellmlFormLayout->count(); i < iMax; ++i) {
            QLayoutItem *item = mCellmlFormLayout->takeAt(0);

            delete item->widget();
            delete item;
        }

        mCellmlCmetaIdValue = 0;

        // Go through the different items which properties we want to add to the
        // GUI

        for (int i = 0, iLast = pCellmlItems.count()-1; i <= iLast; ++i) {
            CellmlItem cellmlItem = pCellmlItems.at(i);

            // Determine which widget should be shown/hidden

            bool showName = false;
            bool showXlinkHref = false;
            bool showUnitReference = false;
            bool showComponentReference = false;
            bool showUnit = false;
            bool showInitialValue = false;
            bool showPublicInterface = false;
            bool showPrivateInterface = false;
            bool showRelationship = false;
            bool showRelationshipNamespace = false;
            bool showComponent = false;
            bool showFirstComponent = false;
            bool showSecondComponent = false;
            bool showFirstVariable = false;
            bool showSecondVariable = false;

            switch (cellmlItem.type) {
            case Model:
            case Unit:
            case UnitElement:
            case Component:
            case Group:
            case Connection:
                showName = true;

                break;
            case Import:
                showXlinkHref = true;

                break;
            case ImportUnit:
                showName = true;
                showUnitReference = true;

                break;
            case ImportComponent:
                showName = true;
                showComponentReference = true;

                break;
            case Variable:
                showName = true;
                showUnit = true;
                showInitialValue = true;
                showPublicInterface = true;
                showPrivateInterface = true;

                break;
            case RelationshipReference:
                showRelationship = true;
                showRelationshipNamespace = true;

                break;
            case ComponentReference:
                showComponent = true;

                break;
            case ComponentMapping:
                showFirstComponent = true;
                showSecondComponent = true;

                break;
            case VariableMapping:
                showFirstVariable = true;
                showSecondVariable = true;

                break;
            };

            // Add whatever we need
            // Note: as long as all of the widgets' parent is our scroll area's
            //       widget, then they will get automatically deleted, so no need to
            //       delete them in ~CellmlAnnotationViewDetailsWidget()...

            // Add a bold centered label as a header to let the user know what type
            // of item we are talking about

            QLabel *header = new QLabel(typeAsString(cellmlItem.type),
                                        mCellmlWidget);

            QFont headerFont = header->font();

            headerFont.setBold(true);

            header->setAlignment(Qt::AlignCenter);
            header->setFont(headerFont);

            mCellmlFormLayout->addRow(header);

            // Show the item's cmeta:id, keeping in mind that we only want to
            // allow the editing of the cmeta:id of the very first item

            QString cmetaId = cellmlItem.element->cmetaId();

            if (i == iLast) {
                // This is our 'main' current item, so we want to allow the user
                // to edit its cmeta:id

                mCellmlCmetaIdValue = new QLineEdit(cmetaId, mCellmlWidget);

                mCellmlFormLayout->addRow(new QLabel(tr("cmeta:id:"), mCellmlWidget),
                                          mCellmlCmetaIdValue);
            } else {
                // Not our 'main' current item, so just display its cmeta:id

                addRowToCellmlFormLayout(tr("cmeta:id:"),
                                         cmetaId.isEmpty()?"/":cmetaId);
            }

            // Show the item's remaining properties

            if (showName) {
                // Retrieve the name of the CellML element
                // Note: in the case of a group or a connection, there won't be a
                //       name, so we use the item's name, hoping one was provided...

                QString name = ((cellmlItem.type == Group) || (cellmlItem.type == Connection))?
                                   (cellmlItem.number == -1)?
                                       "/":
                                       (cellmlItem.type == Group)?
                                           tr("Group #%1").arg(cellmlItem.number):
                                           tr("Connection #%1").arg(cellmlItem.number):
                                   static_cast<CellMLSupport::CellmlFileNamedElement *>(cellmlItem.element)->name();

                addRowToCellmlFormLayout(tr("Name:"), name);
            }

            if (showXlinkHref)
                addRowToCellmlFormLayout(tr("xlink:href:"),
                                         static_cast<CellMLSupport::CellmlFileImport *>(cellmlItem.element)->xlinkHref());

            if (showUnitReference)
                addRowToCellmlFormLayout(tr("Unit reference:"),
                                         static_cast<CellMLSupport::CellmlFileImportUnit *>(cellmlItem.element)->unitReference());

            if (showComponentReference)
                addRowToCellmlFormLayout(tr("Component reference:"),
                                         static_cast<CellMLSupport::CellmlFileImportComponent *>(cellmlItem.element)->componentReference());

            if (showUnit)
                addRowToCellmlFormLayout(tr("Unit:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->unit());

            if (showInitialValue) {
                QString initialValue = static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->initialValue();

                addRowToCellmlFormLayout(tr("Initial value:"),
                                         initialValue.isEmpty()?"/":initialValue);
            }

            if (showPublicInterface)
                addRowToCellmlFormLayout(tr("Public interface:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->publicInterfaceAsString());

            if (showPrivateInterface)
                addRowToCellmlFormLayout(tr("Private interface:"),
                                         static_cast<CellMLSupport::CellmlFileVariable *>(cellmlItem.element)->privateInterfaceAsString());

            if (showRelationship)
                addRowToCellmlFormLayout(tr("Relationship:"),
                                         static_cast<CellMLSupport::CellmlFileRelationshipReference *>(cellmlItem.element)->relationship());

            if (showRelationshipNamespace) {
                QString relationshipNamespace = static_cast<CellMLSupport::CellmlFileRelationshipReference *>(cellmlItem.element)->relationshipNamespace();

                addRowToCellmlFormLayout(tr("Relationship namespace:"),
                                         relationshipNamespace.isEmpty()?"/":relationshipNamespace);
            }

            if (showComponent)
                addRowToCellmlFormLayout(tr("Component:"),
                                         static_cast<CellMLSupport::CellmlFileComponentReference *>(cellmlItem.element)->component());

            if (showFirstComponent)
                addRowToCellmlFormLayout(tr("First component:"),
                                         static_cast<CellMLSupport::CellmlFileMapComponents *>(cellmlItem.element)->firstComponent());

            if (showSecondComponent)
                addRowToCellmlFormLayout(tr("Second component:"),
                                         static_cast<CellMLSupport::CellmlFileMapComponents *>(cellmlItem.element)->secondComponent());

            if (showFirstVariable)
                addRowToCellmlFormLayout(tr("First variable:"),
                                         static_cast<CellMLSupport::CellmlFileMapVariablesItem *>(cellmlItem.element)->firstVariable());

            if (showSecondVariable)
                addRowToCellmlFormLayout(tr("Second variable:"),
                                         static_cast<CellMLSupport::CellmlFileMapVariablesItem *>(cellmlItem.element)->secondVariable());
        }
    } else {
        // We are dealing with some metadata, so enable the metadata ML side of
        // the GUI

        if (!widget() || (widget() != mMetadataWidget)) {
            mMetadataWidget = new QWidget(this);
            mMetadataFormLayout = new QVBoxLayout(mMetadataWidget);

            mMetadataFormLayout->setMargin(0);

            mMetadataWidget->setLayout(mMetadataFormLayout);

            mMetadataTreeView  = new Core::TreeView(mMetadataWidget);
            mMetadataDataModel = new QStandardItemModel(mMetadataTreeView);

            mMetadataTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
            mMetadataTreeView->setFrameShape(QFrame::NoFrame);
            mMetadataTreeView->setModel(mMetadataDataModel);
            mMetadataTreeView->setRootIsDecorated(false);
            mMetadataTreeView->setSelectionMode(QAbstractItemView::SingleSelection);

            mMetadataDataModel->setHorizontalHeaderLabels(QStringList() << tr("#")
                                                                        << tr("Subject")
                                                                        << tr("Predicate")
                                                                        << tr("Object"));

            mMetadataFormLayout->addWidget(mMetadataTreeView);

            setWidget(mMetadataWidget);
        }

        // Remove all previous triples from our tree view

        while (mMetadataDataModel->rowCount())
            foreach (QStandardItem *item, mMetadataDataModel->takeRow(0))
                delete item;

        // Add the 'new' triples to our tree view
        // Note: for the triple's subject, we try to remove the CellML file's
        //       URI base, thus only leaving the equivalent of a CellML element
        //       cmeta:id which will speak more to the user than a possible long
        //       URI reference...

        QString uriBase = mParent->cellmlFile()->uriBase();
        int rdfTripleCounter = 0;

        foreach (CellMLSupport::CellmlFileRdfTriple *rdfTriple, pRdfTriples)
            mMetadataDataModel->invisibleRootItem()->appendRow(QList<QStandardItem *>() << new QStandardItem(QString::number(++rdfTripleCounter))
                                                                                << new QStandardItem(rdfTriple->subject()->asString().remove(QRegExp("^"+QRegExp::escape(uriBase)+"#?")))
                                                                                << new QStandardItem(rdfTriple->predicate()->asString())
                                                                                << new QStandardItem(rdfTriple->object()->asString()));

        // Make sure that all the columns have their contents fit

        mMetadataTreeView->resizeColumnToContents(0);
        mMetadataTreeView->resizeColumnToContents(1);
        mMetadataTreeView->resizeColumnToContents(2);
        mMetadataTreeView->resizeColumnToContents(3);
    }

    // Re-show ourselves

    setVisible(true);

    // Scroll down to the bottom of ourselves, just in case things don't fit
    // within the viewport
    // Note: for this, we need to be up-to-date, hence we make a call to
    //       qApp->processEvents() and this can only be done when we are once
    //       again visible...

    qApp->processEvents();

    verticalScrollBar()->setValue(verticalScrollBar()->maximum());

    // Give the focus to the cmeta:id value field
    // Note: indeed, to have the cmeta:id value field as a focus proxy widget
    //       for CellmlAnnotationViewWidget isn't good enough to have it get the
    //       focus after selecting a 'new' CellML element in
    //       CellmlAnnotationViewWidget (while it's when we switch from one
    //       CellML file to another), so...

    if ((widget() == mCellmlWidget) && mCellmlCmetaIdValue)
        mCellmlCmetaIdValue->setFocus();
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellmlItems &pCellmlItems)
{
    // Call our generic updateGui()

    updateGui(pCellmlItems, CellMLSupport::CellmlFileRdfTriples());
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::updateGui(const CellMLSupport::CellmlFileRdfTriples &pRdfTriples)
{
    // Call our generic updateGui()

    updateGui(CellmlItems(), pRdfTriples);
}

//==============================================================================

void CellmlAnnotationViewDetailsWidget::addRowToCellmlFormLayout(const QString &pLabel,
                                                                 const QString &pValue)
{
    // Add a row to our form layout

    mCellmlFormLayout->addRow(new QLabel(pLabel, mCellmlWidget),
                              new QLabel(pValue, mCellmlWidget));
}

//==============================================================================

QString CellmlAnnotationViewDetailsWidget::typeAsString(const Type &pType) const
{
    switch (pType) {
    case Import:
        return tr("Import");
    case ImportUnit:
        return tr("Imported unit");
    case ImportComponent:
        return tr("Imported component");
    case Unit:
        return tr("Unit");
    case UnitElement:
        return tr("Unit element");
    case Component:
        return tr("Component");
    case Variable:
        return tr("Variable");
    case Group:
        return tr("Group");
    case RelationshipReference:
        return tr("Relationshop reference");
    case ComponentReference:
        return tr("Component reference");
    case Connection:
        return tr("Connection");
    case ComponentMapping:
        return tr("Component mapping");
    case VariableMapping:
        return tr("Variable mapping");
    default:
        // Model

        return tr("Model");
    }
}

//==============================================================================

QWidget * CellmlAnnotationViewDetailsWidget::focusProxyWidget()
{
    // If anything, we want our cmeta:id value widget to be a focus proxy widget

    return (widget() == mCellmlWidget)?mCellmlCmetaIdValue:0;
}

//==============================================================================

}   // namespace CellMLAnnotationView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "test_precomp.hpp"

namespace opencv_test { namespace {

    static const int fixedShiftU8 = 8;

    template <typename T, int fixedShift>
    void eval4(int64_t   xcoeff0, int64_t   xcoeff1, int64_t   ycoeff0, int64_t   ycoeff1, int cn,
               uint8_t* src_pt00, uint8_t* src_pt01, uint8_t* src_pt10, uint8_t* src_pt11, uint8_t* dst_pt)
    {
        static const int64_t fixedRound = ((1LL << (fixedShift * 2)) >> 1);
        int64_t val = (((T*)src_pt00)[cn] * xcoeff0 + ((T*)src_pt01)[cn] * xcoeff1) * ycoeff0 +
                      (((T*)src_pt10)[cn] * xcoeff0 + ((T*)src_pt11)[cn] * xcoeff1) * ycoeff1 ;
        ((T*)dst_pt)[cn] = saturate_cast<T>((val + fixedRound) >> (fixedShift * 2));
    }

TEST(Resize_Bitexact, Linear8U)
{
    static const int64_t fixedOne = (1L << fixedShiftU8);

    struct testmode
    {
        int type;
        Size sz;
    } modes[] = {
        { CV_8UC1, Size( 512, 768) }, //   1/2       1
        { CV_8UC3, Size( 512, 768) },
        { CV_8UC1, Size(1024, 384) }, //    1       1/2
        { CV_8UC4, Size(1024, 384) },
        { CV_8UC1, Size( 512, 384) }, //   1/2      1/2
        { CV_8UC2, Size( 512, 384) },
        { CV_8UC3, Size( 512, 384) },
        { CV_8UC4, Size( 512, 384) },
        { CV_8UC1, Size( 256, 192) }, //   1/4      1/4
        { CV_8UC2, Size( 256, 192) },
        { CV_8UC3, Size( 256, 192) },
        { CV_8UC4, Size( 256, 192) },
        { CV_8UC1, Size(   4,   3) }, //   1/256    1/256
        { CV_8UC2, Size(   4,   3) },
        { CV_8UC3, Size(   4,   3) },
        { CV_8UC4, Size(   4,   3) },
        { CV_8UC1, Size( 342, 384) }, //   1/3      1/2
        { CV_8UC1, Size( 342, 256) }, //   1/3      1/3
        { CV_8UC1, Size( 342, 256) },
        { CV_8UC1, Size( 342, 256) },
        { CV_8UC1, Size( 342, 256) },
        { CV_8UC1, Size( 512, 256) }, //   1/2      1/3
        { CV_8UC1, Size( 146, 110) }, //   1/7      1/7
        { CV_8UC3, Size( 146, 110) },
        { CV_8UC4, Size( 146, 110) },
        { CV_8UC1, Size( 931, 698) }, //  10/11    10/11
        { CV_8UC2, Size( 931, 698) },
        { CV_8UC3, Size( 931, 698) },
        { CV_8UC4, Size( 931, 698) },
        { CV_8UC1, Size( 853, 640) }, //  10/12    10/12
        { CV_8UC3, Size( 853, 640) },
        { CV_8UC4, Size( 853, 640) },
        { CV_8UC1, Size(1004, 753) }, // 251/256  251/256
        { CV_8UC2, Size(1004, 753) },
        { CV_8UC3, Size(1004, 753) },
        { CV_8UC4, Size(1004, 753) },
        { CV_8UC1, Size(2048,1536) }, //    2        2
        { CV_8UC2, Size(2048,1536) },
        { CV_8UC4, Size(2048,1536) },
        { CV_8UC1, Size(3072,2304) }, //    3        3
        { CV_8UC3, Size(3072,2304) },
        { CV_8UC1, Size(7168,5376) }  //    7        7
    };

    for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
        {
            int type = modes[modeind].type, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
            int dcols = modes[modeind].sz.width, drows = modes[modeind].sz.height;
            int cols = 1024, rows = 768;

            double inv_scale_x = (double)dcols / cols;
            double inv_scale_y = (double)drows / rows;
            softdouble scale_x = softdouble::one() / softdouble(inv_scale_x);
            softdouble scale_y = softdouble::one() / softdouble(inv_scale_y);

            Mat src(rows, cols, type), refdst(drows, dcols, type), dst;
            for (int j = 0; j < rows; j++)
            {
                uint8_t* line = src.ptr(j);
                for (int i = 0; i < cols; i++)
                    for (int c = 0; c < cn; c++)
                    {
                        RNG rnd(0x123456789abcdefULL);
                        double val = j < rows / 2 ? ( i < cols / 2 ? ((sin((i + 1)*CV_PI / 256.)*sin((j + 1)*CV_PI / 256.)*sin((cn + 4)*CV_PI / 8.) + 1.)*128.)                         :
                                                                     (((i / 128 + j / 128) % 2) * 250 + (j / 128) % 2)                                                                ) :
                                                    ( i < cols / 2 ? ((i / 128) * (85 - j / 256 * 40) * ((j / 128) % 2) + (7 - i / 128) * (85 - j / 256 * 40) * ((j / 128 + 1) % 2))    :
                                                                     ((uchar)rnd)                                                                                ) ;
                        if (depth == CV_8U)
                            line[i*cn + c] = (uint8_t)val;
                        else if (depth == CV_16U)
                            ((uint16_t*)line)[i*cn + c] = (uint16_t)val;
                        else if (depth == CV_16S)
                            ((int16_t*)line)[i*cn + c] = (int16_t)val;
                        else if (depth == CV_32S)
                            ((int32_t*)line)[i*cn + c] = (int32_t)val;
                        else
                            CV_Assert(0);
                    }
            }

            for (int j = 0; j < drows; j++)
            {
                softdouble src_row_flt = scale_y*(softdouble(j) + softdouble(0.5)) - softdouble(0.5);
                int src_row = cvFloor(src_row_flt);
                int64_t ycoeff1 = cvRound64((src_row_flt - softdouble(src_row))*softdouble(fixedOne));
                int64_t ycoeff0 = fixedOne - ycoeff1;

                for (int i = 0; i < dcols; i++)
                {
                    softdouble src_col_flt = scale_x*(softdouble(i) + softdouble(0.5)) - softdouble(0.5);
                    int src_col = cvFloor(src_col_flt);
                    int64_t xcoeff1 = cvRound64((src_col_flt - softdouble(src_col))*softdouble(fixedOne));
                    int64_t xcoeff0 = fixedOne - xcoeff1;

                    uint8_t* dst_pt = refdst.ptr(j, i);
                    uint8_t* src_pt00 = src.ptr( src_row      < 0 ? 0 :  src_row      >= rows ? rows - 1 :  src_row     ,
                                                 src_col      < 0 ? 0 :  src_col      >= cols ? cols - 1 :  src_col     );
                    uint8_t* src_pt01 = src.ptr( src_row      < 0 ? 0 :  src_row      >= rows ? rows - 1 :  src_row     ,
                                                (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
                    uint8_t* src_pt10 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
                                                 src_col      < 0 ? 0 :  src_col      >= cols ? cols - 1 :  src_col     );
                    uint8_t* src_pt11 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
                                                (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
                    for (int c = 0; c < cn; c++)
                    {
                        if (depth == CV_8U)
                            eval4< uint8_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_16U)
                            eval4<uint16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_16S)
                            eval4< int16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_32S)
                            eval4< int32_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else
                            CV_Assert(0);
                    }
                }
            }

            cv::resize(src, dst, Size(dcols, drows), 0, 0, cv::INTER_LINEAR_EXACT);
            EXPECT_GE(0, cvtest::norm(refdst, dst, cv::NORM_L1))
                << "Resize " << cn << "-chan mat from " << cols << "x" << rows << " to " << dcols << "x" << drows << " failed with max diff " << cvtest::norm(refdst, dst, cv::NORM_INF);
        }
}

}} // namespace
<commit_msg>imgproc(test): fix resize bitexact test<commit_after>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "test_precomp.hpp"

namespace opencv_test { namespace {

    static const int fixedShiftU8 = 8;

    template <typename T, int fixedShift>
    void eval4(int64_t   xcoeff0, int64_t   xcoeff1, int64_t   ycoeff0, int64_t   ycoeff1, int cn,
               uint8_t* src_pt00, uint8_t* src_pt01, uint8_t* src_pt10, uint8_t* src_pt11, uint8_t* dst_pt)
    {
        static const int64_t fixedRound = ((1LL << (fixedShift * 2)) >> 1);
        int64_t val = (((T*)src_pt00)[cn] * xcoeff0 + ((T*)src_pt01)[cn] * xcoeff1) * ycoeff0 +
                      (((T*)src_pt10)[cn] * xcoeff0 + ((T*)src_pt11)[cn] * xcoeff1) * ycoeff1 ;
        ((T*)dst_pt)[cn] = saturate_cast<T>((val + fixedRound) >> (fixedShift * 2));
    }

TEST(Resize_Bitexact, Linear8U)
{
    static const int64_t fixedOne = (1L << fixedShiftU8);

    struct testmode
    {
        int type;
        Size sz;
    } modes[] = {
        { CV_8UC1, Size( 512, 768) }, //   1/2       1
        { CV_8UC3, Size( 512, 768) },
        { CV_8UC1, Size(1024, 384) }, //    1       1/2
        { CV_8UC4, Size(1024, 384) },
        { CV_8UC1, Size( 512, 384) }, //   1/2      1/2
        { CV_8UC2, Size( 512, 384) },
        { CV_8UC3, Size( 512, 384) },
        { CV_8UC4, Size( 512, 384) },
        { CV_8UC1, Size( 256, 192) }, //   1/4      1/4
        { CV_8UC2, Size( 256, 192) },
        { CV_8UC3, Size( 256, 192) },
        { CV_8UC4, Size( 256, 192) },
        { CV_8UC1, Size(   4,   3) }, //   1/256    1/256
        { CV_8UC2, Size(   4,   3) },
        { CV_8UC3, Size(   4,   3) },
        { CV_8UC4, Size(   4,   3) },
        { CV_8UC1, Size( 342, 384) }, //   1/3      1/2
        { CV_8UC1, Size( 342, 256) }, //   1/3      1/3
        { CV_8UC2, Size( 342, 256) },
        { CV_8UC3, Size( 342, 256) },
        { CV_8UC4, Size( 342, 256) },
        { CV_8UC1, Size( 512, 256) }, //   1/2      1/3
        { CV_8UC1, Size( 146, 110) }, //   1/7      1/7
        { CV_8UC3, Size( 146, 110) },
        { CV_8UC4, Size( 146, 110) },
        { CV_8UC1, Size( 931, 698) }, //  10/11    10/11
        { CV_8UC2, Size( 931, 698) },
        { CV_8UC3, Size( 931, 698) },
        { CV_8UC4, Size( 931, 698) },
        { CV_8UC1, Size( 853, 640) }, //  10/12    10/12
        { CV_8UC3, Size( 853, 640) },
        { CV_8UC4, Size( 853, 640) },
        { CV_8UC1, Size(1004, 753) }, // 251/256  251/256
        { CV_8UC2, Size(1004, 753) },
        { CV_8UC3, Size(1004, 753) },
        { CV_8UC4, Size(1004, 753) },
        { CV_8UC1, Size(2048,1536) }, //    2        2
        { CV_8UC2, Size(2048,1536) },
        { CV_8UC4, Size(2048,1536) },
        { CV_8UC1, Size(3072,2304) }, //    3        3
        { CV_8UC3, Size(3072,2304) },
        { CV_8UC1, Size(7168,5376) }  //    7        7
    };

    for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
        {
            int type = modes[modeind].type, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
            int dcols = modes[modeind].sz.width, drows = modes[modeind].sz.height;
            int cols = 1024, rows = 768;

            double inv_scale_x = (double)dcols / cols;
            double inv_scale_y = (double)drows / rows;
            softdouble scale_x = softdouble::one() / softdouble(inv_scale_x);
            softdouble scale_y = softdouble::one() / softdouble(inv_scale_y);

            Mat src(rows, cols, type), refdst(drows, dcols, type), dst;
            RNG rnd(0x123456789abcdefULL);
            for (int j = 0; j < rows; j++)
            {
                uint8_t* line = src.ptr(j);
                for (int i = 0; i < cols; i++)
                    for (int c = 0; c < cn; c++)
                    {
                        double val = j < rows / 2 ? ( i < cols / 2 ? ((sin((i + 1)*CV_PI / 256.)*sin((j + 1)*CV_PI / 256.)*sin((cn + 4)*CV_PI / 8.) + 1.)*128.)                         :
                                                                     (((i / 128 + j / 128) % 2) * 250 + (j / 128) % 2)                                                                ) :
                                                    ( i < cols / 2 ? ((i / 128) * (85 - j / 256 * 40) * ((j / 128) % 2) + (7 - i / 128) * (85 - j / 256 * 40) * ((j / 128 + 1) % 2))    :
                                                                     ((uchar)rnd)                                                                                ) ;
                        if (depth == CV_8U)
                            line[i*cn + c] = (uint8_t)val;
                        else if (depth == CV_16U)
                            ((uint16_t*)line)[i*cn + c] = (uint16_t)val;
                        else if (depth == CV_16S)
                            ((int16_t*)line)[i*cn + c] = (int16_t)val;
                        else if (depth == CV_32S)
                            ((int32_t*)line)[i*cn + c] = (int32_t)val;
                        else
                            CV_Assert(0);
                    }
            }

            for (int j = 0; j < drows; j++)
            {
                softdouble src_row_flt = scale_y*(softdouble(j) + softdouble(0.5)) - softdouble(0.5);
                int src_row = cvFloor(src_row_flt);
                int64_t ycoeff1 = cvRound64((src_row_flt - softdouble(src_row))*softdouble(fixedOne));
                int64_t ycoeff0 = fixedOne - ycoeff1;

                for (int i = 0; i < dcols; i++)
                {
                    softdouble src_col_flt = scale_x*(softdouble(i) + softdouble(0.5)) - softdouble(0.5);
                    int src_col = cvFloor(src_col_flt);
                    int64_t xcoeff1 = cvRound64((src_col_flt - softdouble(src_col))*softdouble(fixedOne));
                    int64_t xcoeff0 = fixedOne - xcoeff1;

                    uint8_t* dst_pt = refdst.ptr(j, i);
                    uint8_t* src_pt00 = src.ptr( src_row      < 0 ? 0 :  src_row      >= rows ? rows - 1 :  src_row     ,
                                                 src_col      < 0 ? 0 :  src_col      >= cols ? cols - 1 :  src_col     );
                    uint8_t* src_pt01 = src.ptr( src_row      < 0 ? 0 :  src_row      >= rows ? rows - 1 :  src_row     ,
                                                (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
                    uint8_t* src_pt10 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
                                                 src_col      < 0 ? 0 :  src_col      >= cols ? cols - 1 :  src_col     );
                    uint8_t* src_pt11 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
                                                (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
                    for (int c = 0; c < cn; c++)
                    {
                        if (depth == CV_8U)
                            eval4< uint8_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_16U)
                            eval4<uint16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_16S)
                            eval4< int16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else if (depth == CV_32S)
                            eval4< int32_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
                        else
                            CV_Assert(0);
                    }
                }
            }

            cv::resize(src, dst, Size(dcols, drows), 0, 0, cv::INTER_LINEAR_EXACT);
            EXPECT_GE(0, cvtest::norm(refdst, dst, cv::NORM_L1))
                << "Resize " << cn << "-chan mat from " << cols << "x" << rows << " to " << dcols << "x" << drows << " failed with max diff " << cvtest::norm(refdst, dst, cv::NORM_INF);
        }
}

}} // namespace
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "XalanDecimalFormatSymbols.hpp"
#include "DOMStringHelper.hpp"
#include "XalanUnicode.hpp"

XALAN_CPP_NAMESPACE_BEGIN

static XalanDOMChar		theNaNDefault[] =
{
	XalanUnicode::charLetter_N,
	XalanUnicode::charLetter_a,
	XalanUnicode::charLetter_N,
	0
};

static XalanDOMChar		theInfinityDefault[] =
{
	XalanUnicode::charLetter_I,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_f,
	XalanUnicode::charLetter_i,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_i,
	XalanUnicode::charLetter_t,
	XalanUnicode::charLetter_y,
	0
};

static XalanDOMChar		theCurrencySymbol[] =
{
	XalanUnicode::charDollarSign,
	0
};

XalanDecimalFormatSymbols::XalanDecimalFormatSymbols() :
	m_currencySymbol(theCurrencySymbol),
	m_decimalSeparator(XalanUnicode::charFullStop),
	m_digit(0),
	m_groupingSeparator(XalanUnicode::charComma),
	m_infinity(theInfinityDefault),
	m_internationalCurrencySymbol(),
	m_minusSign(XalanUnicode::charHyphenMinus),
	m_monetaryDecimalSeparator(XalanUnicode::charFullStop),
	m_NaN(theNaNDefault),
	m_patternSeparator(XalanUnicode::charSemicolon),
	m_percent(XalanUnicode::charPercentSign),
	m_perMill(0),
	m_zeroDigit(XalanUnicode::charDigit_0)
{
}

XalanDecimalFormatSymbols::XalanDecimalFormatSymbols(const XalanDecimalFormatSymbols&	theSource) :
	m_currencySymbol(theSource.m_currencySymbol),
	m_decimalSeparator(theSource.m_decimalSeparator),
	m_digit(theSource.m_digit),
	m_groupingSeparator(theSource.m_groupingSeparator),
	m_infinity(theSource.m_infinity),
	m_internationalCurrencySymbol(theSource.m_internationalCurrencySymbol),
	m_minusSign(theSource.m_minusSign),
	m_monetaryDecimalSeparator(theSource.m_monetaryDecimalSeparator),
	m_NaN(theSource.m_NaN),
	m_patternSeparator(theSource.m_patternSeparator),
	m_percent(theSource.m_percent),
	m_perMill(theSource.m_perMill),
	m_zeroDigit(theSource.m_zeroDigit)
{
}

XalanDecimalFormatSymbols::~XalanDecimalFormatSymbols()
{
}

XalanDecimalFormatSymbols&
XalanDecimalFormatSymbols::operator=(const XalanDecimalFormatSymbols&		theRHS)
{
	if (&theRHS != this)
	{
		m_currencySymbol = theRHS.m_currencySymbol;
		m_decimalSeparator = theRHS.m_decimalSeparator;
		m_digit = theRHS.m_digit;
		m_groupingSeparator = theRHS.m_groupingSeparator;
		m_infinity = theRHS.m_infinity;
		m_internationalCurrencySymbol = theRHS.m_internationalCurrencySymbol;
		m_minusSign = theRHS.m_minusSign;
		m_monetaryDecimalSeparator = theRHS.m_monetaryDecimalSeparator;
		m_NaN = theRHS.m_NaN;
		m_patternSeparator = theRHS.m_patternSeparator;
		m_percent = theRHS.m_percent;
		m_perMill = theRHS.m_perMill;
		m_zeroDigit = theRHS.m_zeroDigit;
	}

	return *this;
}

bool
XalanDecimalFormatSymbols::operator==(const XalanDecimalFormatSymbols&	theRHS) const
{
	return
		m_currencySymbol == theRHS.m_currencySymbol &&
		m_decimalSeparator == theRHS.m_decimalSeparator &&
		m_digit == theRHS.m_digit &&
		m_groupingSeparator == theRHS.m_groupingSeparator &&
		m_infinity == theRHS.m_infinity &&
		m_internationalCurrencySymbol == theRHS.m_internationalCurrencySymbol &&
		m_minusSign == theRHS.m_minusSign &&
		m_monetaryDecimalSeparator == theRHS.m_monetaryDecimalSeparator &&
		m_NaN == theRHS.m_NaN &&
		m_patternSeparator == theRHS.m_patternSeparator &&
		m_percent == theRHS.m_percent &&
		m_perMill == theRHS.m_perMill &&
		m_zeroDigit == theRHS.m_zeroDigit;
}

XALAN_CPP_NAMESPACE_END
<commit_msg>Initialize data member with per Mill symbol.  Fixes bugzilla 20929.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "XalanDecimalFormatSymbols.hpp"
#include "DOMStringHelper.hpp"
#include "XalanUnicode.hpp"

XALAN_CPP_NAMESPACE_BEGIN

static XalanDOMChar		theNaNDefault[] =
{
	XalanUnicode::charLetter_N,
	XalanUnicode::charLetter_a,
	XalanUnicode::charLetter_N,
	0
};

static XalanDOMChar		theInfinityDefault[] =
{
	XalanUnicode::charLetter_I,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_f,
	XalanUnicode::charLetter_i,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_i,
	XalanUnicode::charLetter_t,
	XalanUnicode::charLetter_y,
	0
};

static XalanDOMChar		theCurrencySymbol[] =
{
	XalanUnicode::charDollarSign,
	0
};

XalanDecimalFormatSymbols::XalanDecimalFormatSymbols() :
	m_currencySymbol(theCurrencySymbol),
	m_decimalSeparator(XalanUnicode::charFullStop),
	m_digit(0),
	m_groupingSeparator(XalanUnicode::charComma),
	m_infinity(theInfinityDefault),
	m_internationalCurrencySymbol(),
	m_minusSign(XalanUnicode::charHyphenMinus),
	m_monetaryDecimalSeparator(XalanUnicode::charFullStop),
	m_NaN(theNaNDefault),
	m_patternSeparator(XalanUnicode::charSemicolon),
	m_percent(XalanUnicode::charPercentSign),
	m_perMill(XalanUnicode::charPerMilleSign),
	m_zeroDigit(XalanUnicode::charDigit_0)
{
}

XalanDecimalFormatSymbols::XalanDecimalFormatSymbols(const XalanDecimalFormatSymbols&	theSource) :
	m_currencySymbol(theSource.m_currencySymbol),
	m_decimalSeparator(theSource.m_decimalSeparator),
	m_digit(theSource.m_digit),
	m_groupingSeparator(theSource.m_groupingSeparator),
	m_infinity(theSource.m_infinity),
	m_internationalCurrencySymbol(theSource.m_internationalCurrencySymbol),
	m_minusSign(theSource.m_minusSign),
	m_monetaryDecimalSeparator(theSource.m_monetaryDecimalSeparator),
	m_NaN(theSource.m_NaN),
	m_patternSeparator(theSource.m_patternSeparator),
	m_percent(theSource.m_percent),
	m_perMill(theSource.m_perMill),
	m_zeroDigit(theSource.m_zeroDigit)
{
}

XalanDecimalFormatSymbols::~XalanDecimalFormatSymbols()
{
}

XalanDecimalFormatSymbols&
XalanDecimalFormatSymbols::operator=(const XalanDecimalFormatSymbols&		theRHS)
{
	if (&theRHS != this)
	{
		m_currencySymbol = theRHS.m_currencySymbol;
		m_decimalSeparator = theRHS.m_decimalSeparator;
		m_digit = theRHS.m_digit;
		m_groupingSeparator = theRHS.m_groupingSeparator;
		m_infinity = theRHS.m_infinity;
		m_internationalCurrencySymbol = theRHS.m_internationalCurrencySymbol;
		m_minusSign = theRHS.m_minusSign;
		m_monetaryDecimalSeparator = theRHS.m_monetaryDecimalSeparator;
		m_NaN = theRHS.m_NaN;
		m_patternSeparator = theRHS.m_patternSeparator;
		m_percent = theRHS.m_percent;
		m_perMill = theRHS.m_perMill;
		m_zeroDigit = theRHS.m_zeroDigit;
	}

	return *this;
}

bool
XalanDecimalFormatSymbols::operator==(const XalanDecimalFormatSymbols&	theRHS) const
{
	return
		m_currencySymbol == theRHS.m_currencySymbol &&
		m_decimalSeparator == theRHS.m_decimalSeparator &&
		m_digit == theRHS.m_digit &&
		m_groupingSeparator == theRHS.m_groupingSeparator &&
		m_infinity == theRHS.m_infinity &&
		m_internationalCurrencySymbol == theRHS.m_internationalCurrencySymbol &&
		m_minusSign == theRHS.m_minusSign &&
		m_monetaryDecimalSeparator == theRHS.m_monetaryDecimalSeparator &&
		m_NaN == theRHS.m_NaN &&
		m_patternSeparator == theRHS.m_patternSeparator &&
		m_percent == theRHS.m_percent &&
		m_perMill == theRHS.m_perMill &&
		m_zeroDigit == theRHS.m_zeroDigit;
}

XALAN_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>#include <FAST/Data/Image.hpp>
#include <FAST/Data/ImagePyramid.hpp>
#include <FAST/Data/Tensor.hpp>
#include <FAST/Algorithms/NeuralNetwork/NeuralNetwork.hpp>
#include "PatchStitcher.hpp"

namespace fast {

PatchStitcher::PatchStitcher() {
    createInputPort<DataObject>(0); // Can be Image, Batch or Tensor
    createOutputPort<DataObject>(0); // Can be Image or Tensor

    createOpenCLProgram(Config::getKernelSourcePath() + "/Algorithms/ImagePatch/PatchStitcher2D.cl", "2D");
    createOpenCLProgram(Config::getKernelSourcePath() + "/Algorithms/ImagePatch/PatchStitcher3D.cl", "3D");
}

void PatchStitcher::execute() {
    auto patch = getInputData<DataObject>();
    mRuntimeManager->startRegularTimer("stitch patch");
    auto tensorPatch = std::dynamic_pointer_cast<Tensor>(patch);
    auto imagePatch = std::dynamic_pointer_cast<Image>(patch);
    auto batchOfPatches = std::dynamic_pointer_cast<Batch>(patch);
    if(batchOfPatches) {
       auto list = batchOfPatches->get();
       if(list.isTensors()) {
           for(auto&& tensor : list.getTensors())
               processTensor(tensor);
       }
        if(list.isImages()) {
            for(auto&& image : list.getImages())
                processImage(image);
        }
    } else {
        // Single
        if(tensorPatch) {
            processTensor(tensorPatch);
        } else if(imagePatch) {
            processImage(imagePatch);
        }
    }
    mRuntimeManager->stopRegularTimer("stitch patch");

    if(m_outputImage) {
        addOutputData(0, m_outputImage);
    } else if(m_outputTensor) {
        addOutputData(0, m_outputTensor);
    } else if(m_outputImagePyramid) {
        addOutputData(0, m_outputImagePyramid);
    } else {
        throw Exception("Unexpected event in PatchStitcher");
    }
}

void PatchStitcher::processTensor(std::shared_ptr<Tensor> patch) {
    const int fullWidth = std::stoi(patch->getFrameData("original-width"));
    const int fullHeight = std::stoi(patch->getFrameData("original-height"));

    const int patchWidth = std::stoi(patch->getFrameData("patch-width"));
    const int patchHeight = std::stoi(patch->getFrameData("patch-height"));

    const float patchSpacingX = std::stof(patch->getFrameData("patch-spacing-x"));
    const float patchSpacingY = std::stof(patch->getFrameData("patch-spacing-y"));

    auto shape = patch->getShape();
    if(shape.getDimensions() != 1) {
        throw Exception("Can only handle 1D tensors atm");
    }
    const int channels = shape[0];

    if(!m_outputTensor) {
        // Create output tensor
        TensorShape fullShape({(int)std::ceil((float)fullHeight / patchHeight), (int)std::ceil((float)fullWidth / patchWidth), channels});
        auto initializedData = std::make_unique<float[]>(fullShape.getTotalSize());
        m_outputTensor = Tensor::create(std::move(initializedData), fullShape);
        m_outputTensor->setSpacing(Vector3f(patchHeight*patchSpacingY, patchWidth*patchSpacingX, 1.0f));
    }
    reportInfo() << "Stitching " << patch->getFrameData("patchid-x") << " " << patch->getFrameData("patchid-y") << reportEnd();
    reportInfo() << "Stitching data" << patch->getFrameData("patch-spacing-x") << " " << patch->getFrameData("patch-spacing-y") << reportEnd();

    const int startX = std::stoi(patch->getFrameData("patchid-x"));
    const int startY = std::stoi(patch->getFrameData("patchid-y"));

    auto inputAccess = patch->getAccess(ACCESS_READ);
    auto tensorData = inputAccess->getData<1>();
    auto outputAccess = m_outputTensor->getAccess(ACCESS_READ_WRITE);
    auto outputTensorData = outputAccess->getData<3>();

    for(int i = 0; i < channels; ++i) {
        outputTensorData(startY, startX, i) = tensorData(i); // TODO fix
    }
    //outputTensorData(startY, startX, 1) = 1.0f; // TODO remove
}

void PatchStitcher::processImage(std::shared_ptr<Image> patch) {
    const int fullWidth = std::stoi(patch->getFrameData("original-width"));
    const int fullHeight = std::stoi(patch->getFrameData("original-height"));
    const float patchSpacingX = std::stof(patch->getFrameData("patch-spacing-x"));
    const float patchSpacingY = std::stof(patch->getFrameData("patch-spacing-y"));

    int fullDepth = 1;
    float patchSpacingZ = 1.0f;
    bool is3D = true;
    try {
        fullDepth = std::stoi(patch->getFrameData("original-depth"));
        patchSpacingZ = std::stof(patch->getFrameData("patch-spacing-z"));
    } catch(Exception &e) {
        // If exception: is a 2D image
        is3D = false;
    }

    if(!m_outputImage && !m_outputImagePyramid) {
        // Create output image
        if(is3D) {
			m_outputImage = Image::create(fullWidth, fullHeight, fullDepth, patch->getDataType(), patch->getNrOfChannels());
        } else {
            if(fullWidth < 8192 && fullHeight < 8192) {
                reportInfo() << "Patch stitcher creating image with size " << fullWidth << " " << fullHeight << reportEnd();
				m_outputImage = Image::create(fullWidth, fullHeight, patch->getDataType(), patch->getNrOfChannels());
            } else {
                // Large image, create image pyramid instead
                int patchWidth = std::stoi(patch->getFrameData("patch-width")) - 2*std::stoi(patch->getFrameData("patch-overlap-x"));
                int patchHeight = std::stoi(patch->getFrameData("patch-height")) - 2*std::stoi(patch->getFrameData("patch-overlap-y"));
                m_outputImagePyramid = ImagePyramid::create(fullWidth, fullHeight, patch->getNrOfChannels(), patchWidth, patchHeight);
                reportInfo() << "Patch stitcher creating image PYRAMID with size " << fullWidth << " " << fullHeight << ", patch size: " <<
                    patchWidth << " " << patchHeight << " Levels: " << m_outputImagePyramid->getNrOfLevels() << reportEnd();
            }
        }
        if(m_outputImage) {
            m_outputImage->fill(0);
            m_outputImage->setSpacing(Vector3f(patchSpacingX, patchSpacingY, patchSpacingZ));
        } else {
            //m_outputImagePyramid->fill(0);
            m_outputImagePyramid->setSpacing(Vector3f(patchSpacingX, patchSpacingY, patchSpacingZ));
        }
        try {
            auto transformData = split(patch->getFrameData("original-transform"));
            auto T = Transform::create();
            Affine3f transform;
            for(int i = 0; i < 16; ++i)
                transform.matrix()(i) = std::stof(transformData[i]);
            T->set(transform);
            if(m_outputImage) {
                m_outputImage->getSceneGraphNode()->setTransform(T);
            } else {
                m_outputImagePyramid->getSceneGraphNode()->setTransform(T);
            }
        } catch(Exception &e) {

        }
    }

    auto device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice());

    if(fullDepth == 1) {
		reportInfo() << "Stitching 2D data " << patch->getFrameData("patchid-x") << " " << patch->getFrameData("patchid-y")
			<< reportEnd();

        const int patchOverlapX = std::stoi(patch->getFrameData("patch-overlap-x"));
        const int patchOverlapY = std::stoi(patch->getFrameData("patch-overlap-y"));
        // Calculate offset. If this calculation is incorrect. Update in ImagePyramidPatchExporter as well.
        const int startX = std::stoi(patch->getFrameData("patchid-x")) * (std::stoi(patch->getFrameData("patch-width")) - patchOverlapX*2); // TODO + overlap to compensate for start offset
        const int startY = std::stoi(patch->getFrameData("patchid-y")) * (std::stoi(patch->getFrameData("patch-height")) - patchOverlapY*2);
        if(m_outputImage) {
            cl::Program program = getOpenCLProgram(device, "2D");

			auto patchAccess = patch->getOpenCLImageAccess(ACCESS_READ, device);
            auto outputAccess = m_outputImage->getOpenCLImageAccess(ACCESS_READ_WRITE, device);

            cl::Kernel kernel(program, "applyPatch2D");
            kernel.setArg(0, *patchAccess->get2DImage());
            kernel.setArg(1, *outputAccess->get2DImage());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, patchOverlapX);
            kernel.setArg(5, patchOverlapY);
            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(patch->getWidth(), patch->getHeight()),
                cl::NullRange
            );
        } else {
            if(patch->getWidth() <= patchOverlapX*2 || patch->getHeight() <= patchOverlapY*2) // Image to small..
                return;
            auto outputAccess = m_outputImagePyramid->getAccess(ACCESS_READ_WRITE);
            mRuntimeManager->startRegularTimer("copy patch");
            if(patchOverlapX > 0 || patchOverlapY > 0) {
                patch = patch->crop(
                        Vector2i(patchOverlapX, patchOverlapY),
                        Vector2i(patch->getWidth() - patchOverlapX * 2, patch->getHeight() - patchOverlapY * 2)
                );
            }
            outputAccess->setPatch(0, startX, startY, patch);
            mRuntimeManager->stopRegularTimer("copy patch");
        }
    } else {
        // 3D
        // TODO overlap not implemented for 3D
        const int startX = 0;
        const int startY = 0;
        const int startZ = std::stoi(patch->getFrameData("patch-offset-z"));
        const int endX = startX + patch->getWidth();
        const int endY = startY + patch->getHeight();
        reportInfo() << "Stitching " << startZ << reportEnd();
		auto patchAccess = patch->getOpenCLImageAccess(ACCESS_READ, device);

        if(device->isWritingTo3DTexturesSupported()) {
            auto outputAccess = m_outputImage->getOpenCLImageAccess(ACCESS_READ_WRITE, device);
            cl::Program program = getOpenCLProgram(device, "3D");
            cl::Kernel kernel(program, "applyPatch3D");
            kernel.setArg(0, *patchAccess->get3DImage());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, startZ);
            kernel.setArg(1, *outputAccess->get3DImage());

            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(patch->getWidth(), patch->getHeight(), patch->getDepth()),
                cl::NullRange
            );
        } else {
            auto outputAccess = m_outputImage->getOpenCLBufferAccess(ACCESS_READ_WRITE, device);
            cl::Program program = getOpenCLProgram(device, "3D", "-DTYPE=" + getCTypeAsString(m_outputImage->getDataType()));
            cl::Kernel kernel(program, "applyPatch3D");
            kernel.setArg(0, *patchAccess->get3DImage());
            kernel.setArg(1, *outputAccess->get());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, startZ);
            kernel.setArg(5, fullWidth);
            kernel.setArg(6, fullHeight);
            kernel.setArg(7, m_outputImage->getNrOfChannels());

            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(patch->getWidth(), patch->getHeight(), patch->getDepth()),
                cl::NullRange
            );
        }

    }
}

}<commit_msg>Fixed out of bounds issue in patch stitcher when result is an Image<commit_after>#include <FAST/Data/Image.hpp>
#include <FAST/Data/ImagePyramid.hpp>
#include <FAST/Data/Tensor.hpp>
#include <FAST/Algorithms/NeuralNetwork/NeuralNetwork.hpp>
#include "PatchStitcher.hpp"

namespace fast {

PatchStitcher::PatchStitcher() {
    createInputPort<DataObject>(0); // Can be Image, Batch or Tensor
    createOutputPort<DataObject>(0); // Can be Image or Tensor

    createOpenCLProgram(Config::getKernelSourcePath() + "/Algorithms/ImagePatch/PatchStitcher2D.cl", "2D");
    createOpenCLProgram(Config::getKernelSourcePath() + "/Algorithms/ImagePatch/PatchStitcher3D.cl", "3D");
}

void PatchStitcher::execute() {
    auto patch = getInputData<DataObject>();
    mRuntimeManager->startRegularTimer("stitch patch");
    auto tensorPatch = std::dynamic_pointer_cast<Tensor>(patch);
    auto imagePatch = std::dynamic_pointer_cast<Image>(patch);
    auto batchOfPatches = std::dynamic_pointer_cast<Batch>(patch);
    if(batchOfPatches) {
       auto list = batchOfPatches->get();
       if(list.isTensors()) {
           for(auto&& tensor : list.getTensors())
               processTensor(tensor);
       }
        if(list.isImages()) {
            for(auto&& image : list.getImages())
                processImage(image);
        }
    } else {
        // Single
        if(tensorPatch) {
            processTensor(tensorPatch);
        } else if(imagePatch) {
            processImage(imagePatch);
        }
    }
    mRuntimeManager->stopRegularTimer("stitch patch");

    if(m_outputImage) {
        addOutputData(0, m_outputImage);
    } else if(m_outputTensor) {
        addOutputData(0, m_outputTensor);
    } else if(m_outputImagePyramid) {
        addOutputData(0, m_outputImagePyramid);
    } else {
        throw Exception("Unexpected event in PatchStitcher");
    }
}

void PatchStitcher::processTensor(std::shared_ptr<Tensor> patch) {
    const int fullWidth = std::stoi(patch->getFrameData("original-width"));
    const int fullHeight = std::stoi(patch->getFrameData("original-height"));

    const int patchWidth = std::stoi(patch->getFrameData("patch-width"));
    const int patchHeight = std::stoi(patch->getFrameData("patch-height"));

    const float patchSpacingX = std::stof(patch->getFrameData("patch-spacing-x"));
    const float patchSpacingY = std::stof(patch->getFrameData("patch-spacing-y"));

    auto shape = patch->getShape();
    if(shape.getDimensions() != 1) {
        throw Exception("Can only handle 1D tensors atm");
    }
    const int channels = shape[0];

    if(!m_outputTensor) {
        // Create output tensor
        TensorShape fullShape({(int)std::ceil((float)fullHeight / patchHeight), (int)std::ceil((float)fullWidth / patchWidth), channels});
        auto initializedData = std::make_unique<float[]>(fullShape.getTotalSize());
        m_outputTensor = Tensor::create(std::move(initializedData), fullShape);
        m_outputTensor->setSpacing(Vector3f(patchHeight*patchSpacingY, patchWidth*patchSpacingX, 1.0f));
    }
    reportInfo() << "Stitching " << patch->getFrameData("patchid-x") << " " << patch->getFrameData("patchid-y") << reportEnd();
    reportInfo() << "Stitching data" << patch->getFrameData("patch-spacing-x") << " " << patch->getFrameData("patch-spacing-y") << reportEnd();

    const int startX = std::stoi(patch->getFrameData("patchid-x"));
    const int startY = std::stoi(patch->getFrameData("patchid-y"));

    auto inputAccess = patch->getAccess(ACCESS_READ);
    auto tensorData = inputAccess->getData<1>();
    auto outputAccess = m_outputTensor->getAccess(ACCESS_READ_WRITE);
    auto outputTensorData = outputAccess->getData<3>();

    for(int i = 0; i < channels; ++i) {
        outputTensorData(startY, startX, i) = tensorData(i); // TODO fix
    }
    //outputTensorData(startY, startX, 1) = 1.0f; // TODO remove
}

void PatchStitcher::processImage(std::shared_ptr<Image> patch) {
    const int fullWidth = std::stoi(patch->getFrameData("original-width"));
    const int fullHeight = std::stoi(patch->getFrameData("original-height"));
    const float patchSpacingX = std::stof(patch->getFrameData("patch-spacing-x"));
    const float patchSpacingY = std::stof(patch->getFrameData("patch-spacing-y"));

    int fullDepth = 1;
    float patchSpacingZ = 1.0f;
    bool is3D = true;
    try {
        fullDepth = std::stoi(patch->getFrameData("original-depth"));
        patchSpacingZ = std::stof(patch->getFrameData("patch-spacing-z"));
    } catch(Exception &e) {
        // If exception: is a 2D image
        is3D = false;
    }

    if(!m_outputImage && !m_outputImagePyramid) {
        // Create output image
        if(is3D) {
			m_outputImage = Image::create(fullWidth, fullHeight, fullDepth, patch->getDataType(), patch->getNrOfChannels());
        } else {
            if(fullWidth < 8192 && fullHeight < 8192) {
                reportInfo() << "Patch stitcher creating image with size " << fullWidth << " " << fullHeight << reportEnd();
				m_outputImage = Image::create(fullWidth, fullHeight, patch->getDataType(), patch->getNrOfChannels());
            } else {
                // Large image, create image pyramid instead
                int patchWidth = std::stoi(patch->getFrameData("patch-width")) - 2*std::stoi(patch->getFrameData("patch-overlap-x"));
                int patchHeight = std::stoi(patch->getFrameData("patch-height")) - 2*std::stoi(patch->getFrameData("patch-overlap-y"));
                m_outputImagePyramid = ImagePyramid::create(fullWidth, fullHeight, patch->getNrOfChannels(), patchWidth, patchHeight);
                reportInfo() << "Patch stitcher creating image PYRAMID with size " << fullWidth << " " << fullHeight << ", patch size: " <<
                    patchWidth << " " << patchHeight << " Levels: " << m_outputImagePyramid->getNrOfLevels() << reportEnd();
            }
        }
        if(m_outputImage) {
            m_outputImage->fill(0);
            m_outputImage->setSpacing(Vector3f(patchSpacingX, patchSpacingY, patchSpacingZ));
        } else {
            //m_outputImagePyramid->fill(0);
            m_outputImagePyramid->setSpacing(Vector3f(patchSpacingX, patchSpacingY, patchSpacingZ));
        }
        try {
            auto transformData = split(patch->getFrameData("original-transform"));
            auto T = Transform::create();
            Affine3f transform;
            for(int i = 0; i < 16; ++i)
                transform.matrix()(i) = std::stof(transformData[i]);
            T->set(transform);
            if(m_outputImage) {
                m_outputImage->getSceneGraphNode()->setTransform(T);
            } else {
                m_outputImagePyramid->getSceneGraphNode()->setTransform(T);
            }
        } catch(Exception &e) {

        }
    }

    auto device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice());

    if(fullDepth == 1) {
		reportInfo() << "Stitching 2D data " << patch->getFrameData("patchid-x") << " " << patch->getFrameData("patchid-y")
			<< reportEnd();

        const int patchOverlapX = std::stoi(patch->getFrameData("patch-overlap-x"));
        const int patchOverlapY = std::stoi(patch->getFrameData("patch-overlap-y"));
        // Calculate offset. If this calculation is incorrect. Update in ImagePyramidPatchExporter as well.
        const int startX = std::stoi(patch->getFrameData("patchid-x")) * (std::stoi(patch->getFrameData("patch-width")) - patchOverlapX*2); // TODO + overlap to compensate for start offset
        const int startY = std::stoi(patch->getFrameData("patchid-y")) * (std::stoi(patch->getFrameData("patch-height")) - patchOverlapY*2);
        if(m_outputImage) {
            cl::Program program = getOpenCLProgram(device, "2D");

			auto patchAccess = patch->getOpenCLImageAccess(ACCESS_READ, device);
            auto outputAccess = m_outputImage->getOpenCLImageAccess(ACCESS_READ_WRITE, device);

            cl::Kernel kernel(program, "applyPatch2D");
            kernel.setArg(0, *patchAccess->get2DImage());
            kernel.setArg(1, *outputAccess->get2DImage());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, patchOverlapX);
            kernel.setArg(5, patchOverlapY);
            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(
                        std::min(patch->getWidth(), m_outputImage->getWidth()-startX),
                        std::min(patch->getHeight(), m_outputImage->getHeight()-startY)
                    ),
                cl::NullRange
            );
        } else {
            if(patch->getWidth() <= patchOverlapX*2 || patch->getHeight() <= patchOverlapY*2) // Image to small..
                return;
            auto outputAccess = m_outputImagePyramid->getAccess(ACCESS_READ_WRITE);
            mRuntimeManager->startRegularTimer("copy patch");
            if(patchOverlapX > 0 || patchOverlapY > 0) {
                patch = patch->crop(
                        Vector2i(patchOverlapX, patchOverlapY),
                        Vector2i(patch->getWidth() - patchOverlapX * 2, patch->getHeight() - patchOverlapY * 2)
                );
            }
            outputAccess->setPatch(0, startX, startY, patch);
            mRuntimeManager->stopRegularTimer("copy patch");
        }
    } else {
        // 3D
        // TODO overlap not implemented for 3D
        const int startX = 0;
        const int startY = 0;
        const int startZ = std::stoi(patch->getFrameData("patch-offset-z"));
        const int endX = startX + patch->getWidth();
        const int endY = startY + patch->getHeight();
        reportInfo() << "Stitching " << startZ << reportEnd();
		auto patchAccess = patch->getOpenCLImageAccess(ACCESS_READ, device);

        if(device->isWritingTo3DTexturesSupported()) {
            auto outputAccess = m_outputImage->getOpenCLImageAccess(ACCESS_READ_WRITE, device);
            cl::Program program = getOpenCLProgram(device, "3D");
            cl::Kernel kernel(program, "applyPatch3D");
            kernel.setArg(0, *patchAccess->get3DImage());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, startZ);
            kernel.setArg(1, *outputAccess->get3DImage());

            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(patch->getWidth(), patch->getHeight(), patch->getDepth()),
                cl::NullRange
            );
        } else {
            auto outputAccess = m_outputImage->getOpenCLBufferAccess(ACCESS_READ_WRITE, device);
            cl::Program program = getOpenCLProgram(device, "3D", "-DTYPE=" + getCTypeAsString(m_outputImage->getDataType()));
            cl::Kernel kernel(program, "applyPatch3D");
            kernel.setArg(0, *patchAccess->get3DImage());
            kernel.setArg(1, *outputAccess->get());
            kernel.setArg(2, startX);
            kernel.setArg(3, startY);
            kernel.setArg(4, startZ);
            kernel.setArg(5, fullWidth);
            kernel.setArg(6, fullHeight);
            kernel.setArg(7, m_outputImage->getNrOfChannels());

            device->getCommandQueue().enqueueNDRangeKernel(
                kernel,
                cl::NullRange,
                cl::NDRange(patch->getWidth(), patch->getHeight(), patch->getDepth()),
                cl::NullRange
            );
        }

    }
}

}<|endoftext|>