WMPickingDVR.cpp 30.2 KB
Newer Older
1 2 3 4
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
5
// Copyright 2015-2017 A. Betz, D. Gerlicher, OpenWalnut Community
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// 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 <algorithm>
26
#include <cmath>
Alexander Wiebel's avatar
[STYLE]  
Alexander Wiebel committed
27
#include <limits>
28
#include <string>
Alexander Wiebel's avatar
Alexander Wiebel committed
29
#include <utility>
30
#include <vector>
31 32

#include <osg/CullFace>
33 34 35 36
#include <osg/Geometry>
#include <osg/LineWidth>
#include <osg/ShapeDrawable>
#include <osgViewer/View>
37

38
#include "core/common/datastructures/WSinglePosition.h"
39 40 41
#include "core/dataHandler/WDataSetScalar.h"
#include "core/graphicsEngine/WGEGeodeUtils.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
42
#include "core/graphicsEngine/WGERequirement.h"
43 44 45 46 47
#include "core/graphicsEngine/WGraphicsEngine.h"
#include "core/graphicsEngine/WPickHandler.h"
#include "core/graphicsEngine/WPickInfo.h"
#include "core/kernel/WKernel.h"
#include "core/kernel/WModuleInputData.h"
48
#include "core/ui/WUIRequirement.h"
49

50 51
#include "WMPickingDVR.h"
#include "WMPickingDVRHelper.h"
52
#include "WVisiTrace.h"
53

54
// Module Defines
Alexander Wiebel's avatar
Alexander Wiebel committed
55 56 57 58
#define WMPICKINGDVR_MAX_INT   "Picking - Maximum Intensity"
#define WMPICKINGDVR_FIRST_HIT   "Picking - First Hit"
#define WMPICKINGDVR_THRESHOLD   "Picking - Threshold"
#define WMPICKINGDVR_MOST_CONTRIBUTING "Picking - Most Contributing"
59
#define WMPICKINGDVR_HIGHEST_OPACITY   "Picking - Highest Opacity"
Alexander Wiebel's avatar
Alexander Wiebel committed
60 61
#define WMPICKINGDVR_WYSIWYP   "Picking - WYSIWYP"

62
// This line is needed by the module loader to actually find your module.
63
W_LOADABLE_MODULE( WMPickingDVR )
64

65
WMPickingDVR::WMPickingDVR():
66
WModule(),
67
    m_propCondition( new WCondition() ),
68
    m_intersected( false ),
69
    m_curve3D( 0 ),
70 71
    m_oldRayStart( 0.0, 0.0, 0.0 ),
    m_pickHandlerConnected( false )
72
{
73 74
    m_posStart = osg::Vec3f( 0.0, 0.0, 0.0 );
    m_posEnd = osg::Vec3f( 0.0, 0.0, 0.0 );
75 76
}

77
WMPickingDVR::~WMPickingDVR()
78 79 80
{
}

81
boost::shared_ptr< WModule > WMPickingDVR::factory() const
82
{
83
    return boost::shared_ptr< WModule >( new WMPickingDVR() );
84 85
}

86
const std::string WMPickingDVR::getName() const
87
{
88
    return "Picking in DVR";
89 90
}

91
const std::string WMPickingDVR::getDescription() const
92
{
93
    return ""; // See META file in resources directory instead.
94 95
}

96
void WMPickingDVR::connectors()
97
{
98 99 100 101 102 103 104 105 106
    m_transferFunction = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(),
                                                                           "transfer function",
                                                                           "The 1D transfer function." );
    m_scalarIC = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(),
                                                                   "scalar data",
                                                                   "Scalar data." );
    m_externalScreenPos = WModuleInputData< WSinglePosition >::createAndAdd( shared_from_this(),
                                                                             "External Screen Position",
                                                                             "External screen position for picking." );
107 108 109 110

    WModule::connectors();
}

