<commit_before>/* OpenSceneGraph example, osgshaderterrain.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <osg/AlphaFunc>
#include <osg/Billboard>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/GL2Extensions>
#include <osg/Material>
#include <osg/Math>
#include <osg/MatrixTransform>
#include <osg/PolygonOffset>
#include <osg/Program>
#include <osg/Projection>
#include <osg/Shader>
#include <osg/ShapeDrawable>
#include <osg/StateSet>
#include <osg/Switch>
#include <osg/Texture2D>
#include <osg/Uniform>

#include <osgDB/ReadFile>
#include <osgDB/FileUtils>

#include <osgUtil/IntersectVisitor>
#include <osgUtil/SmoothingVisitor>

#include <osgText/Text>

#include <osgViewer/Viewer>

#include <iostream>

// for the grid data..
#include "../osghangglide/terrain_coords.h"

osg::Node* createScene()
{
    osg::Group* scene = new osg::Group;

    unsigned int numColumns = 38;
    unsigned int numRows = 39;
    unsigned int r;
    unsigned int c;

    osg::Vec3 origin(0.0f,0.0f,0.0f);
    osg::Vec3 size(1000.0f,1000.0f,250.0f);
    osg::Vec3 scaleDown(1.0f/size.x(),1.0f/size.y(),1.0f/size.z());

    // ---------------------------------------
    // Set up a StateSet to texture the objects
    // ---------------------------------------
    osg::StateSet* stateset = new osg::StateSet();

    osg::Uniform* originUniform = new osg::Uniform("terrainOrigin",origin);
    stateset->addUniform(originUniform);

    osg::Uniform* sizeUniform = new osg::Uniform("terrainSize",size);
    stateset->addUniform(sizeUniform);

    osg::Uniform* scaleDownUniform = new osg::Uniform("terrainScaleDown",scaleDown);
    stateset->addUniform(scaleDownUniform);

    osg::Uniform* terrainTextureSampler = new osg::Uniform("terrainTexture",0);
    stateset->addUniform(terrainTextureSampler);

    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",1);
    stateset->addUniform(baseTextureSampler);

    osg::Uniform* treeTextureSampler = new osg::Uniform("treeTexture",1);
    stateset->addUniform(treeTextureSampler);

    // compute z range of z values of grid data so we can scale it.
    float min_z = FLT_MAX;
    float max_z = -FLT_MAX;
    for(r=0;r<numRows;++r)
    {
        for(c=0;c<numColumns;++c)
        {
            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
        }
    }

    float scale_z = size.z()/(max_z-min_z);

    osg::Image* terrainImage = new osg::Image;
    terrainImage->allocateImage(numColumns,numRows,1,GL_LUMINANCE, GL_FLOAT);
    terrainImage->setInternalTextureFormat(GL_LUMINANCE_FLOAT32_ATI);
    for(r=0;r<numRows;++r)
    {
        for(c=0;c<numColumns;++c)
        {
            *((float*)(terrainImage->data(c,r))) = (vertex[r+c*numRows][2]-min_z)*scale_z;
        }
    }

    osg::Texture2D* terrainTexture = new osg::Texture2D;
    terrainTexture->setImage(terrainImage);
    terrainTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
    terrainTexture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
    terrainTexture->setResizeNonPowerOfTwoHint(false);
    stateset->setTextureAttributeAndModes(0,terrainTexture,osg::StateAttribute::ON);

    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
    if (image)
    {
        osg::Texture2D* texture = new osg::Texture2D;

        texture->setImage(image);
        stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
    }

    {
        std::cout<<"Creating terrain...";

        osg::Geode* geode = new osg::Geode();
        geode->setStateSet( stateset );

        {
            osg::Program* program = new osg::Program;
            stateset->setAttribute(program);

#if 1
            // use inline shaders

            ///////////////////////////////////////////////////////////////////
            // vertex shader using just Vec4 coefficients
            char vertexShaderSource[] =
               "uniform sampler2D terrainTexture;\n"
               "uniform vec3 terrainOrigin;\n"
               "uniform vec3 terrainScaleDown;\n"
               "\n"
               "varying vec2 texcoord;\n"
               "\n"
               "void main(void)\n"
               "{\n"
               "    texcoord = gl_Vertex.xy - terrainOrigin.xy;\n"
               "    texcoord.x *= terrainScaleDown.x;\n"
               "    texcoord.y *= terrainScaleDown.y;\n"
               "\n"
               "    vec4 position;\n"
               "    position.x = gl_Vertex.x;\n"
               "    position.y = gl_Vertex.y;\n"
               "    position.z = texture2D(terrainTexture, texcoord).r;\n"
               "    position.w = 1.0;\n"
               " \n"
               "    gl_Position     = gl_ModelViewProjectionMatrix * position;\n"
                "   gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
               "}\n";

            //////////////////////////////////////////////////////////////////
            // fragment shader
            //
            char fragmentShaderSource[] =
                "uniform sampler2D baseTexture; \n"
                "varying vec2 texcoord;\n"
                "\n"
                "void main(void) \n"
                "{\n"
                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
                "}\n";

            program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));

#else

            // get shaders from source
            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/terrain.vert")));
            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/terrain.frag")));

#endif

            // get shaders from source
        }

        {
            osg::Geometry* geometry = new osg::Geometry;

            osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
            osg::Vec4ubArray& color = *(new osg::Vec4ubArray(1));

            color[0].set(255,255,255,255);

            float rowCoordDelta = size.y()/(float)(numRows-1);
            float columnCoordDelta = size.x()/(float)(numColumns-1);

            float rowTexDelta = 1.0f/(float)(numRows-1);
            float columnTexDelta = 1.0f/(float)(numColumns-1);

            osg::Vec3 pos = origin;
            osg::Vec2 tex(0.0f,0.0f);
            int vi=0;
            for(r=0;r<numRows;++r)
            {
                pos.x() = origin.x();
                tex.x() = 0.0f;
                for(c=0;c<numColumns;++c)
                {
                    v[vi].set(pos.x(),pos.y(),pos.z());
                    pos.x()+=columnCoordDelta;
                    tex.x()+=columnTexDelta;
                    ++vi;
                }
                pos.y() += rowCoordDelta;
                tex.y() += rowTexDelta;
            }

            geometry->setVertexArray(&v);
            geometry->setColorArray(&color);
            geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

            for(r=0;r<numRows-1;++r)
            {
                osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
                geometry->addPrimitiveSet(&drawElements);
                int ei=0;
                for(c=0;c<numColumns;++c)
                {
                    drawElements[ei++] = (r+1)*numColumns+c;
                    drawElements[ei++] = (r)*numColumns+c;
                }
            }

            geometry->setInitialBound(osg::BoundingBox(origin, origin+size));

            geode->addDrawable(geometry);

            scene->addChild(geode);
        }
    }

    std::cout<<"done."<<std::endl;

    return scene;
}

class TestSupportOperation: public osg::Operation
{
public:

    TestSupportOperation():
        osg::Operation("TestSupportOperation",false),
        _supported(true),
        _errorMessage() {}

    virtual void operator () (osg::Object* object)
    {
        osg::GraphicsContext* gc = dynamic_cast<osg::GraphicsContext*>(object);
        if (!gc) return;

        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);

        unsigned int contextID = gc->getState()->getContextID();
        osg::GL2Extensions* gl2ext = osg::GL2Extensions::Get(contextID,true);
        if( gl2ext )
        {
            if( !gl2ext->isGlslSupported() )
            {
                _supported = false;
                _errorMessage = "ERROR: GLSL not supported by OpenGL driver.";
            }

            GLint numVertexTexUnits = 0;
            glGetIntegerv( GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexTexUnits );
            if( numVertexTexUnits <= 0 )
            {
                _supported = false;
                _errorMessage = "ERROR: vertex texturing not supported by OpenGL driver.";
            }
        }
        else
        {
            _supported = false;
            _errorMessage = "ERROR: GLSL not supported.";
        }
    }

    OpenThreads::Mutex  _mutex;
    bool                _supported;
    std::string         _errorMessage;
};

int main(int, char **)
{
    // construct the viewer.
    osgViewer::Viewer viewer;

    osg::Node* node = createScene();

    // add model to viewer.
    viewer.setSceneData( node );

    viewer.setUpViewAcrossAllScreens();

    osg::ref_ptr<TestSupportOperation> testSupportOperation = new TestSupportOperation;
#if 0
    // temporily commenting out as its causing the viewer to crash... no clue yet to why
    viewer.setRealizeOperation(testSupportOperation.get());
#endif
    // create the windows and run the threads.
    viewer.realize();

    if (!testSupportOperation->_supported)
    {
        osg::notify(osg::WARN)<<testSupportOperation->_errorMessage<<std::endl;

        return 1;
    }

    return viewer.run();
}
<commit_msg>Changed across to using a GraphicsOperation as the base class for the RealizeOperation.<commit_after>/* OpenSceneGraph example, osgshaderterrain.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <osg/AlphaFunc>
#include <osg/Billboard>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/GL2Extensions>
#include <osg/Material>
#include <osg/Math>
#include <osg/MatrixTransform>
#include <osg/PolygonOffset>
#include <osg/Program>
#include <osg/Projection>
#include <osg/Shader>
#include <osg/ShapeDrawable>
#include <osg/StateSet>
#include <osg/Switch>
#include <osg/Texture2D>
#include <osg/Uniform>

#include <osgDB/ReadFile>
#include <osgDB/FileUtils>

#include <osgUtil/IntersectVisitor>
#include <osgUtil/SmoothingVisitor>

#include <osgText/Text>

#include <osgViewer/Viewer>

#include <iostream>

// for the grid data..
#include "../osghangglide/terrain_coords.h"

osg::Node* createScene()
{
    osg::Group* scene = new osg::Group;

    unsigned int numColumns = 38;
    unsigned int numRows = 39;
    unsigned int r;
    unsigned int c;

    osg::Vec3 origin(0.0f,0.0f,0.0f);
    osg::Vec3 size(1000.0f,1000.0f,250.0f);
    osg::Vec3 scaleDown(1.0f/size.x(),1.0f/size.y(),1.0f/size.z());

    // ---------------------------------------
    // Set up a StateSet to texture the objects
    // ---------------------------------------
    osg::StateSet* stateset = new osg::StateSet();

    osg::Uniform* originUniform = new osg::Uniform("terrainOrigin",origin);
    stateset->addUniform(originUniform);

    osg::Uniform* sizeUniform = new osg::Uniform("terrainSize",size);
    stateset->addUniform(sizeUniform);

    osg::Uniform* scaleDownUniform = new osg::Uniform("terrainScaleDown",scaleDown);
    stateset->addUniform(scaleDownUniform);

    osg::Uniform* terrainTextureSampler = new osg::Uniform("terrainTexture",0);
    stateset->addUniform(terrainTextureSampler);

    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",1);
    stateset->addUniform(baseTextureSampler);

    osg::Uniform* treeTextureSampler = new osg::Uniform("treeTexture",1);
    stateset->addUniform(treeTextureSampler);

    // compute z range of z values of grid data so we can scale it.
    float min_z = FLT_MAX;
    float max_z = -FLT_MAX;
    for(r=0;r<numRows;++r)
    {
        for(c=0;c<numColumns;++c)
        {
            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
        }
    }

    float scale_z = size.z()/(max_z-min_z);

    osg::Image* terrainImage = new osg::Image;
    terrainImage->allocateImage(numColumns,numRows,1,GL_LUMINANCE, GL_FLOAT);
    terrainImage->setInternalTextureFormat(GL_LUMINANCE_FLOAT32_ATI);
    for(r=0;r<numRows;++r)
    {
        for(c=0;c<numColumns;++c)
        {
            *((float*)(terrainImage->data(c,r))) = (vertex[r+c*numRows][2]-min_z)*scale_z;
        }
    }

    osg::Texture2D* terrainTexture = new osg::Texture2D;
    terrainTexture->setImage(terrainImage);
    terrainTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
    terrainTexture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
    terrainTexture->setResizeNonPowerOfTwoHint(false);
    stateset->setTextureAttributeAndModes(0,terrainTexture,osg::StateAttribute::ON);

    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
    if (image)
    {
        osg::Texture2D* texture = new osg::Texture2D;

        texture->setImage(image);
        stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
    }

    {
        std::cout<<"Creating terrain...";

        osg::Geode* geode = new osg::Geode();
        geode->setStateSet( stateset );

        {
            osg::Program* program = new osg::Program;
            stateset->setAttribute(program);

#if 1
            // use inline shaders

            ///////////////////////////////////////////////////////////////////
            // vertex shader using just Vec4 coefficients
            char vertexShaderSource[] =
               "uniform sampler2D terrainTexture;\n"
               "uniform vec3 terrainOrigin;\n"
               "uniform vec3 terrainScaleDown;\n"
               "\n"
               "varying vec2 texcoord;\n"
               "\n"
               "void main(void)\n"
               "{\n"
               "    texcoord = gl_Vertex.xy - terrainOrigin.xy;\n"
               "    texcoord.x *= terrainScaleDown.x;\n"
               "    texcoord.y *= terrainScaleDown.y;\n"
               "\n"
               "    vec4 position;\n"
               "    position.x = gl_Vertex.x;\n"
               "    position.y = gl_Vertex.y;\n"
               "    position.z = texture2D(terrainTexture, texcoord).r;\n"
               "    position.w = 1.0;\n"
               " \n"
               "    gl_Position     = gl_ModelViewProjectionMatrix * position;\n"
                "   gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
               "}\n";

            //////////////////////////////////////////////////////////////////
            // fragment shader
            //
            char fragmentShaderSource[] =
                "uniform sampler2D baseTexture; \n"
                "varying vec2 texcoord;\n"
                "\n"
                "void main(void) \n"
                "{\n"
                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
                "}\n";

            program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
            program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));

#else

            // get shaders from source
            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/terrain.vert")));
            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/terrain.frag")));

#endif

            // get shaders from source
        }

        {
            osg::Geometry* geometry = new osg::Geometry;

            osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
            osg::Vec4ubArray& color = *(new osg::Vec4ubArray(1));

            color[0].set(255,255,255,255);

            float rowCoordDelta = size.y()/(float)(numRows-1);
            float columnCoordDelta = size.x()/(float)(numColumns-1);

            float rowTexDelta = 1.0f/(float)(numRows-1);
            float columnTexDelta = 1.0f/(float)(numColumns-1);

            osg::Vec3 pos = origin;
            osg::Vec2 tex(0.0f,0.0f);
            int vi=0;
            for(r=0;r<numRows;++r)
            {
                pos.x() = origin.x();
                tex.x() = 0.0f;
                for(c=0;c<numColumns;++c)
                {
                    v[vi].set(pos.x(),pos.y(),pos.z());
                    pos.x()+=columnCoordDelta;
                    tex.x()+=columnTexDelta;
                    ++vi;
                }
                pos.y() += rowCoordDelta;
                tex.y() += rowTexDelta;
            }

            geometry->setVertexArray(&v);
            geometry->setColorArray(&color);
            geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

            for(r=0;r<numRows-1;++r)
            {
                osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
                geometry->addPrimitiveSet(&drawElements);
                int ei=0;
                for(c=0;c<numColumns;++c)
                {
                    drawElements[ei++] = (r+1)*numColumns+c;
                    drawElements[ei++] = (r)*numColumns+c;
                }
            }

            geometry->setInitialBound(osg::BoundingBox(origin, origin+size));

            geode->addDrawable(geometry);

            scene->addChild(geode);
        }
    }

    std::cout<<"done."<<std::endl;

    return scene;
}

class TestSupportOperation: public osg::GraphicsOperation
{
public:

    TestSupportOperation():
        osg::GraphicsOperation("TestSupportOperation",false),
        _supported(true),
        _errorMessage() {}

    virtual void operator () (osg::GraphicsContext* gc)
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);

        unsigned int contextID = gc->getState()->getContextID();
        osg::GL2Extensions* gl2ext = osg::GL2Extensions::Get(contextID,true);
        if( gl2ext )
        {
            if( !gl2ext->isGlslSupported() )
            {
                _supported = false;
                _errorMessage = "ERROR: GLSL not supported by OpenGL driver.";
            }

            GLint numVertexTexUnits = 0;
            glGetIntegerv( GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &numVertexTexUnits );
            if( numVertexTexUnits <= 0 )
            {
                _supported = false;
                _errorMessage = "ERROR: vertex texturing not supported by OpenGL driver.";
            }
        }
        else
        {
            _supported = false;
            _errorMessage = "ERROR: GLSL not supported.";
        }
    }

    OpenThreads::Mutex  _mutex;
    bool                _supported;
    std::string         _errorMessage;
};

int main(int, char **)
{
    // construct the viewer.
    osgViewer::Viewer viewer;

    osg::Node* node = createScene();

    // add model to viewer.
    viewer.setSceneData( node );

    viewer.setUpViewAcrossAllScreens();

    osg::ref_ptr<TestSupportOperation> testSupportOperation = new TestSupportOperation;
#if 0
    // temporily commenting out as its causing the viewer to crash... no clue yet to why
    viewer.setRealizeOperation(testSupportOperation.get());
#endif
    // create the windows and run the threads.
    viewer.realize();

    if (!testSupportOperation->_supported)
    {
        osg::notify(osg::WARN)<<testSupportOperation->_errorMessage<<std::endl;

        return 1;
    }

    return viewer.run();
}
<|endoftext|>


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

Copyright The University of Auckland

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.

*******************************************************************************/

