WMVectorNormalize.cpp 7.41 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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 <stdint.h>

#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include <boost/variant.hpp>

#include "core/common/math/linearAlgebra/WLinearAlgebra.h"
#include "core/common/WAssert.h"
#include "core/common/WProgress.h"
#include "core/common/WStringUtils.h"
#include "core/common/WTypeTraits.h"
#include "core/common/exceptions/WTypeMismatch.h"
#include "core/dataHandler/WGridRegular3D.h"
#include "core/dataHandler/WDataHandlerEnums.h"
#include "core/dataHandler/WDataHandler.h"
#include "core/dataHandler/exceptions/WDHValueSetMismatch.h"
#include "core/kernel/WKernel.h"

#include "WMVectorNormalize.h"

// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMVectorNormalize )

WMVectorNormalize::WMVectorNormalize() :
    WModule()
{
    // initialize
}

WMVectorNormalize::~WMVectorNormalize()
{
    // cleanup
    removeConnectors();
}

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

const std::string WMVectorNormalize::getName() const
{
    return "Vector Normalize";
}

const std::string WMVectorNormalize::getDescription() const
{
    return "Normalize a vector field.";
}

void WMVectorNormalize::connectors()
{
    m_inputA = WModuleInputData< WDataSetVector >::createAndAdd( shared_from_this(), "input", "Input vectors." );

    m_output = WModuleOutputData< WDataSetVector >::createAndAdd( shared_from_this(), "normalized", "Normalized input." );

    // call WModules initialization
    WModule::connectors();
}

void WMVectorNormalize::properties()
{
    m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );

93 94 95 96
    m_zeroTol = m_properties->addProperty( "Zero Tolerance", "Vector lengths smaller than this are assumed as being 0.", 0.000001, m_propCondition );
    m_zeroTol->setMin( 0.0 );
    m_zeroTol->setMax( 1.0 );

97 98 99 100 101 102 103 104 105 106 107
    WModule::properties();
}

/**
 * Visitor for discriminating the type of the first valueset.
 */
class VisitorVSetA: public boost::static_visitor< boost::shared_ptr< WValueSetBase > >
{
public:
    /**
     * Create visitor instance.
108 109
     *
     * \param zeroZol zero tollerance
110
     */
111 112 113
    VisitorVSetA( double zeroTol = 0.0000001 ):
        boost::static_visitor< result_type >(),
        m_zeroTol( zeroTol )
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    {
    }

    /**
     * Called by boost::varying during static visiting.
     *
     * \tparam T the real integral type of the first value set.
     * \param vsetA the first valueset currently visited.
     *
     * \return the result from the operation
     */
    template < typename T >
    result_type operator()( const WValueSet< T >* const& vsetA ) const             // NOLINT
    {
        // get some info
        std::vector< T > data;
        data.resize( vsetA->rawSize() );

        // apply op to each value
        // iterate field
        for( size_t i = 0; i < vsetA->size(); ++i )
        {
            // to avoid cascading numeric errors due to T being a low resolution type, we use doubles during calculation
            double x = vsetA->getScalar( ( i * 3 ) + 0 );
            double y = vsetA->getScalar( ( i * 3 ) + 1 );
            double z = vsetA->getScalar( ( i * 3 ) + 2 );

            double len = sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
142 143 144 145 146 147 148 149
            if( len < m_zeroTol )
            {
                data[ ( i * 3 ) + 0 ] = 0;
                data[ ( i * 3 ) + 1 ] = 0;
                data[ ( i * 3 ) + 2 ] = 0;

                continue;
            }
150 151 152 153 154 155 156 157 158 159 160 161 162

            data[ ( i * 3 ) + 0 ] = static_cast< T >( x / len );
            data[ ( i * 3 ) + 1 ] = static_cast< T >( y / len );
            data[ ( i * 3 ) + 2 ] = static_cast< T >( z / len );
        }

        // create result value set
        return boost::shared_ptr< WValueSet< T > >( new WValueSet< T >( 1,
                                                                        3,
                                                                        boost::shared_ptr< std::vector< T > >(
                                                                            new std::vector< T >( data ) ),
                                                                        DataType< T >::type ) );
    }
163 164 165 166 167

    /**
     * Zero tollerance. Values smaller than this are interpreted as zero
     */
    double m_zeroTol;
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
};

void WMVectorNormalize::moduleMain()
{
    // let the main loop awake if the data changes or the properties changed.
    m_moduleState.setResetable( true, true );
    m_moduleState.add( m_inputA->getDataChangedCondition() );
    m_moduleState.add( m_propCondition );

    // signal ready state
    ready();

    // loop until the module container requests the module to quit
    while( !m_shutdownFlag() )
    {
        // Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
        // or an property changes. The main loop now waits until something happens.
        debugLog() << "Waiting ...";
        m_moduleState.wait();

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

        // has the data changed?
195
        if( m_zeroTol->changed() || m_inputA->handledUpdate() )
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
        {
            boost::shared_ptr< WDataSetVector > dataSetA = m_inputA->getData();

            // valid data?
            if( dataSetA )
            {
                boost::shared_ptr< WValueSetBase > valueSetA = dataSetA->getValueSet();

                // use a custom progress combiner
                boost::shared_ptr< WProgress > prog = boost::shared_ptr< WProgress >(
                    new WProgress( "Applying operator on data" ) );
                m_progress->addSubProgress( prog );

                // apply the operation to each voxel
                debugLog() << "Processing ...";
211
                boost::shared_ptr< WValueSetBase > newValueSet = valueSetA->applyFunction( VisitorVSetA( m_zeroTol->get( true ) ) );
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

                // Create the new dataset and export it
                m_output->updateData( boost::shared_ptr<WDataSetVector>( new WDataSetVector( newValueSet, m_inputA->getData()->getGrid() ) ) );

                // done
                prog->finish();
                m_progress->removeSubProgress( prog );
            }
            else
            {
                debugLog() << "Resetting output.";
                m_output->reset();
            }
        }
    }
}