111
void WMPickingDVR::properties()
112
{
113 114
    m_selectionTypesList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
    m_selectionTypesList->addItem( "Position (Picking)" );
115
    m_selectionTypesList->addItem( "Line (First Hit)" );
116
    m_selectionTypesList->addItem( "Line (VisiTrace)" );
117 118 119 120 121 122 123
    m_selectionType = m_properties->addProperty( "Selection type",
                                                 "What type of structure is to be selected in the DVR?",
                                                 m_selectionTypesList->getSelectorFirst(),
                                                 m_propCondition );
    WPropertyHelper::PC_SELECTONLYONE::addTo( m_selectionType );
    WPropertyHelper::PC_NOTEMPTY::addTo( m_selectionType );

124 125 126 127
    m_sampleSteps = m_properties->addProperty( "Samples - steps",
                      "Number of samples. Choose this appropriately for the settings used for the DVR itself.",
                       256,
                       m_propCondition );
128 129 130 131 132
    m_sampleSteps->setMin( 0 );
    m_sampleSteps->setMax( 10000 );

    m_opacityCorrectionEnabled = m_properties->addProperty( "Opacity correction",
            "If enabled, opacities are assumed to be relative to the "
133
            "sample count. Choose this appropriately for the settings used for the DVR itself.",
134 135
            true,
            m_propCondition );
136

137 138 139 140
    m_continuousDrawing = m_properties->addProperty( "Continuous drawing",
            "Should line be shown during drawing action?",
            true,
            m_propCondition );
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    m_lineColor = m_properties->addProperty( "Line color",
                                             "Color of line/s indicating selected position/s.",
                                             WColor( 0.5f, 0.5f, 0.5f, 1.0f ),
                                             m_propCondition );

    m_lineThickness = m_properties->addProperty( "Line thickness",
                                                 "Thickness of line/s indicating selected position/s.",
                                                 0.5,
                                                 m_propCondition );
    m_lineThickness->setMin( 0.001 );
    m_lineThickness->setMax( 5.0 );

    m_crossSize = m_properties->addProperty( "Crosshair size",
                                             "Length of crosshair lines.",
                                             100.0,
                                             m_propCondition );
158 159 160
    m_crossSize->setMin( 0.001 );
    m_crossSize->setMax( 1000.0 );

161 162 163 164
    m_pickingCriteriaList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
    m_pickingCriteriaList->addItem( WMPICKINGDVR_FIRST_HIT, WMPICKINGDVR_FIRST_HIT );
    m_pickingCriteriaList->addItem( WMPICKINGDVR_THRESHOLD, WMPICKINGDVR_THRESHOLD );
    m_pickingCriteriaList->addItem( WMPICKINGDVR_MOST_CONTRIBUTING, WMPICKINGDVR_MOST_CONTRIBUTING );
165
    m_pickingCriteriaList->addItem( WMPICKINGDVR_HIGHEST_OPACITY, WMPICKINGDVR_HIGHEST_OPACITY );
166 167 168 169
    m_pickingCriteriaList->addItem( WMPICKINGDVR_WYSIWYP, WMPICKINGDVR_WYSIWYP );
    m_pickingCriteriaList->addItem( WMPICKINGDVR_MAX_INT, WMPICKINGDVR_MAX_INT );

    m_pickingCriteriaCur = m_properties->addProperty( "Picking method",
170
                                                      "Select a picking method",
171
                                                      m_pickingCriteriaList->getSelectorFirst(),
172 173
                                                      m_propCondition );

174 175
    WPropertyHelper::PC_SELECTONLYONE::addTo( m_pickingCriteriaCur );
    WPropertyHelper::PC_NOTEMPTY::addTo( m_pickingCriteriaCur );
176

177 178 179 180
    m_alphaThreshold = m_properties->addProperty( "Alpha threshold %",
                                                  "Alpha value threshold for threshold picking mode.",
                                                  0.5,
                                                  m_propCondition );
181 182 183
    m_alphaThreshold->setMin( 0.0 );
    m_alphaThreshold->setMax( 1.0 );

184 185 186 187 188 189 190 191 192 193 194 195 196 197

    m_wysiwypPositionTypesList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
    m_wysiwypPositionTypesList->addItem( "Front" );
    m_wysiwypPositionTypesList->addItem( "Center" );

    m_wysiwypPositionType = m_properties->addProperty( "Pick position type",
                                                       "Which position of the picked object should be returned?",
                                                       m_wysiwypPositionTypesList->getSelectorFirst(),
                                                       m_propCondition );

    WPropertyHelper::PC_SELECTONLYONE::addTo( m_wysiwypPositionType );
    WPropertyHelper::PC_NOTEMPTY::addTo( m_wysiwypPositionType );


198 199 200
    WModule::properties();
}

201
void WMPickingDVR::requirements()
202
{
203 204
    m_requirements.push_back( new WGERequirement() );
    m_requirements.push_back( new WUIRequirement() );
205 206
}