//==============================================================================
// Single Cell view information parameters widget
//==============================================================================

#include "cellmlfileruntime.h"
#include "singlecellviewinformationparameterswidget.h"
#include "singlecellviewsimulation.h"
#include "singlecellviewsimulationwidget.h"

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

#include <QMenu>

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

namespace OpenCOR {
namespace SingleCellView {

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

SingleCellViewInformationParametersWidget::SingleCellViewInformationParametersWidget(QWidget *pParent) :
    PropertyEditorWidget(false, pParent),
    mParameters(QMap<Core::Property *, CellMLSupport::CellmlFileRuntimeParameter *>()),
    mParameterActions(QMap<QAction *, CellMLSupport::CellmlFileRuntimeParameter *>()),
    mSimulation(0),
    mNeedClearing(false),
    mVoiAccessible(false)
{
    // Create our context menu

    mContextMenu = new QMenu(this);

    // We want our own context menu

    setContextMenuPolicy(Qt::CustomContextMenu);

    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(propertyEditorContextMenu(const QPoint &)));

    // Keep track of when the user changes a property value

    connect(this, SIGNAL(propertyChanged(Core::Property *)),
            this, SLOT(propertyChanged(Core::Property *)));
}

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

void SingleCellViewInformationParametersWidget::retranslateContextMenu()
{
    // Retranslate our context menu, in case it has been populated

    if (mContextMenu->actions().count() >= mVoiAccessible+1) {
        if (mVoiAccessible)
            mContextMenu->actions()[0]->setText(tr("Plot Against Variable of Integration"));

        mContextMenu->actions()[(mVoiAccessible?0:-1)+1]->setText(tr("Plot Against"));
    }
}

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

void SingleCellViewInformationParametersWidget::retranslateUi()
{
    // Default retranslation

    PropertyEditorWidget::retranslateUi();

    // Retranslate our context menu

    retranslateContextMenu();

    // Retranslate the extra info of all our parameters

    updateExtraInfos();
}

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

void SingleCellViewInformationParametersWidget::initialize(SingleCellViewSimulation *pSimulation,
                                                           const bool &pReloadingView)
{
    // Keep track of the simulation

    mSimulation = pSimulation;

    // First clear ourselves, if needed

    if (mNeedClearing) {
        clear();

        mNeedClearing = false;
    }

    // Check whether our model's variable of integration is among our model's
    // parameters (i.e. it is defined in the main CellML file)

    CellMLSupport::CellmlFileRuntime *runtime = pSimulation->runtime();

    mVoiAccessible = runtime->parameters().contains(runtime->variableOfIntegration());

    // Retranslate our core self, if needed
    // Note: part of reloading ourselves consists of finalising ourselves, which
    //       means clearing all of our contents including our header labels. So,
    //       we need to 'retranslate' them otherwise they will read "1", "2",
    //       "3", etc.

    if (pReloadingView)
        PropertyEditorWidget::retranslateUi();

    // Populate our property editor and context menu

    populateModel(runtime);
    populateContextMenu(runtime);

    // Keep track of when some of the model's data has changed

    connect(pSimulation->data(), SIGNAL(updated(const double &)),
            this, SLOT(updateParameters(const double &)));
}

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

void SingleCellViewInformationParametersWidget::finalize()
{
    // Clear ourselves, as well as our context menu, parameters and parameter
    // actions

    mNeedClearing = true;

    mContextMenu->clear();

    mParameters.clear();
    mParameterActions.clear();
}

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

void SingleCellViewInformationParametersWidget::updateParameters(const double &pCurrentPoint)
{
    // Update our data

    foreach (Core::Property *property, properties()) {
        CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(property);

        if (parameter) {
            switch (parameter->type()) {
            case CellMLSupport::CellmlFileRuntimeParameter::Voi:
                property->setDoubleValue(pCurrentPoint, false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Constant:
            case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
                property->setDoubleValue(mSimulation->data()->constants()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Rate:
                property->setDoubleValue(mSimulation->data()->rates()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::State:
                property->setDoubleValue(mSimulation->data()->states()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
                property->setDoubleValue(mSimulation->data()->algebraic()[parameter->index()], false);

                break;
            default:
                // Not a relevant type, so do nothing

                break;
            }
        }
    }

    // Check whether any of our properties has actually been modified

    mSimulation->data()->checkForModifications();
}

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

void SingleCellViewInformationParametersWidget::propertyChanged(Core::Property *pProperty)
{
    // Update our simulation data

    CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(pProperty);

    if (parameter) {
        switch (parameter->type()) {
        case CellMLSupport::CellmlFileRuntimeParameter::Constant:
            mSimulation->data()->constants()[parameter->index()] = pProperty->doubleValue();

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::State:
            mSimulation->data()->states()[parameter->index()] = pProperty->doubleValue();

            break;
        default:
            // Not a relevant type, so do nothing

            ;
        }
    }

    // Recompute our 'computed constants' and 'variables'
    // Note #1: we would normally call
    //          mSimulation->data()->checkForModifications() after recomputing
    //          our 'computed constants' and 'variables, but the recomputation
    //          will eventually result in updateParameters() above to be called,
    //          which will check for modifications...
    // Note #2: some state variables may be considered as computed constants by
    //          the CellML API. This is fine when we need to initialise things,
    //          but not after the user has modified one or several model
    //          parameters (see issue #234 for more information), hence our
    //          passing false to mSimulation->data()->reset()...

    mSimulation->data()->reset(false);
}

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

QMap<Core::Property *, CellMLSupport::CellmlFileRuntimeParameter *> SingleCellViewInformationParametersWidget::parameters() const
{
    // Return our parameters

    return mParameters;
}

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

void SingleCellViewInformationParametersWidget::populateModel(CellMLSupport::CellmlFileRuntime *pRuntime)
{
    // Populate our property editor with the parameters

    QString componentHierarchy = QString();
    Core::Property *sectionProperty = 0;

    foreach (CellMLSupport::CellmlFileRuntimeParameter *parameter, pRuntime->parameters()) {
        // Check whether the current parameter is in the same component
        // hierarchy as the previous one

        QString crtComponentHierarchy = parameter->formattedComponentHierarchy();

        if (crtComponentHierarchy.compare(componentHierarchy)) {
            // The current parameter is in a different component hierarchy, so
            // create a new section hierarchy for our 'new' component, reusing
            // existing sections, whenever possible

            Core::Property *section = 0;

            foreach (const QString &component, parameter->componentHierarchy()) {
                // Check whether we already have a section for our current
                // component

                sectionProperty = 0;

                // Retrieve the sub-sections for the current section

                QList<Core::Property *> subSections = QList<Core::Property *>();

                if (section) {
                    // We have a section, so go through its children and keep
                    // track of its propeties that are a section

                    foreach (QObject *object, section->children()) {
                        Core::Property *property = qobject_cast<Core::Property *>(object);

                        if (   property
                            && (property->type() == Core::Property::Section)) {
                            subSections << property;
                        }
                    }
                } else {
                    // We don't have a section, so go through our properties and
                    // keep tack of those that are a section

                    foreach (Core::Property *property, properties()) {
                        if (property->type() == Core::Property::Section)
                            subSections << property;
                    }
                }

                // Go through the sub-sections and check if one of them is the
                // one we are after

                foreach (Core::Property *subSection, subSections) {
                    if (!subSection->name().compare(component)) {
                        sectionProperty = subSection;

                        break;
                    }
                }

                // Create a new section for our current component, if none could
                // be found

                if (!sectionProperty)
                    sectionProperty = addSectionProperty(component, section);

                // Get ready for the next component in our component hierarchy

                section = sectionProperty;
            }

            // Keep track of the new component hierarchy

            componentHierarchy = crtComponentHierarchy;
        }

        // Add the current parameter to the current section property, after
        // having retrieved its current value

        double propertyValue = 0.0;

        switch (parameter->type()) {
        case CellMLSupport::CellmlFileRuntimeParameter::Voi:
            propertyValue = mSimulation->data()->startingPoint();

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Constant:
        case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
            propertyValue = mSimulation->data()->constants()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Rate:
            propertyValue = mSimulation->data()->rates()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::State:
            propertyValue = mSimulation->data()->states()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
            propertyValue = mSimulation->data()->algebraic()[parameter->index()];

            break;
        default:
            // Not a relevant type, so do nothing

            ;
        }

        Core::Property *property = addDoubleProperty(propertyValue, sectionProperty);

        property->setEditable(   (parameter->type() == CellMLSupport::CellmlFileRuntimeParameter::Constant)
                              || (parameter->type() == CellMLSupport::CellmlFileRuntimeParameter::State));

        property->setIcon(SingleCellViewSimulationWidget::parameterIcon(parameter->type()));

        property->setName(parameter->formattedName(), false);
        property->setUnit(parameter->formattedUnit(pRuntime->variableOfIntegration()->unit()), false);

        // Keep track of the link between our property value and parameter

        mParameters.insert(property, parameter);
    }

    // Update (well, set here) the extra info of all our parameters

    updateExtraInfos();

    // Expand all our properties

    expandAll();
}

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

void SingleCellViewInformationParametersWidget::populateContextMenu(CellMLSupport::CellmlFileRuntime *pRuntime)
{
    // Create our two main menu items

    QAction *voiAction = mVoiAccessible?mContextMenu->addAction(QString()):0;
    QMenu *plotAgainstMenu = new QMenu(mContextMenu);

    mContextMenu->addAction(plotAgainstMenu->menuAction());

    // Initialise our two main menu items

    retranslateContextMenu();

    // Create a connection to handle the graph requirement against our variable
    // of integration, and keep track of the parameter associated with our first
    // main menu item

    if (mVoiAccessible) {
        connect(voiAction, SIGNAL(triggered(bool)),
                this, SLOT(emitGraphRequired()));

        mParameterActions.insert(voiAction, pRuntime->variableOfIntegration());
    }

    // Populate our context menu with the parameters

    QString componentHierarchy = QString();
    QMenu *componentMenu = 0;

    foreach (CellMLSupport::CellmlFileRuntimeParameter *parameter, pRuntime->parameters()) {
        // Check whether the current parameter is in the same component
        // hierarchy as the previous one

        QString crtComponentHierarchy = parameter->formattedComponentHierarchy();

        if (crtComponentHierarchy.compare(componentHierarchy)) {
            // The current parameter is in a different component hierarchy, so
            // create a new menu hierarchy for our 'new' component, reusing
            // existing menus, whenever possible

            QMenu *menu = plotAgainstMenu;

            foreach (const QString &component, parameter->componentHierarchy()) {
                // Check whether we already have a menu for our current
                // component

                componentMenu = 0;

                foreach (QObject *object, menu->children()) {
                    QMenu *subMenu = qobject_cast<QMenu *>(object);

                    if (    subMenu
                        && !subMenu->menuAction()->text().compare(component)) {
                        componentMenu = subMenu;

                        break;
                    }
                }

                // Create a new menu for our current component, if none could be
                // found

                if (!componentMenu) {
                    componentMenu = new QMenu(component, menu);

                    menu->addMenu(componentMenu);
                }

                // Get ready for the next component in our component hierarchy

                menu = componentMenu;
            }

            // Keep track of the new component hierarchy

            componentHierarchy = crtComponentHierarchy;
        }

        // Make sure that we have a 'current' component menu
        // Note: this should never happen, but we never know...

        if (!componentMenu)
            continue;

        // Add the current parameter to the 'current' component menu

        QAction *parameterAction = componentMenu->addAction(SingleCellViewSimulationWidget::parameterIcon(parameter->type()),
                                                            parameter->formattedName());

        // Create a connection to handle the graph requirement against our
        // parameter

        connect(parameterAction, SIGNAL(triggered(bool)),
                this, SLOT(emitGraphRequired()));

        // Keep track of the parameter associated with our model parameter
        // action

        mParameterActions.insert(parameterAction, parameter);
    }
}

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

void SingleCellViewInformationParametersWidget::updateExtraInfos()
{
    // Update the extra info of all our properties

    foreach (Core::Property *property, properties()) {
        CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(property);

        if (parameter) {
            QString parameterType = QString();

            switch (parameter->type()) {
            case CellMLSupport::CellmlFileRuntimeParameter::Voi:
                parameterType = tr("variable of integration");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Constant:
                parameterType = tr("constant");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
                parameterType = tr("computed constant");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Rate:
                parameterType = tr("rate");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::State:
                parameterType = tr("state");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
                parameterType = tr("algebraic");

                break;
            default:
                // Not a relevant type, so do nothing

                ;
            }

            property->setExtraInfo(parameterType);
        }
    }
}

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

void SingleCellViewInformationParametersWidget::propertyEditorContextMenu(const QPoint &pPosition) const
{
    Q_UNUSED(pPosition);

    // Make sure that we have a current property

    Core::Property *crtProperty = currentProperty();

    if (!crtProperty)
        return;

    // Make sure that our current property is not a section

    if (crtProperty->type() == Core::Property::Section)
        return;

    // Generate and show the context menu

    mContextMenu->exec(QCursor::pos());
}

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

void SingleCellViewInformationParametersWidget::emitGraphRequired()
{
    // Let people know that we want to plot the current parameter against
    // another

    emit graphRequired(mParameterActions.value(qobject_cast<QAction *>(sender())),
                       mParameters.value(currentProperty()));
}

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

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Copyright The University of Auckland

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.

*******************************************************************************/

//==============================================================================
// Single Cell view information parameters widget
//==============================================================================

#include "cellmlfileruntime.h"
#include "singlecellviewinformationparameterswidget.h"
#include "singlecellviewsimulation.h"
#include "singlecellviewsimulationwidget.h"

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

#include <QMenu>

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

namespace OpenCOR {
namespace SingleCellView {

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

SingleCellViewInformationParametersWidget::SingleCellViewInformationParametersWidget(QWidget *pParent) :
    PropertyEditorWidget(false, pParent),
    mParameters(QMap<Core::Property *, CellMLSupport::CellmlFileRuntimeParameter *>()),
    mParameterActions(QMap<QAction *, CellMLSupport::CellmlFileRuntimeParameter *>()),
    mSimulation(0),
    mNeedClearing(false),
    mVoiAccessible(false)
{
    // Create our context menu

    mContextMenu = new QMenu(this);

    // We want our own context menu

    setContextMenuPolicy(Qt::CustomContextMenu);

    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(propertyEditorContextMenu(const QPoint &)));

    // Keep track of when the user changes a property value

    connect(this, SIGNAL(propertyChanged(Core::Property *)),
            this, SLOT(propertyChanged(Core::Property *)));
}

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

void SingleCellViewInformationParametersWidget::retranslateContextMenu()
{
    // Retranslate our context menu, in case it has been populated

    if (mContextMenu->actions().count() >= mVoiAccessible+1) {
        if (mVoiAccessible)
            mContextMenu->actions()[0]->setText(tr("Plot Against Variable of Integration"));

        mContextMenu->actions()[(mVoiAccessible?0:-1)+1]->setText(tr("Plot Against"));
    }
}

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

void SingleCellViewInformationParametersWidget::retranslateUi()
{
    // Default retranslation

    PropertyEditorWidget::retranslateUi();

    // Retranslate our context menu

    retranslateContextMenu();

    // Retranslate the extra info of all our parameters

    updateExtraInfos();
}

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

void SingleCellViewInformationParametersWidget::initialize(SingleCellViewSimulation *pSimulation,
                                                           const bool &pReloadingView)
{
    // Keep track of the simulation

    mSimulation = pSimulation;

    // First clear ourselves, if needed

    if (mNeedClearing) {
        clear();

        mNeedClearing = false;
    }

    // Check whether our model's variable of integration is among our model's
    // parameters (i.e. it is defined in the main CellML file)

    CellMLSupport::CellmlFileRuntime *runtime = pSimulation->runtime();

    mVoiAccessible = runtime->parameters().contains(runtime->variableOfIntegration());

    // Retranslate our core self, if needed
    // Note: part of reloading ourselves consists of finalising ourselves, which
    //       means clearing all of our contents including our header labels. So,
    //       we need to 'retranslate' them otherwise they will read "1", "2",
    //       "3", etc.

    if (pReloadingView)
        PropertyEditorWidget::retranslateUi();

    // Populate our property editor and context menu

    populateModel(runtime);
    populateContextMenu(runtime);

    // Keep track of when some of the model's data has changed

    connect(pSimulation->data(), SIGNAL(updated(const double &)),
            this, SLOT(updateParameters(const double &)));
}

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

void SingleCellViewInformationParametersWidget::finalize()
{
    // Clear ourselves, as well as our context menu, parameters and parameter
    // actions

    mNeedClearing = true;

    mContextMenu->clear();

    mParameters.clear();
    mParameterActions.clear();
}

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

void SingleCellViewInformationParametersWidget::updateParameters(const double &pCurrentPoint)
{
    // Update our data

    foreach (Core::Property *property, properties()) {
        CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(property);

        if (parameter) {
            switch (parameter->type()) {
            case CellMLSupport::CellmlFileRuntimeParameter::Voi:
                property->setDoubleValue(pCurrentPoint, false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Constant:
            case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
                property->setDoubleValue(mSimulation->data()->constants()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Rate:
                property->setDoubleValue(mSimulation->data()->rates()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::State:
                property->setDoubleValue(mSimulation->data()->states()[parameter->index()], false);

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
                property->setDoubleValue(mSimulation->data()->algebraic()[parameter->index()], false);

                break;
            default:
                // Not a relevant type, so do nothing

                break;
            }
        }
    }

    // Check whether any of our properties has actually been modified

    mSimulation->data()->checkForModifications();
}

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

void SingleCellViewInformationParametersWidget::propertyChanged(Core::Property *pProperty)
{
    // Update our simulation data

    CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(pProperty);

    if (parameter) {
        switch (parameter->type()) {
        case CellMLSupport::CellmlFileRuntimeParameter::Constant:
            mSimulation->data()->constants()[parameter->index()] = pProperty->doubleValue();

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::State:
            mSimulation->data()->states()[parameter->index()] = pProperty->doubleValue();

            break;
        default:
            // Not a relevant type, so do nothing

            ;
        }
    }

    // Recompute our 'computed constants' and 'variables'
    // Note #1: we would normally call
    //          mSimulation->data()->checkForModifications() after recomputing
    //          our 'computed constants' and 'variables, but the recomputation
    //          will eventually result in updateParameters() above to be called,
    //          which will check for modifications...
    // Note #2: some state variables may be considered as computed constants by
    //          the CellML API. This is fine when we need to initialise things,
    //          but not after the user has modified one or several model
    //          parameters (see issue #234 for more information), hence our
    //          passing false to mSimulation->data()->reset()...

    mSimulation->data()->reset(false);
}

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

QMap<Core::Property *, CellMLSupport::CellmlFileRuntimeParameter *> SingleCellViewInformationParametersWidget::parameters() const
{
    // Return our parameters

    return mParameters;
}

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

void SingleCellViewInformationParametersWidget::populateModel(CellMLSupport::CellmlFileRuntime *pRuntime)
{
    // Populate our property editor with the parameters

    QString componentHierarchy = QString();
    Core::Property *sectionProperty = 0;

    foreach (CellMLSupport::CellmlFileRuntimeParameter *parameter, pRuntime->parameters()) {
        // Check whether the current parameter is in the same component
        // hierarchy as the previous one

        QString crtComponentHierarchy = parameter->formattedComponentHierarchy();

        if (crtComponentHierarchy.compare(componentHierarchy)) {
            // The current parameter is in a different component hierarchy, so
            // create a new section hierarchy for our 'new' component, reusing
            // existing sections, whenever possible

            Core::Property *parentSectionProperty = 0;

            foreach (const QString &component, parameter->componentHierarchy()) {
                // Check whether we already have a section for our current
                // component

                sectionProperty = 0;

                // Retrieve the sub-sections for the current section

                QList<Core::Property *> subSections = QList<Core::Property *>();

                if (parentSectionProperty) {
                    // We have a parent section, so go through its children and
                    // keep track of its propeties that are a section

                    foreach (QObject *object, parentSectionProperty->children()) {
                        Core::Property *property = qobject_cast<Core::Property *>(object);

                        if (   property
                            && (property->type() == Core::Property::Section)) {
                            subSections << property;
                        }
                    }
                } else {
                    // We don't have a section, so go through our properties and
                    // keep tack of those that are a section

                    foreach (Core::Property *property, properties()) {
                        if (property->type() == Core::Property::Section)
                            subSections << property;
                    }
                }

                // Go through the sub-sections and check if one of them is the
                // one we are after

                foreach (Core::Property *subSection, subSections) {
                    if (!subSection->name().compare(component)) {
                        sectionProperty = subSection;

                        break;
                    }
                }

                // Create a new section for our current component, if none could
                // be found

                if (!sectionProperty)
                    sectionProperty = addSectionProperty(component, parentSectionProperty);

                // Get ready for the next component in our component hierarchy

                parentSectionProperty = sectionProperty;
            }

            // Keep track of the new component hierarchy

            componentHierarchy = crtComponentHierarchy;
        }

        // Add the current parameter to the current section property, after
        // having retrieved its current value

        double propertyValue = 0.0;

        switch (parameter->type()) {
        case CellMLSupport::CellmlFileRuntimeParameter::Voi:
            propertyValue = mSimulation->data()->startingPoint();

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Constant:
        case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
            propertyValue = mSimulation->data()->constants()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Rate:
            propertyValue = mSimulation->data()->rates()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::State:
            propertyValue = mSimulation->data()->states()[parameter->index()];

            break;
        case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
            propertyValue = mSimulation->data()->algebraic()[parameter->index()];

            break;
        default:
            // Not a relevant type, so do nothing

            ;
        }

        Core::Property *property = addDoubleProperty(propertyValue, sectionProperty);

        property->setEditable(   (parameter->type() == CellMLSupport::CellmlFileRuntimeParameter::Constant)
                              || (parameter->type() == CellMLSupport::CellmlFileRuntimeParameter::State));

        property->setIcon(SingleCellViewSimulationWidget::parameterIcon(parameter->type()));

        property->setName(parameter->formattedName(), false);
        property->setUnit(parameter->formattedUnit(pRuntime->variableOfIntegration()->unit()), false);

        // Keep track of the link between our property value and parameter

        mParameters.insert(property, parameter);
    }

    // Update (well, set here) the extra info of all our parameters

    updateExtraInfos();

    // Expand all our properties

    expandAll();
}

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

void SingleCellViewInformationParametersWidget::populateContextMenu(CellMLSupport::CellmlFileRuntime *pRuntime)
{
    // Create our two main menu items

    QAction *voiAction = mVoiAccessible?mContextMenu->addAction(QString()):0;
    QMenu *plotAgainstMenu = new QMenu(mContextMenu);

    mContextMenu->addAction(plotAgainstMenu->menuAction());

    // Initialise our two main menu items

    retranslateContextMenu();

    // Create a connection to handle the graph requirement against our variable
    // of integration, and keep track of the parameter associated with our first
    // main menu item

    if (mVoiAccessible) {
        connect(voiAction, SIGNAL(triggered(bool)),
                this, SLOT(emitGraphRequired()));

        mParameterActions.insert(voiAction, pRuntime->variableOfIntegration());
    }

    // Populate our context menu with the parameters

    QString componentHierarchy = QString();
    QMenu *componentMenu = 0;

    foreach (CellMLSupport::CellmlFileRuntimeParameter *parameter, pRuntime->parameters()) {
        // Check whether the current parameter is in the same component
        // hierarchy as the previous one

        QString crtComponentHierarchy = parameter->formattedComponentHierarchy();

        if (crtComponentHierarchy.compare(componentHierarchy)) {
            // The current parameter is in a different component hierarchy, so
            // create a new menu hierarchy for our 'new' component, reusing
            // existing menus, whenever possible

            QMenu *menu = plotAgainstMenu;

            foreach (const QString &component, parameter->componentHierarchy()) {
                // Check whether we already have a menu for our current
                // component

                componentMenu = 0;

                foreach (QObject *object, menu->children()) {
                    QMenu *subMenu = qobject_cast<QMenu *>(object);

                    if (    subMenu
                        && !subMenu->menuAction()->text().compare(component)) {
                        componentMenu = subMenu;

                        break;
                    }
                }

                // Create a new menu for our current component, if none could be
                // found

                if (!componentMenu) {
                    componentMenu = new QMenu(component, menu);

                    menu->addMenu(componentMenu);
                }

                // Get ready for the next component in our component hierarchy

                menu = componentMenu;
            }

            // Keep track of the new component hierarchy

            componentHierarchy = crtComponentHierarchy;
        }

        // Make sure that we have a 'current' component menu
        // Note: this should never happen, but we never know...

        if (!componentMenu)
            continue;

        // Add the current parameter to the 'current' component menu

        QAction *parameterAction = componentMenu->addAction(SingleCellViewSimulationWidget::parameterIcon(parameter->type()),
                                                            parameter->formattedName());

        // Create a connection to handle the graph requirement against our
        // parameter

        connect(parameterAction, SIGNAL(triggered(bool)),
                this, SLOT(emitGraphRequired()));

        // Keep track of the parameter associated with our model parameter
        // action

        mParameterActions.insert(parameterAction, parameter);
    }
}

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

void SingleCellViewInformationParametersWidget::updateExtraInfos()
{
    // Update the extra info of all our properties

    foreach (Core::Property *property, properties()) {
        CellMLSupport::CellmlFileRuntimeParameter *parameter = mParameters.value(property);

        if (parameter) {
            QString parameterType = QString();

            switch (parameter->type()) {
            case CellMLSupport::CellmlFileRuntimeParameter::Voi:
                parameterType = tr("variable of integration");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Constant:
                parameterType = tr("constant");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::ComputedConstant:
                parameterType = tr("computed constant");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Rate:
                parameterType = tr("rate");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::State:
                parameterType = tr("state");

                break;
            case CellMLSupport::CellmlFileRuntimeParameter::Algebraic:
                parameterType = tr("algebraic");

                break;
            default:
                // Not a relevant type, so do nothing

                ;
            }

            property->setExtraInfo(parameterType);
        }
    }
}

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

void SingleCellViewInformationParametersWidget::propertyEditorContextMenu(const QPoint &pPosition) const
{
    Q_UNUSED(pPosition);

    // Make sure that we have a current property

    Core::Property *crtProperty = currentProperty();

    if (!crtProperty)
        return;

    // Make sure that our current property is not a section

    if (crtProperty->type() == Core::Property::Section)
        return;

    // Generate and show the context menu

    mContextMenu->exec(QCursor::pos());
}

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

void SingleCellViewInformationParametersWidget::emitGraphRequired()
{
    // Let people know that we want to plot the current parameter against
    // another

    emit graphRequired(mParameterActions.value(qobject_cast<QAction *>(sender())),
                       mParameters.value(currentProperty()));
}

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

}   // namespace SingleCellView
}   // namespace OpenCOR

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


<commit_before>/*
 * 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.
 *
 * Written (W) 2011-2012 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 * Written (W) 2012 Victor Sadkov
 * Copyright (C) 2011 Moscow State University
 */

#include <shogun/base/init.h>
#include <shogun/mathematics/Statistics.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

void test_confidence_intervals()
{
	int32_t data_size=100;
	SGVector<float64_t> data(data_size);

	CMath::random_vector(data.vector, data.vlen, 0.0, 1.0);

	float64_t low, up, mean;
	float64_t error_prob=0.1;
	mean=CStatistics::confidence_intervals_mean(data, error_prob, low, up);

	SG_SPRINT("sample mean: %f. True mean lies in [%f,%f] with %f%%\n",
			mean, low, up, 100*(1-error_prob));

	SG_SPRINT("variance: %f\n", CStatistics::variance(data));
	SG_SPRINT("deviation: %f\n", CStatistics::std_deviation(data));
}

void test_inverse_incomplete_gamma()
{
	/* some tests for high precision MATLAB comparison */
	float64_t difference=CStatistics::inverse_incomplete_gamma(1, 1-0.95)*2;
	difference-=5.991464547107981;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-15);

	difference=CStatistics::inverse_incomplete_gamma(0.3, 1-0.95)*3;
	difference-=4.117049832302619;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-14)

	difference=CStatistics::inverse_incomplete_gamma(2, 1-0.95)*0.1;
	difference-=0.474386451839058;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-15)
}

int main(int argc, char **argv)
{
	init_shogun_with_defaults();

	test_confidence_intervals();
	test_inverse_incomplete_gamma();

	exit_shogun();

	return 0;
}

<commit_msg>added tests for gamma cdf and minor changes<commit_after>/*
 * 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.
 *
 * Written (W) 2011-2012 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 * Written (W) 2012 Victor Sadkov
 * Copyright (C) 2011 Moscow State University
 */

#include <shogun/base/init.h>
#include <shogun/mathematics/Statistics.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

void test_confidence_intervals()
{
	int32_t data_size=100;
	SGVector<float64_t> data(data_size);
	data.range_fill();

	float64_t low, up, mean;
	float64_t error_prob=0.1;
	mean=CStatistics::confidence_intervals_mean(data, error_prob, low, up);

	SG_SPRINT("sample mean: %f. True mean lies in [%f,%f] with %f%%\n",
			mean, low, up, 100*(1-error_prob));

	SG_SPRINT("variance: %f\n", CStatistics::variance(data));
	SG_SPRINT("deviation: %f\n", CStatistics::std_deviation(data));
}

void test_inverse_student_t()
{
	/* some tests for high precision MATLAB comparison */
	float64_t difference=CStatistics::inverse_student_t(1, 0.99);
	SG_SPRINT("inverse_student_t(0.99, 1)=%f\n", difference);
	difference-=31.820515953773953;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-14);

	difference=CStatistics::inverse_student_t(2, 0.99);
	SG_SPRINT("inverse_student_t(0.99, 2)=%f\n", difference);
	difference-= 6.964556734283233;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-14);

	difference=CStatistics::inverse_student_t(3, 0.99);
	SG_SPRINT("inverse_student_t(0.99, 3)=%f\n", difference);
	difference-=4.540702858568132;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-20);

	difference=CStatistics::inverse_student_t(4, 0.99);
	SG_SPRINT("inverse_student_t(0.99, 4)=%f\n", difference);
	difference-=3.746947387979196;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-20);
}

