WMIsoLines.cpp 9.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

#include <string>

#include <osg/Geometry>

29
#include "core/common/WItemSelectionItemTyped.h"
30 31 32 33 34 35 36 37
#include "core/dataHandler/WDataSetScalar.h"
#include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h"
#include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/WGEGeodeUtils.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/kernel/WKernel.h"
#include "core/kernel/WModuleInputData.h"
38
#include "WMIsoLines.xpm"
39 40 41
#include "WMIsoLines.h"

WMIsoLines::WMIsoLines():
42
    WMAbstractSliceModule(),
43
    m_first( true )
44 45 46 47 48 49 50 51 52 53 54 55 56 57
{
}

WMIsoLines::~WMIsoLines()
{
}

boost::shared_ptr< WModule > WMIsoLines::factory() const
{
    return boost::shared_ptr< WModule >( new WMIsoLines() );
}

const char** WMIsoLines::getXPMIcon() const
{
58
    return WMIsoLines_xpm;
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
}
const std::string WMIsoLines::getName() const
{
    return "Isoline";
}

const std::string WMIsoLines::getDescription() const
{
    return "Renders isolines in a specific color.";
}

void WMIsoLines::connectors()
{
    m_scalarIC = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(), "scalarData", "Scalar data." );

74
    WMAbstractSliceModule::connectors();
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
}

void WMIsoLines::properties()
{
    m_isovalue = m_properties->addProperty( "Isovalue", "Value selecting the contours", 0.0 );
    m_isovalue->setMin( 0.0 );
    m_isovalue->setMax( 0.0 ); // make it unusable at first

    m_color = m_properties->addProperty( "Line color", "The color for the isoline", WColor( 0.0, 0.0, 0.0, 1.0 ) );
    m_resolution = m_properties->addProperty( "Resolution", "Quad size used for generating line segments", 1.0, m_propCondition );
    m_resolution->setMin( 0.01 );
    m_resolution->setMax( 10.0 );

    m_lineWidth = m_properties->addProperty( "Line Width", "The width of the isoline.", 0.1 );
    m_lineWidth->setMin( 0.0 );
    m_lineWidth->setMax( 1.0 );

92
    WMAbstractSliceModule::properties();
93 94 95 96 97 98 99 100 101 102
}

namespace
{
    osg::ref_ptr< osg::Geode > genQuadsPerCell( osg::Vec3 const& base, osg::Vec3 const& a, osg::Vec3 const& b,
            boost::shared_ptr< WDataSetScalar > data, const double resolution )
    {
        size_t maxA = a.length() / resolution;
        size_t maxB = b.length() / resolution;
        // the stuff needed by the OSG to create a geometry instance
103 104 105
        osg::ref_ptr< osg::Vec3Array > vertices = new osg::Vec3Array;
        osg::ref_ptr< osg::Vec3Array > texcoords0 = new osg::Vec3Array;
        osg::ref_ptr< osg::Vec3Array > texcoords1 = new osg::Vec3Array;
106 107 108 109 110 111 112 113 114 115
        osg::ref_ptr< osg::Vec3Array > normals = new osg::Vec3Array;
        osg::ref_ptr< osg::Vec4Array > colors = new osg::Vec4Array;

        osg::Vec3 aCrossB = a ^ b;
        aCrossB.normalize();
        osg::Vec3 aNorm = a;
        aNorm.normalize();
        osg::Vec3 bNorm = b;
        bNorm.normalize();

116
        boost::shared_ptr< WGridRegular3D > grid = boost::dynamic_pointer_cast< WGridRegular3D >( data->getGrid() );
117 118 119 120 121 122 123 124 125 126

        if( grid )
        {
            for( size_t i = 0; i < maxA; ++i )
            {
                for( size_t j = 0; j < maxB; ++j )
                {
                    for( int k = 0; k < 4; ++k )
                    {
                        vertices->push_back( base + aNorm * i * resolution + bNorm * j * resolution );
127 128
                        normals->push_back( aCrossB );
                        colors->push_back( osg::Vec4( 1.0, 1.0, 1.0, 1.0 ) );
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
                    }

                    texcoords0->push_back( ( -aNorm + -bNorm ) * 0.5 * resolution );
                    texcoords0->push_back( (  aNorm + -bNorm ) * 0.5 * resolution );
                    texcoords0->push_back( (  aNorm +  bNorm ) * 0.5 * resolution );
                    texcoords0->push_back( ( -aNorm +  bNorm ) * 0.5 * resolution );

                    texcoords1->push_back( osg::Vec3( 0.0, 0.0, 0.0 ) );
                    texcoords1->push_back( osg::Vec3( 1.0, 0.0, 0.0 ) );
                    texcoords1->push_back( osg::Vec3( 1.0, 1.0, 0.0 ) );
                    texcoords1->push_back( osg::Vec3( 0.0, 1.0, 0.0 ) );
                }
            }
        }


        // put it all together
        osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry();
        geometry->setVertexArray( vertices );
        geometry->setTexCoordArray( 0, texcoords0 );
        geometry->setTexCoordArray( 1, texcoords1 );
        geometry->setNormalArray( normals );
        geometry->setColorArray( colors );
152 153
        geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
        geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
154 155 156 157 158 159 160 161
        geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, vertices->size() ) );

        osg::ref_ptr< osg::Geode > geode = new osg::Geode();
        geode->addDrawable( geometry );
        return geode;
    }
}