207
void WMPickingDVR::moduleMain()
208
{
Alexander Wiebel's avatar
Alexander Wiebel committed
209
    // Get notified about data changes
210 211 212
    m_moduleState.setResetable( true, true );
    m_moduleState.add( m_scalarIC->getDataChangedCondition() );
    m_moduleState.add( m_transferFunction->getDataChangedCondition() );
213
    m_moduleState.add( m_externalScreenPos->getDataChangedCondition() );
214 215 216 217
    m_moduleState.add( m_propCondition );

    ready();

Alexander Wiebel's avatar
Alexander Wiebel committed
218
    // Graphics setup
219 220 221
    m_rootNode = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );

222
    //Get Camera and Register the callback
223 224 225
    boost::shared_ptr< WGraphicsEngine > graphicsEngine = WGraphicsEngine::getGraphicsEngine();
    boost::shared_ptr< WGEViewer > mainView = graphicsEngine->getViewerByName( "Main View" );

Alexander Wiebel's avatar
Alexander Wiebel committed
226
    // Main loop
227 228 229 230 231 232 233 234 235 236 237
    while( !m_shutdownFlag() )
    {
        debugLog() << "Waiting ...";
        m_moduleState.wait();

        // woke up since the module is requested to finish?
        if( m_shutdownFlag() )
        {
            break;
        }

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
        if( m_externalScreenPos->isConnected() == 0 )
        {
            if( !m_pickHandlerConnected )
            {
                // Register PickHandler
                mainView->getPickHandler()->getPickSignal()->connect( boost::bind( &WMPickingDVR::pickHandler, this, _1 ) );
                m_pickHandlerConnected = true;
            }
        }
        else
        {
            if( m_pickHandlerConnected )
            {
                // Register PickHandler
                mainView->getPickHandler()->getPickSignal()->disconnect( boost::bind( &WMPickingDVR::pickHandler, this, _1 ) );
                m_pickHandlerConnected = false;
            }
        }




260 261
        std::string pickingMode;

262 263
        const int selectionType =  m_selectionType->get( true ).getItemIndexOfSelected( 0 );
        if( selectionType == 0 ) // Pick
264
        {
265 266 267
            pickingMode = m_pickingCriteriaCur->get( true ).at( 0 )->getName();
            debugLog() << pickingMode;
        }
268
        else if( selectionType == 1 ) // Line (First Hit)
269 270
        {
            pickingMode = WMPICKINGDVR_FIRST_HIT;
271
            debugLog() << "Line (First Hit)";
272 273
        }
        else if( selectionType == 2 ) // VisiTrace
274 275 276 277
        {
            pickingMode = WMPICKINGDVR_WYSIWYP;
            debugLog() << "VisiTrace";
        }
278

279 280
        updateModuleGUI( pickingMode );

281
        if( selectionType == 0 )
282
        {
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
            if( m_externalScreenPos->isConnected() != 0 && m_externalScreenPos->getData() )
            {
                float fPosX = ( *( m_externalScreenPos->getData() ) )[0];
                float fPosY = ( *( m_externalScreenPos->getData() ) )[1];

                boost::shared_ptr< WGraphicsEngine > graphicsEngine = WGraphicsEngine::getGraphicsEngine();
                boost::shared_ptr< WGEViewer > mainView = graphicsEngine->getViewerByName( "Main View" );

                osg::ref_ptr< osgViewer::Viewer > view = mainView->getView();
                osgUtil::LineSegmentIntersector::Intersections intersections;

                bool intersected = view->computeIntersections( fPosX, fPosY, intersections, 0xFFFFFFFF );
                if( intersected )
                {
                    osgUtil::LineSegmentIntersector::Intersection start= *intersections.begin();
                    osgUtil::LineSegmentIntersector::Intersection end = *intersections.rbegin();

                    m_posStart = start.getWorldIntersectPoint();
                    m_posEnd  = end.getWorldIntersectPoint();

                    m_intersected = true;
                }
            }

307
            // Valid position picked on proxy cube
Alexander Wiebel's avatar
Alexander Wiebel committed
308
            if( m_intersected )
309
            {
310
                bool pickingSuccessful = false;
311
                const WPosition posPicking = getPickedDVRPosition( pickingMode, &pickingSuccessful );
312 313 314 315 316

                if( pickingSuccessful )
                {
                    updatePositionIndicator( posPicking );
                }
317 318
            }
        }
319
        else if( selectionType == 1)
320
        {
321 322 323 324 325 326
            bool pickingSuccessful = false;
            const WPosition posPicking = getPickedDVRPosition( pickingMode, &pickingSuccessful );
            if( pickingSuccessful )
            {
                m_curve3D.push_back( posPicking );
            }
327

328 329 330 331 332
            if( m_continuousDrawing->get()
                || !m_pickInProgress )
            {
                updateCurveRendering();
            }
333 334 335 336 337 338 339 340 341

            if( m_pickInProgress )
            {
                m_moduleState.notify(); // Make sure that main loop is excuted until picking stopped
            }
            else
            {
                m_curve3D.clear(); // Start a new line for the next line selection
            }
342
        }
Alexander Wiebel's avatar
[STYLE]  
Alexander Wiebel committed
343
        else if( selectionType == 2 )
344
        {
345
            if( m_oldRayStart != WPosition( m_posStart ) )
346
            {
347 348 349 350 351 352 353
                m_oldRayStart = m_posStart;

                std::vector< std::pair< double, WPosition > > candidates = computeVisiTraceCandidates();
                if( candidates.size() )
                {
                    m_visiTrace.addCandidatesForRay( candidates );
                }
354
            }
355 356 357 358 359

            if( m_continuousDrawing->get()
                || !m_pickInProgress )
            {
                m_curve3D = m_visiTrace.getLine();
360
                debugLog() << "Obtained line with " <<  m_curve3D.size() << " elements.";
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
                updateCurveRendering();
            }

            if( m_pickInProgress )
            {
                m_moduleState.notify(); // Make sure that main loop is excuted until picking stopped
            }
            else
            {
                m_visiTrace.reset();
                m_curve3D.clear(); // Start a new line for the next line selection
            }
        }
        else
        {
            WAssert( false, "This should not happen. Internal module error." );
        }
378 379 380 381 382
    }

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