void test_incomplete_gamma()
{
	/* some tests for high precision MATLAB comparison */
	float64_t difference=CStatistics::incomplete_gamma(2, 1);
	SG_SPRINT("incomplete_gamma(1, 2)=%f\n", difference);
	difference-= 0.264241117657115;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-16);

	difference=CStatistics::incomplete_gamma(3, 2);
	SG_SPRINT("incomplete_gamma(3, 2)=%f\n", difference);
	difference-= 0.323323583816937;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-16);

	difference=CStatistics::incomplete_gamma(1, 0.1);
	SG_SPRINT("incomplete_gamma(1, 0.1)=%f\n", difference);
	difference-=0.095162581964040;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-16);
}

void test_gamma_cdf()
{
	/* some tests for high precision MATLAB comparison */
	float64_t difference=CStatistics::gamma_cdf(0.95, 1, 2);
	SG_SPRINT("gamma_cdf(0.95, 1, 2)=%f\n", difference);
	difference-=0.378114943534980;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-16);

	difference=CStatistics::gamma_cdf(0.95, 2, 2);
	SG_SPRINT("gamma_cdf(0.95, 2, 2)=%f\n", difference);
	difference-= 0.082719541714095;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-15);

	difference=CStatistics::gamma_cdf(1, 1, 1);
	SG_SPRINT("gamma_cdf(1, 1, 1)=%f\n", difference);
	difference-= 0.632120558828558;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-15);

	difference=CStatistics::gamma_cdf(0.95, 0.9, 1.1);
	SG_SPRINT("gamma_cdf(0.95, 0.9, 1.1=%f\n", difference);
	difference-= 0.624727614394445;
	difference=CMath::abs(difference);
	ASSERT(difference<=10E-15);
}