162
void WMIsoLines::initOSG( boost::shared_ptr< WDataSetScalar > scalars, const double resolution, const size_t axis )
163 164 165 166 167 168 169 170 171 172 173
{
    debugLog() << "Init OSG";
    m_output->clear();

    // grab the current bounding box for computing the size of the slice
    WBoundingBox bb = scalars->getGrid()->getBoundingBox();
    WVector3d minV = bb.getMin();
    WVector3d maxV = bb.getMax();
    WVector3d sizes = ( maxV - minV );
    WVector3d midBB = minV + ( sizes * 0.5 );

174 175 176 177 178 179 180
    if( axis > 2 )
    {
        errorLog() << "Somehow an axis >= 2 was given (" << axis << "). This is a bug! Please report at openwalnut.org. Aborting.";
        return;
    }

    // determine other two plane vectors
181 182
    osg::Vec3 aVec( sliceBaseVectors( sizes, axis ).first );
    osg::Vec3 bVec( sliceBaseVectors( sizes, axis ).second );
183 184 185 186

    m_pos->setMin( minV[axis] );
    m_pos->setMax( maxV[axis] );

187
    if( m_first )
188 189 190 191
    {
        m_first = false;
        m_pos->set( midBB[axis] );
    }
192

193
    osg::ref_ptr< osg::Uniform > u_WorldTransform = new osg::Uniform( "u_WorldTransform", osg::Matrixf::identity() );
194 195 196 197 198 199 200
    wge::bindAsUniform( m_output, u_WorldTransform, "u_WorldTransform" );
    wge::bindAsUniform( m_output, m_isovalue, "u_isovalue" );
    wge::bindAsUniform( m_output, m_lineWidth, "u_lineWidth" );
    wge::bindAsUniform( m_output, m_color, "u_color" );
    wge::bindAsUniform( m_output, aVec, "u_aVec" );
    wge::bindAsUniform( m_output, bVec, "u_bVec" );
    wge::bindAsUniform( m_output, resolution, "u_resolution" );
201

202 203 204 205 206 207
    // each slice is child of an transformation node
    osg::ref_ptr< osg::MatrixTransform > mT = new osg::MatrixTransform();
    osg::ref_ptr< osg::Node > slice = genQuadsPerCell( minV, aVec, bVec, scalars, resolution );
    slice->setCullingActive( false );
    mT->addChild( slice );

208 209
    // Control transformation node by properties. We use an additional uniform here to provide the shader
    // the transformation matrix used to translate the slice.
210 211 212
    osg::Vec3 planeNormal( 0.0, 0.0, 0.0 );
    planeNormal[axis] = 1.0;
    mT->addUpdateCallback( new WGELinearTranslationCallback< WPropDouble >( planeNormal, m_pos, u_WorldTransform ) );
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

    m_output->getOrCreateStateSet()->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
    m_output->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON );
    m_output->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
    m_output->insert( mT );
    m_output->dirtyBound();
}

void WMIsoLines::moduleMain()
{
    // get notified about data changes
    m_moduleState.setResetable( true, true );
    m_moduleState.add( m_scalarIC->getDataChangedCondition() );
    m_moduleState.add( m_propCondition );

    ready();

    // graphics setup
    m_output = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_output );
    osg::ref_ptr< WGEShader > shader = new WGEShader( "WIsolines", m_localPath );
    shader->apply( m_output ); // this automatically applies the shader

    // main loop
    while( !m_shutdownFlag() )
    {
        infoLog() << "Waiting ...";
        m_moduleState.wait();

242 243 244
        // determine axis to draw contours for
        size_t axis = m_sliceSelection->get( true ).at( 0 )->getAs< AxisType >()->getValue();

245 246 247 248 249 250 251 252 253 254 255 256 257 258
        // woke up since the module is requested to finish?
        if( m_shutdownFlag() )
        {
            break;
        }

        // save data behind connectors since it might change during processing
        boost::shared_ptr< WDataSetScalar > scalarData = m_scalarIC->getData();

        if( !scalarData )
        {
            continue;
        }

259 260 261
        // now something different has happened: We need to create new geometry
        debugLog() << "Handle scalar data update, regenerate geometry.";

262 263 264
        m_isovalue->setMin( 0.0 );
        m_isovalue->setMax( 1.0 );

265
        initOSG( scalarData, m_resolution->get(), axis );
266 267 268 269 270 271

        wge::bindTexture( m_output, scalarData->getTexture(), 0, "u_scalarData" );
    }

    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_output );
}