383
void WMPickingDVR::pickHandler( WPickInfo pickInfo )
384
{
385
    if( pickInfo.getMouseButton() != 2 ) // Not right mouse button
386
    {
387 388 389 390
        if( pickInfo.getName() == WPickHandler::unpickString )
        {
            m_pickInProgress = false;
        }
391 392
        return;
    }
393

394 395
    m_pickInProgress = true;

396 397
    boost::shared_ptr< WGraphicsEngine > graphicsEngine = WGraphicsEngine::getGraphicsEngine();
    boost::shared_ptr< WGEViewer > mainView = graphicsEngine->getViewerByName( "Main View" );
398

399
    osg::ref_ptr< osgViewer::Viewer > view = mainView->getView();
400 401
    osgUtil::LineSegmentIntersector::Intersections intersections;

402 403
    float fPosX = pickInfo.getPickPixel().x();
    float fPosY = pickInfo.getPickPixel().y();
Alexander Wiebel's avatar
Alexander Wiebel committed
404

Alexander Wiebel's avatar
Alexander Wiebel committed
405 406
    bool intersected = view->computeIntersections( fPosX, fPosY, intersections, 0xFFFFFFFF );
    if( intersected )
407 408 409
    {
        osgUtil::LineSegmentIntersector::Intersection start= *intersections.begin();
        osgUtil::LineSegmentIntersector::Intersection end = *intersections.rbegin();
410

411 412
        m_posStart = start.getWorldIntersectPoint();
        m_posEnd  = end.getWorldIntersectPoint();
413

Alexander Wiebel's avatar
Alexander Wiebel committed
414
        m_intersected = true;
415

Alexander Wiebel's avatar
Alexander Wiebel committed
416
        // Notify moduleMain()
417
        m_propCondition->notify();
418
    }
419
}
420

421
void WMPickingDVR::updateModuleGUI( std::string pickingMode )
422
{
423
    const bool picking = ( m_selectionType->get( true ).getItemIndexOfSelected( 0 ) == 0 );
424

425
    if( pickingMode == WMPICKINGDVR_THRESHOLD )
426 427 428 429 430 431 432
    {
        m_alphaThreshold->setHidden( false );
    }
    else
    {
        m_alphaThreshold->setHidden( true );
    }
433

434
    if( pickingMode == WMPICKINGDVR_WYSIWYP )
435 436 437 438 439 440 441
    {
        m_wysiwypPositionType->setHidden( false );
    }
    else
    {
        m_wysiwypPositionType->setHidden( true );
    }
442 443 444 445 446

    if( picking )
    {
        m_pickingCriteriaCur->setHidden( false );
        m_crossSize->setHidden( false );
447
        m_continuousDrawing->setHidden( true );
448 449 450 451 452
    }
    else
    {
        m_pickingCriteriaCur->setHidden( true );
        m_crossSize->setHidden( true );
453
        m_continuousDrawing->setHidden( false );
454
    }
455
}
Alexander Wiebel's avatar
Alexander Wiebel committed
456