int main(int argc, char **argv)
{
	init_shogun_with_defaults();

	test_confidence_intervals();
	test_inverse_student_t();
	test_incomplete_gamma();
	test_gamma_cdf();

	exit_shogun();

	return 0;
}

<|endoftext|>


<commit_before>#include "TestFixtures.h"
#include "ECSE/EntityManager.h"

class EntityManagerTest : public ::testing::Test
{
public:
    ECSE::EntityManager manager;
};

TEST_F(EntityManagerTest, TestEmpty)
{
    ASSERT_TRUE(manager.getEntities().empty()) << "No entities should be returned";
}

TEST_F(EntityManagerTest, TestCreateEntity)
{
    ECSE::Entity::ID eID = manager.createEntity();
    ASSERT_NE(ECSE::Entity::invalidID, eID) << "Entity should have a valid ID";
}

TEST_F(EntityManagerTest, TestGetEntity)
{
    ECSE::Entity::ID eID = manager.createEntity();

    ASSERT_NE(nullptr, manager.getEntity(eID)) << "Entity should have a valid pointer";
}

TEST_F(EntityManagerTest, TestDestroyEntity)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    manager.destroyEntity(eID);

    ASSERT_EQ(2, manager.getEntities().size()) << "One entity should have been removed";
}

TEST_F(EntityManagerTest, TestDestroyEntityByPointer)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    ECSE::Entity* ptr = manager.getEntity(eID);
    manager.destroyEntity(ptr);

    ASSERT_EQ(2, manager.getEntities().size()) << "One entity should have been removed";
}

TEST_F(EntityManagerTest, TestGetEntities)
{
    std::vector<ECSE::Entity*> added;
    for (size_t i = 0; i < 5; ++i)
    {
        ECSE::Entity::ID eID = manager.createEntity();
        added.push_back(manager.getEntity(eID));
    }

    auto entities = manager.getEntities();
    for (ECSE::Entity* e : added)
    {
        ASSERT_TRUE(std::find(entities.begin(), entities.end(), e) != entities.end()) << "Entity should have been in vector";
    }

    for (ECSE::Entity* e : entities)
    {
        ASSERT_TRUE(std::find(added.begin(), added.end(), e) != added.end()) << "Entity was not added, but is in vector anyway";
    }
}<commit_msg>Added allocation tests<commit_after>#include "TestFixtures.h"
#include "ECSE/EntityManager.h"

class EntityManagerTest : public ::testing::Test
{
public:
    ECSE::EntityManager manager;
};

TEST_F(EntityManagerTest, TestEmpty)
{
    ASSERT_TRUE(manager.getEntities().empty()) << "No entities should be returned";
}

TEST_F(EntityManagerTest, TestCreateEntity)
{
    ECSE::Entity::ID eID = manager.createEntity();
    ASSERT_NE(ECSE::Entity::invalidID, eID) << "Entity should have a valid ID";
}