457

458 459
std::pair<int, int> WMPickingDVR::getWYSIWYPBounds( const std::vector<double>& vecAlphaAcc )
{
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    std::vector<int> vecIndicesLowerBounds;
    std::vector<int> vecIndicesUpperBounds;
    calculateIntervalsWYSIWYP( vecAlphaAcc, vecIndicesLowerBounds, vecIndicesUpperBounds );

    // Calculate max difference
    double diff = 0.0;
    double maxDiff = 0.0;
    int sampleLo = -1;
    int sampleUp = -1;

    for( unsigned int j = 0; j < std::min( vecIndicesLowerBounds.size(), vecIndicesUpperBounds.size() ); j++ )
    {
        // Calculate opacity jump of interval
        diff = vecAlphaAcc[vecIndicesUpperBounds[j]] - vecAlphaAcc[vecIndicesLowerBounds[j]];
        //debugLog() << "Interval [" <<  vecIndicesLowerBounds[j] << "," << vecIndicesUpperBounds[j] << "] = " << diff;

        // Is max diff
        if( diff > maxDiff )
        {
            maxDiff = diff;
            sampleLo = vecIndicesLowerBounds[j];
            sampleUp = vecIndicesUpperBounds[j];
        }
    }
    //debugLog() << "Start of largest interval " << sampleLo;

    return std::make_pair( sampleLo, sampleUp );
487 488 489
}


490 491 492
void WMPickingDVR::calculateIntervalsWYSIWYP( const std::vector<double>& vecAlphaAcc,
                                              std::vector<int>& vecIndicesLowerBounds,
                                              std::vector<int>& vecIndicesUpperBounds )
Alexander Wiebel's avatar
Alexander Wiebel committed
493 494 495 496
{
    std::vector<double> vecFirstDerivative;
    std::vector<double> vecSecondDerivative;

497
    PickingDVRHelper::calculateDerivativesWYSIWYP( vecAlphaAcc, vecFirstDerivative, vecSecondDerivative );
Alexander Wiebel's avatar
Alexander Wiebel committed
498

499
    // Calculate interval boundaries
Alexander Wiebel's avatar
Alexander Wiebel committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
    double oldDerivative;
    if( vecSecondDerivative.size() > 0 )
    {
        oldDerivative = vecSecondDerivative[0];
    }

    for( unsigned int j = 1; j < vecSecondDerivative.size(); j++ )
    {
        if( oldDerivative < 0.0 && vecSecondDerivative[j] >= 0.0
            && ( vecIndicesLowerBounds.size() > 0 ) ) // need to have a lower bound already
        {
            vecIndicesUpperBounds.push_back( j );
        }

        if( oldDerivative <= 0.0 && vecSecondDerivative[j] > 0.0 )
        {
            vecIndicesLowerBounds.push_back( j );
        }

        oldDerivative = vecSecondDerivative[j];
    }
}

Alexander Wiebel's avatar
Alexander Wiebel committed
523 524 525
void WMPickingDVR::updatePositionIndicator( osg::Vec3f position )
{
    osg::ref_ptr< osg::Geometry > geometry;
Alexander Wiebel's avatar
Alexander Wiebel committed
526
    osg::ref_ptr< osg::Geode > geode( new osg::Geode );
Alexander Wiebel's avatar
Alexander Wiebel committed
527 528

    const double size  = m_crossSize->get();
529
    const double thickness = m_lineThickness->get();
Alexander Wiebel's avatar
Alexander Wiebel committed
530 531 532 533 534

    osg::ShapeDrawable* pBoxX = new osg::ShapeDrawable( new osg::Box( position, size, thickness, thickness ) );
    osg::ShapeDrawable* pBoxY = new osg::ShapeDrawable( new osg::Box( position, thickness, size, thickness ) );
    osg::ShapeDrawable* pBoxZ = new osg::ShapeDrawable( new osg::Box( position, thickness, thickness, size ) );

535 536 537
    pBoxX->setColor( m_lineColor->get() );
    pBoxY->setColor( m_lineColor->get() );
    pBoxZ->setColor( m_lineColor->get() );
Alexander Wiebel's avatar
Alexander Wiebel committed
538 539 540 541 542 543 544 545 546 547 548

    geode->addDrawable( pBoxX );
    geode->addDrawable( pBoxY );
    geode->addDrawable( pBoxZ );

    m_rootNode->remove( m_geode );
    m_geode = geode;

    m_rootNode->clear();
    m_rootNode->insert( geode );
}
549