TEST_F(EntityManagerTest, TestGetEntity)
{
    ECSE::Entity::ID eID = manager.createEntity();

    ASSERT_NE(nullptr, manager.getEntity(eID)) << "Entity should have a valid pointer";
}

TEST_F(EntityManagerTest, TestDestroyEntity)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    manager.destroyEntity(eID);

    ASSERT_EQ(2, manager.getEntities().size()) << "One entity should have been removed";
}

TEST_F(EntityManagerTest, TestDestroyEntityByPointer)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    ECSE::Entity* ptr = manager.getEntity(eID);
    manager.destroyEntity(ptr);

    ASSERT_EQ(2, manager.getEntities().size()) << "One entity should have been removed";
}

TEST_F(EntityManagerTest, TestGetEntities)
{
    std::vector<ECSE::Entity*> added;
    for (size_t i = 0; i < 5; ++i)
    {
        ECSE::Entity::ID eID = manager.createEntity();
        added.push_back(manager.getEntity(eID));
    }

    auto entities = manager.getEntities();
    for (ECSE::Entity* e : added)
    {
        ASSERT_TRUE(std::find(entities.begin(), entities.end(), e) != entities.end()) << "Entity should have been in vector";
    }

    for (ECSE::Entity* e : entities)
    {
        ASSERT_TRUE(std::find(added.begin(), added.end(), e) != added.end()) << "Entity was not added, but is in vector anyway";
    }
}

TEST_F(EntityManagerTest, TestNewID)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    manager.destroyEntity(eID);

    ECSE::Entity::ID newID = manager.createEntity();

    ASSERT_NE(eID, newID) << "Entity limit not exceeded, so fresh IDs should be used";
}

TEST_F(EntityManagerTest, TestReplaceMemory)
{
    manager.createEntity();
    ECSE::Entity::ID eID = manager.createEntity();
    manager.createEntity();

    ECSE::Entity* entityA = manager.getEntity(eID);

    manager.destroyEntity(eID);

    ECSE::Entity::ID newID = manager.createEntity();
    ECSE::Entity* entityB = manager.getEntity(newID);

    ASSERT_EQ(entityA, entityB) << "Entities should backfill unused memory";
}<|endoftext|>


<commit_before>#ifndef BLUETOE_BINDINGS_NRF_HPP
#define BLUETOE_BINDINGS_NRF_HPP

#include <bluetoe/meta_types.hpp>
#include <bluetoe/default_pdu_layout.hpp>

#include <nrf.h>

namespace bluetoe
{
    namespace nrf52_details {
        void gpio_debug_hfxo_stopped();
    }

    /**
     * @brief namespace with nRF51/52 specific configuration options
     */
    namespace nrf
    {
        /*
         * Some aliases that can be used in the debugger
         */
        static NRF_RADIO_Type* const        nrf_radio            = NRF_RADIO;
        static NRF_TIMER_Type* const        nrf_timer            = NRF_TIMER0;
        static NRF_CLOCK_Type* const        nrf_clock            = NRF_CLOCK;
        static NRF_RTC_Type* const          nrf_rtc              = NRF_RTC0;
        static NRF_CCM_Type* const          nrf_ccm              = NRF_CCM;
        static NRF_AAR_Type* const          nrf_aar              = NRF_AAR;
        static NRF_PPI_Type* const          nrf_ppi              = NRF_PPI;
        static NRF_RNG_Type* const          nrf_random           = NRF_RNG;
        static NRF_ECB_Type* const          nrf_aes              = NRF_ECB;
        static NRF_GPIOTE_Type* const       nrf_gpiote           = NRF_GPIOTE;
        static NVIC_Type* const             nvic                 = NVIC;

        namespace nrf_details {
            struct radio_option_meta_type : ::bluetoe::details::binding_option_meta_type {};
            struct sleep_clock_source_meta_type : radio_option_meta_type {};

            static void start_high_frequency_clock()
            {
                // This tasks starts the high frequency crystal oscillator (HFXO)
                nrf_clock->TASKS_HFCLKSTART = 1;

                // TODO: do not wait busy
                // Issue: do not poll for readiness of the high frequency clock #63
                while ( !nrf_clock->EVENTS_HFCLKSTARTED )
                    ;

                nrf_clock->EVENTS_HFCLKSTARTED = 0;
            }

            inline void start_lfclock_and_rtc()
            {
                nrf_clock->EVENTS_LFCLKSTARTED = 0;
                nrf_clock->TASKS_LFCLKSTART = 1;

                while ( nrf_clock->EVENTS_LFCLKSTARTED == 0 )
                    ;

                // https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev3/ERR/nRF52840/Rev3/latest/anomaly_840_20.html#anomaly_840_20
                nrf_rtc->TASKS_STOP = 0;
                nrf_rtc->TASKS_START = 1;

                // Configure the RTC to generate these two events
                // Overflow flag does not harm the power performance much and is used for
                // debugging.
                nrf_rtc->EVTEN =
                    ( RTC_EVTEN_COMPARE0_Enabled << RTC_EVTEN_COMPARE0_Pos )
                  | ( RTC_EVTEN_COMPARE1_Enabled << RTC_EVTEN_COMPARE1_Pos )
                  | ( RTC_EVTEN_OVRFLW_Enabled << RTC_EVTEN_OVRFLW_Pos );
            }
        }

        /**
         * @brief configure the low frequency clock to be sourced out of the high frequency clock
         *
         * The resulting sleep clock accurary is then the accuarcy of your high frequency clock source.
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator
         * @sa bluetoe::nrf::calibrated_sleep_clock
         *
         * TODO: With this configuration, the HFXO must not be stopped.
         */
        struct synthesized_sleep_clock
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Synth << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();
            }

            static void stop_high_frequency_crystal_oscilator()
            {
            }
            /** @endcond */
        };

        /**
         * @brief configure the low frequency clock to be sourced from a crystal oscilator
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::synthesized_sleep_clock
         * @sa bluetoe::nrf::calibrated_sleep_clock
         */
        struct sleep_clock_crystal_oscillator
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Xtal << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();
            }

            static void stop_high_frequency_crystal_oscilator()
            {
                nrf_clock->TASKS_HFCLKSTOP = 1;

#               if defined BLUETOE_NRF52_RADIO_DEBUG
                    bluetoe::nrf52_details::gpio_debug_hfxo_stopped();
#               endif

            }
            /** @endcond */
        };

        /**
         * @brief configure the low frequency clock to run from the RC oscilator.
         *
         * That low frequency RC oscilator will be calibrated by the high frequency
         * crystal oscilator periodically.
         *
         * According to the datasheet, the resulting sleep clock accuarcy is then 500ppm.
         * If no sleep clock configuration is given, this is the default.
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::synthesized_sleep_clock
         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator
         */
        struct calibrated_sleep_clock
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_RC << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();

                nrf_clock->EVENTS_DONE = 0;
                nrf_clock->TASKS_CAL = 1;

                // TODO
                while ( !nrf_clock->EVENTS_DONE )
                    ;

            }

            static void stop_high_frequency_crystal_oscilator()
            {
                // TODO
                nrf_clock->TASKS_HFCLKSTOP = 1;
            }
            /** @endcond */
        };
    }

    namespace nrf_details
    {
        struct encrypted_pdu_layout : bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >
        {
            /** @cond HIDDEN_SYMBOLS */
            static constexpr std::size_t header_size = sizeof( std::uint16_t );

            using bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >::header;

            static std::uint16_t header( const std::uint8_t* pdu )
            {
                return ::bluetoe::details::read_16bit( pdu );
            }

            static void header( std::uint8_t* pdu, std::uint16_t header_value )
            {
                ::bluetoe::details::write_16bit( pdu, header_value );
            }

            static std::pair< std::uint8_t*, std::uint8_t* > body( const link_layer::read_buffer& pdu )
            {
                assert( pdu.size >= header_size );

                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };
            }

            static std::pair< const std::uint8_t*, const std::uint8_t* > body( const link_layer::write_buffer& pdu )
            {
                assert( pdu.size >= header_size );

                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };
            }

            static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )
            {
                return header_size + payload_size + 1;
            }
            /** @endcond */
        };
    }
}

#endif

<commit_msg>missed nrf.hpp header<commit_after>#ifndef BLUETOE_BINDINGS_NRF_HPP
#define BLUETOE_BINDINGS_NRF_HPP

#include <bluetoe/meta_types.hpp>
#include <bluetoe/default_pdu_layout.hpp>

#include <nrf.h>

namespace bluetoe
{
    namespace nrf52_details {
        void gpio_debug_hfxo_stopped();
        void init_calibration_timer();
        void deassign_hfxo();
    }

    /**
     * @brief namespace with nRF51/52 specific configuration options
     */
    namespace nrf
    {
        /*
         * Some aliases that can be used in the debugger
         */
        static NRF_RADIO_Type* const        nrf_radio            = NRF_RADIO;
        static NRF_TIMER_Type* const        nrf_timer            = NRF_TIMER0;
        static NRF_CLOCK_Type* const        nrf_clock            = NRF_CLOCK;
        static NRF_RTC_Type* const          nrf_rtc              = NRF_RTC0;
        static NRF_CCM_Type* const          nrf_ccm              = NRF_CCM;
        static NRF_AAR_Type* const          nrf_aar              = NRF_AAR;
        static NRF_PPI_Type* const          nrf_ppi              = NRF_PPI;
        static NRF_RNG_Type* const          nrf_random           = NRF_RNG;
        static NRF_ECB_Type* const          nrf_aes              = NRF_ECB;
        static NRF_GPIOTE_Type* const       nrf_gpiote           = NRF_GPIOTE;
        static NVIC_Type* const             nvic                 = NVIC;

        namespace nrf_details {
            struct radio_option_meta_type : ::bluetoe::details::binding_option_meta_type {};
            struct sleep_clock_source_meta_type : radio_option_meta_type {};

            static void start_high_frequency_clock()
            {
                // This tasks starts the high frequency crystal oscillator (HFXO)
                nrf_clock->TASKS_HFCLKSTART = 1;

                // TODO: do not wait busy
                // Issue: do not poll for readiness of the high frequency clock #63
                while ( !nrf_clock->EVENTS_HFCLKSTARTED )
                    ;

                nrf_clock->EVENTS_HFCLKSTARTED = 0;
            }