550
std::vector< std::pair< double, WPosition > > WMPickingDVR::sampleIntensityAlongRay()
551
{
552 553 554 555
    osg::Vec3f posStart = m_posStart;
    osg::Vec3f posEnd = m_posEnd;
    osg::Vec3f posSample = m_posStart;
    osg::Vec3f vecDir = posEnd - posStart;
556

Alexander Wiebel's avatar
Alexander Wiebel committed
557
    // Calculate step
558 559 560 561 562
    if( m_sampleSteps->get() > 0 )
    {
        vecDir = vecDir / m_sampleSteps->get();
    }

Alexander Wiebel's avatar
Alexander Wiebel committed
563
    // Get scalar field
564 565 566 567
    boost::shared_ptr< WDataSetScalar > scalarData = m_scalarIC->getData();
    if(!scalarData)
    {
        errorLog()<< "[Invalid scalar field]";
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
        return std::vector< std::pair< double, WPosition > >();
    }

    std::vector< std::pair< double, WPosition > > result;
    // Sampling loop
    for( int i = 0; i < m_sampleSteps->get(); i++ )
    {
        //Scalarfield values
        bool success = false;
        double value = scalarData->interpolate( posSample, &success );

        //Add Step
        posSample = posSample + vecDir;

        if( success )
        {
            result.push_back( std::make_pair( value, posSample ) );
        }
    }
    return result;
}

590
double WMPickingDVR::getTFAlpha( const double scalar ) const
591
{
Alexander Wiebel's avatar
Alexander Wiebel committed
592
    // Get transferfunction data
593
    boost::shared_ptr< WDataSetSingle > transferFunctionData = m_transferFunction->getData();
594
    if( !transferFunctionData )
595
    {
596
        WAssert( false, "Invalid transferfunction data" );
597 598
    }

Alexander Wiebel's avatar
Alexander Wiebel committed
599
    // Get transferfunction values
600 601
    boost::shared_ptr< WValueSetBase > transferFunctionValues = transferFunctionData->getValueSet();

602

603 604 605 606
    // Get scalar field
    boost::shared_ptr< WDataSetScalar > scalarData = m_scalarIC->getData();
    if(!scalarData)
    {
607
        WAssert( false, "Invalid scalar field" );
608 609
    }

610 611
    const double max = scalarData->getMax();
    const double min = scalarData->getMin();
612

613 614 615
    // Classification variables
    const double nominator = scalar - min;
    double denominator = max - min;
616

617
    if( denominator == 0.0 )
618
    {
619 620
        denominator = 0.0001;
    }
621

622 623 624 625 626
    // Classification: Convert scalar to color
    double scalarPercentage = nominator / denominator;
    int colorIdx = scalarPercentage * transferFunctionValues->size();

    WMPickingColor<double> color;
627

628 629 630 631 632 633
    // Get color from transferfunction
    color.setRed( transferFunctionData->getSingleRawValue( colorIdx * 4 + 0 ) );
    color.setGreen( transferFunctionData->getSingleRawValue( colorIdx * 4 + 1 ) );
    color.setBlue( transferFunctionData->getSingleRawValue( colorIdx * 4 + 2 ) );
    color.setAlpha( transferFunctionData->getSingleRawValue( colorIdx * 4 + 3 ) );
    color.normalize();
634

635 636
    return color.getAlpha();
}
637

638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
double WMPickingDVR::compositingStep( double accAlpha, const double currentAlpha )
{
    double currentAlphaCorrected;

    if( m_opacityCorrectionEnabled->get( true ) )
    {
        const double defaultNumberOfSteps = 128.0;
        float relativeSampleDistance = defaultNumberOfSteps / m_sampleSteps->get();
        currentAlphaCorrected =  1.0 - pow( 1.0 - currentAlpha, relativeSampleDistance );
    }
    else
    {
        currentAlphaCorrected = currentAlpha;
    }

    accAlpha  = currentAlphaCorrected + ( accAlpha - currentAlphaCorrected * accAlpha );
    return accAlpha;
}

657