            inline void start_lfclock_and_rtc()
            {
                nrf_clock->EVENTS_LFCLKSTARTED = 0;
                nrf_clock->TASKS_LFCLKSTART = 1;

                while ( nrf_clock->EVENTS_LFCLKSTARTED == 0 )
                    ;

                // https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev3/ERR/nRF52840/Rev3/latest/anomaly_840_20.html#anomaly_840_20
                nrf_rtc->TASKS_STOP = 0;
                nrf_rtc->TASKS_START = 1;

                // Configure the RTC to generate these two events
                // Overflow flag does not harm the power performance much and is used for
                // debugging.
                nrf_rtc->EVTEN =
                    ( RTC_EVTEN_COMPARE0_Enabled << RTC_EVTEN_COMPARE0_Pos )
                  | ( RTC_EVTEN_COMPARE1_Enabled << RTC_EVTEN_COMPARE1_Pos )
                  | ( RTC_EVTEN_OVRFLW_Enabled << RTC_EVTEN_OVRFLW_Pos );
            }
        }

        /**
         * @brief configure the low frequency clock to be sourced out of the high frequency clock
         *
         * The resulting sleep clock accurary is then the accuarcy of your high frequency clock source.
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator
         * @sa bluetoe::nrf::calibrated_rc_sleep_clock
         *
         * TODO: With this configuration, the HFXO must not be stopped.
         */
        struct synthesized_sleep_clock
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Synth << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();
            }

            static void stop_high_frequency_crystal_oscilator()
            {
            }
            /** @endcond */
        };

        /**
         * @brief configure the low frequency clock to be sourced from a crystal oscilator
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::synthesized_sleep_clock
         * @sa bluetoe::nrf::calibrated_rc_sleep_clock
         */
        struct sleep_clock_crystal_oscillator
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Xtal << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();
            }

            static void stop_high_frequency_crystal_oscilator()
            {
                nrf_clock->TASKS_HFCLKSTOP = 1;

#               if defined BLUETOE_NRF52_RADIO_DEBUG
                    bluetoe::nrf52_details::gpio_debug_hfxo_stopped();
#               endif

            }
            /** @endcond */
        };

        /**
         * @brief configure the low frequency clock to run from the RC oscilator.
         *
         * That low frequency RC oscilator will be calibrated by the high frequency
         * crystal oscilator periodically.
         *
         * According to the datasheet, the resulting sleep clock accuarcy is then 500ppm.
         * If no sleep clock configuration is given, this is the default.
         *
         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm
         * @sa bluetoe::nrf::synthesized_sleep_clock
         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator
         */
        struct calibrated_rc_sleep_clock
        {
            /** @cond HIDDEN_SYMBOLS */
            using meta_type = nrf_details::sleep_clock_source_meta_type;

            static void start_clocks()
            {
                nrf_details::start_high_frequency_clock();

                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_RC << CLOCK_LFCLKSRCCOPY_SRC_Pos;
                nrf_details::start_lfclock_and_rtc();
                nrf52_details::init_calibration_timer();
            }

            static void stop_high_frequency_crystal_oscilator()
            {
                nrf52_details::deassign_hfxo();
            }
            /** @endcond */
        };
    }

    namespace nrf_details
    {
        struct encrypted_pdu_layout : bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >
        {
            /** @cond HIDDEN_SYMBOLS */
            static constexpr std::size_t header_size = sizeof( std::uint16_t );

            using bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >::header;

            static std::uint16_t header( const std::uint8_t* pdu )
            {
                return ::bluetoe::details::read_16bit( pdu );
            }

            static void header( std::uint8_t* pdu, std::uint16_t header_value )
            {
                ::bluetoe::details::write_16bit( pdu, header_value );
            }

            static std::pair< std::uint8_t*, std::uint8_t* > body( const link_layer::read_buffer& pdu )
            {
                assert( pdu.size >= header_size );

                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };
            }

            static std::pair< const std::uint8_t*, const std::uint8_t* > body( const link_layer::write_buffer& pdu )
            {
                assert( pdu.size >= header_size );

                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };
            }

            static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )
            {
                return header_size + payload_size + 1;
            }
            /** @endcond */
        };
    }
}

#endif

<|endoftext|>


<commit_before>#ifndef ITKIMAGEEXPORTER_HPP_
#define ITKIMAGEEXPORTER_HPP_

#include "ProcessObject.hpp"
#include "Image2D.hpp"

#include <itkImageSource.h>
#include <itkImageRegionIterator.h>

namespace fast {

template<class TImage>
class ITKImageExporter: public itk::ImageSource<TImage>, public ProcessObject {
    public:
        /** Standard class typedefs. */
        typedef ITKImageExporter Self;
        typedef itk::ImageSource<TImage> Superclass;
        typedef itk::SmartPointer<Self> Pointer;

        /** Method for creation through the object factory. */
        itkNewMacro(Self);

        /** Run-time type information (and related methods). */
        itkTypeMacro(MyImageSource, ImageSource);
        void SetInput(Image2D::pointer image);
    private:
        Image2D::pointer mInput;

        ITKImageExporter();
        void execute() {};

        // Is called by ITK
        void GenerateData();

};

} // end namespace fast

template<class TImage>
inline void fast::ITKImageExporter<TImage>::SetInput(Image2D::pointer image) {
    mInput = image;
}

template<class TImage>
inline fast::ITKImageExporter<TImage>::ITKImageExporter() {
}

template<class TImage>
inline void fast::ITKImageExporter<TImage>::GenerateData() {
    typename TImage::Pointer output = this->GetOutput();
    typename TImage::RegionType region;
    typename TImage::IndexType start;
    start[0] = 0;
    start[1] = 0;

    typename TImage::SizeType size;
    size[0] = mInput->getWidth();
    size[1] = mInput->getHeight();

    region.SetSize(size);
    region.SetIndex(start);

    output->SetRegions(region);
    output->Allocate();

    // TODO support different data types
    mInput->update();
    ImageAccess2D access = mInput->getImageAccess(ACCESS_READ);
    float * fastPixelData = (float *) access.get();

    itk::ImageRegionIterator<TImage> imageIterator(output,
            output->GetLargestPossibleRegion());
    unsigned int width = mInput->getWidth();

    while (!imageIterator.IsAtEnd()) {
        unsigned int x = imageIterator.GetIndex()[0];
        unsigned int y = imageIterator.GetIndex()[1];
        //unsigned int z = imageIterator.GetIndex()[2];
        imageIterator.Set(fastPixelData[x + y * width]);

        ++imageIterator;
    }
}

#endif // ITKIMAGEEXPORTER_HPP_
<commit_msg>moved update call in ITKImageExporter<commit_after>#ifndef ITKIMAGEEXPORTER_HPP_
#define ITKIMAGEEXPORTER_HPP_

#include "ProcessObject.hpp"
#include "Image2D.hpp"

#include <itkImageSource.h>
#include <itkImageRegionIterator.h>

namespace fast {

template<class TImage>
class ITKImageExporter: public itk::ImageSource<TImage>, public ProcessObject {
    public:
        /** Standard class typedefs. */
        typedef ITKImageExporter Self;
        typedef itk::ImageSource<TImage> Superclass;
        typedef itk::SmartPointer<Self> Pointer;

        /** Method for creation through the object factory. */
        itkNewMacro(Self);

        /** Run-time type information (and related methods). */
        itkTypeMacro(MyImageSource, ImageSource);
        void SetInput(Image2D::pointer image);
    private:
        Image2D::pointer mInput;

        ITKImageExporter();
        void execute() {};

        // Is called by ITK
        void GenerateData();

};

} // end namespace fast

template<class TImage>
inline void fast::ITKImageExporter<TImage>::SetInput(Image2D::pointer image) {
    mInput = image;
}

template<class TImage>
inline fast::ITKImageExporter<TImage>::ITKImageExporter() {
}

template<class TImage>
inline void fast::ITKImageExporter<TImage>::GenerateData() {
    mInput->update();
    typename TImage::Pointer output = this->GetOutput();
    typename TImage::RegionType region;
    typename TImage::IndexType start;
    start[0] = 0;
    start[1] = 0;

    typename TImage::SizeType size;
    size[0] = mInput->getWidth();
    size[1] = mInput->getHeight();

    region.SetSize(size);
    region.SetIndex(start);

    output->SetRegions(region);
    output->Allocate();

    // TODO support different data types
    ImageAccess2D access = mInput->getImageAccess(ACCESS_READ);
    float * fastPixelData = (float *) access.get();

    itk::ImageRegionIterator<TImage> imageIterator(output,
            output->GetLargestPossibleRegion());
    unsigned int width = mInput->getWidth();

    while (!imageIterator.IsAtEnd()) {
        unsigned int x = imageIterator.GetIndex()[0];
        unsigned int y = imageIterator.GetIndex()[1];
        //unsigned int z = imageIterator.GetIndex()[2];
        imageIterator.Set(fastPixelData[x + y * width]);

        ++imageIterator;
    }
}

#endif // ITKIMAGEEXPORTER_HPP_
<|endoftext|>