658 659 660 661
std::vector< std::pair< double, WPosition > > WMPickingDVR::computeVisiTraceCandidates()
{
    std::vector< std::pair< double, WPosition > > samples( 0 );
    samples = sampleIntensityAlongRay();
662

663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
    if( samples.size() == 0 )
    {
        return std::vector< std::pair< double, WPosition > >();
    }

    double accAlpha = 0.0;

    std::vector<double> vecAlphaAcc;

    for( unsigned int i = 0; i < samples.size(); i++ )
    {
        const double currentAlpha = getTFAlpha( samples[i].first );
        accAlpha = compositingStep( accAlpha, currentAlpha );
        vecAlphaAcc.push_back( accAlpha );
    }

    std::vector<int> vecIndicesLowerBounds;
    std::vector<int> vecIndicesUpperBounds;
    calculateIntervalsWYSIWYP( vecAlphaAcc, vecIndicesLowerBounds, vecIndicesUpperBounds );

    std::vector<int> opacityJumps( 0 );
    for( unsigned int j = 0; j < std::min( vecIndicesLowerBounds.size(), vecIndicesUpperBounds.size() ); j++ )
    {
        opacityJumps.push_back( vecAlphaAcc[vecIndicesUpperBounds[j]] - vecAlphaAcc[vecIndicesLowerBounds[j]] );
    }

    std::vector< std::pair< double, WPosition > > candidates( 0 );
    for( size_t id = 0; id < opacityJumps.size(); ++id )
    {
        candidates.push_back( std::make_pair( opacityJumps[id], samples[vecIndicesLowerBounds[id]].second ) );
    }
    return candidates;
}

697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
WPosition WMPickingDVR::getPickedDVRPosition(  std::string pickingMode, bool* pickingSuccess )
{
    std::vector< std::pair< double, WPosition > > samples( 0 );
    samples = sampleIntensityAlongRay();
    if( samples.size() == 0 )
    {
        *pickingSuccess = false;
        return WPosition();
    }

    WPosition posPicking = m_posStart;

    double accAlpha = 0.0;
    double accAlphaOld = 0.0;
    double pickedAlpha = 0.0;
Alexander Wiebel's avatar
[STYLE]  
Alexander Wiebel committed
712
    double maxValue =  -1 * std::numeric_limits< double >::max();
713 714 715 716 717 718

    std::vector<double> vecAlphaAcc;

    for( unsigned int i = 0; i < samples.size(); i++ )
    {
        const double currentAlpha = getTFAlpha( samples[i].first );
719
        accAlpha = compositingStep( accAlpha, currentAlpha );
720 721 722

        if( pickingMode == WMPICKINGDVR_MAX_INT )
        {
Alexander Wiebel's avatar
Alexander Wiebel committed
723
            // Maximum Intensity: maximal scalar value
724
            if( samples[i].first > maxValue )
725
            {
726 727
                maxValue = samples[i].first;
                posPicking = samples[i].second;
728 729 730 731 732
                *pickingSuccess = true;
            }
        }
        else if( pickingMode == WMPICKINGDVR_FIRST_HIT )
        {
Alexander Wiebel's avatar
Alexander Wiebel committed
733
            // First Hit: first alpha value > 0.0
734 735 736
            if( currentAlpha > 0.0 )
            {
                pickedAlpha = currentAlpha;
737
                posPicking  =  samples[i].second;
738 739 740 741 742 743
                *pickingSuccess  = true;
                break;
            }
        }
        else if( pickingMode == WMPICKINGDVR_THRESHOLD )
        {
Alexander Wiebel's avatar
Alexander Wiebel committed
744
            // Threshold: accumulated alpha value > threshold
745 746 747
            if( accAlpha > m_alphaThreshold->get() )
            {
                pickedAlpha = currentAlpha;
748
                posPicking  =  samples[i].second;
749 750 751 752 753 754
                *pickingSuccess  = true;
                break;
            }
        }
        else if( pickingMode == WMPICKINGDVR_HIGHEST_OPACITY )
        {
Alexander Wiebel's avatar
Alexander Wiebel committed
755
            // Highest opacity: maximal alpha value
756 757 758
            if( currentAlpha > pickedAlpha )
            {
                pickedAlpha = currentAlpha;
759
                posPicking  =  samples[i].second;
760 761 762 763 764 765
                *pickingSuccess  = true;
            }
        }
        else if( pickingMode == WMPICKINGDVR_MOST_CONTRIBUTING )
        {
            double currenAlphaIncrease = accAlpha - accAlphaOld;
Alexander Wiebel's avatar
Alexander Wiebel committed
766
            // Most Contributing: maximal alpha value increase
767 768 769
            if( currenAlphaIncrease > pickedAlpha )
            {
                pickedAlpha = currenAlphaIncrease;
770
                posPicking = samples[i].second;
Alexander Wiebel's avatar
[STYLE]  
Alexander Wiebel committed
771
                *pickingSuccess = true;
772 773 774 775 776 777 778 779 780 781
            }
            accAlphaOld = accAlpha;
        }
        else if( pickingMode == WMPICKINGDVR_WYSIWYP )
        {
            //WYSIWYP: Save all the accumulated alpha values
            vecAlphaAcc.push_back( accAlpha );
        }
    } // End of sampling loop

Alexander Wiebel's avatar
Alexander Wiebel committed
782
    // WYSIWYP: Calculate the largest interval
783 784 785 786 787 788
    if( pickingMode == WMPICKINGDVR_WYSIWYP )
    {
        std::pair<int, int> bounds = getWYSIWYPBounds( vecAlphaAcc );

        if( bounds.first >= 0 )
        {
789 790 791 792 793 794 795 796
            osg::Vec3f vecDir = m_posEnd - m_posStart;

            // Calculate step
            if( m_sampleSteps->get() > 0 )
            {
                vecDir = vecDir / m_sampleSteps->get();
            }

Alexander Wiebel's avatar
Alexander Wiebel committed
797
            // Calculate pick position
798 799
            if( m_wysiwypPositionType->get( true ).getItemIndexOfSelected( 0 ) == 0 )
            {
800
                posPicking = m_posStart + vecDir * bounds.first;
801 802 803 804
            }
            else
            {
                int centerSample = ( bounds.first + bounds.second ) / 2;
805
                posPicking = m_posStart + vecDir * centerSample;
806 807 808 809 810 811 812 813
            }

            *pickingSuccess = true;
        }
    }

    if( *pickingSuccess )
    {
814 815 816
        // debugLog() << "[pickedAlpha = " << pickedAlpha << "]"
        //            << "[posPicking][X = " << posPicking.x() << " ]"
        //            << "[Y = " << posPicking.y() << " ][Z = " << posPicking.z() << "]";
817 818 819 820
    }

    return posPicking;
}
821

Alexander Wiebel's avatar
Alexander Wiebel committed
822
namespace
823
{
Alexander Wiebel's avatar
Alexander Wiebel committed
824
    osg::ref_ptr< osg::Geode > generateLineStripGeode( const WLine& line, const float thickness, const WColor& color )
825
    {
Alexander Wiebel's avatar
Alexander Wiebel committed
826 827 828 829
        using osg::ref_ptr;
        ref_ptr< osg::Vec3Array > vertices = ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
        ref_ptr< osg::Vec4Array > colors = ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
        ref_ptr< osg::Geometry > geometry = ref_ptr< osg::Geometry >( new osg::Geometry );
830

Alexander Wiebel's avatar
Alexander Wiebel committed
831 832 833 834 835 836 837
        for( size_t i = 1; i < line.size(); ++i )
        {
            vertices->push_back( osg::Vec3( line[i-1][0], line[i-1][1], line[i-1][2] ) );
            colors->push_back( wge::getRGBAColorFromDirection( line[i-1], line[i] ) );
        }
        vertices->push_back( osg::Vec3( line.back()[0], line.back()[1], line.back()[2] ) );
        colors->push_back( colors->back() );
838

Alexander Wiebel's avatar
Alexander Wiebel committed
839 840
        geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, line.size() ) );
        geometry->setVertexArray( vertices );
841

Alexander Wiebel's avatar
Alexander Wiebel committed
842 843 844 845 846 847 848 849 850 851 852 853
        if( color != WColor( 0, 0, 0, 0 ) )
        {
            colors->clear();
            colors->push_back( color );
            geometry->setColorArray( colors );
            geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
        }
        else
        {
            geometry->setColorArray( colors );
            geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); // This will not work on OSG 3.2 you should compute the color per vertex
        }
854

Alexander Wiebel's avatar
Alexander Wiebel committed
855 856 857 858 859 860 861 862 863
        // line width
        osg::StateSet* stateset = geometry->getOrCreateStateSet();
        stateset->setAttributeAndModes( new osg::LineWidth( thickness ), osg::StateAttribute::ON );
        stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );

        osg::ref_ptr< osg::Geode > geode = osg::ref_ptr< osg::Geode >( new osg::Geode );
        geode->addDrawable( geometry );
        return geode;
    }
864 865 866 867 868 869 870 871
}

void WMPickingDVR::updateCurveRendering()
{
    WLine line( m_curve3D );
    if( line.size() > 1 )
    {
        m_rootNode->remove( m_geode );
872
        m_geode = generateLineStripGeode( line, m_lineThickness->get(), m_lineColor->get() );
873 874 875 876 877

        m_rootNode->clear();
        m_rootNode->insert( m_geode );
    }
}