Commit 9bb574fe authored by Andreas Schwarzkopf's avatar Andreas Schwarzkopf

[ADD #361] An additional outline method in the wall detection module and some fixes.

 * Added a new outline method to the wall detection. Voxels or properties of its
 * input point data can be displayed using rhombs. They display the wall node group,
 * Eigen Vectors, Eigen Values and the mean coordinate.
 *
 * Applied fixes:
 * The wall detection failed by bleeding through several surfaces. The problem was
 * that no angle condition was applied during merging wall groups.
 * Also small cleanups were applied on the code.
parent df86ea5c
......@@ -33,6 +33,7 @@
#include "buildingsDetection/WMBuildingsDetection.h"
#include "buildingsDetectionByPCA/WMBuildingsDetectionByPCA.h"
#include "elevationImageExport/WMElevationImageExport.h"
#include "pointsCrop/WMPointsCrop.h"
#include "pointsCutOutliers/WMPointsCutOutliers.h"
#include "pointsGroupSelector/WMPointsGroupSelector.h"
#include "readLAS/WMReadLAS.h"
......@@ -55,6 +56,7 @@ extern "C" void WLoadModule( WModuleList& m ) // NOLINT
m.push_back( boost::shared_ptr< WModule >( new WMBuildingsDetection ) );
m.push_back( boost::shared_ptr< WModule >( new WMBuildingsDetectionByPCA ) );
m.push_back( boost::shared_ptr< WModule >( new WMElevationImageExport ) );
m.push_back( boost::shared_ptr< WModule >( new WMPointsCrop ) );
m.push_back( boost::shared_ptr< WModule >( new WMPointsCutOutliers ) );
m.push_back( boost::shared_ptr< WModule >( new WMPointsGroupSelector ) );
m.push_back( boost::shared_ptr< WModule >( new WMReadLAS ) );
......
......@@ -107,8 +107,8 @@ void WMBuildingsDetection::properties()
"depth for the octree search tree.", 0 );
m_detailDepth->setMin( -3 );
m_detailDepth->setMax( 4 );
m_detailDepthLabel = m_properties->addProperty( "Detail Depth meters: ", "Resulting detail depth "
"in meters for the octree search tree.", 1.0 );
m_detailDepthLabel = m_properties->addProperty( "Voxel width meters: ", "Resulting detail depth "
"in meters for the octree search tree.", pow( 2.0, m_detailDepth->get() ) * 2.0 );
m_detailDepthLabel->setPurpose( PV_PURPOSE_INFORMATION );
m_minSearchDetailDepth = m_properties->addProperty( "Detail Depth min. search: ",
......@@ -173,8 +173,8 @@ void WMBuildingsDetection::moduleMain()
detector.detectBuildings( points );
WOctree* buildingGroups = detector.getBuildingGroups();
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) );
WQuadTree* boundingBox = new WQuadTree( m_detailDepthLabel->get() );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) * 2.0 );
WQuadTree* boundingBox = new WQuadTree( pow( 2.0, m_detailDepth->get() ) );
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
for ( size_t vertex = 0; vertex < count; vertex++)
......
......@@ -99,7 +99,7 @@ void WMBuildingsDetectionByPCA::properties()
m_detailDepth->setMin( -3 );
m_detailDepth->setMax( 4 );
m_detailDepthLabel = m_properties->addProperty( "Detail Depth meters: ", "Resulting detail depth "
"in meters for the octree search tree.", 1.0 );
"in meters for the octree search tree.", pow( 2.0, m_detailDepth->get() ) * 2.0 );
m_detailDepthLabel->setPurpose( PV_PURPOSE_INFORMATION );
m_showedIsotropicThresholdMin = m_properties->addProperty( "Eigen Value Quot. min.: ", "The minimal "
......@@ -158,8 +158,8 @@ void WMBuildingsDetectionByPCA::moduleMain()
size_t count = inputVerts->size()/3;
setProgressSettings( count );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) );
WOctree* pcaAnalysis = new WOctree( m_detailDepthLabel->get(), new WPcaDetectOctNode() );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) * 2.0 );
WOctree* pcaAnalysis = new WOctree( pow( 2.0, m_detailDepth->get() ), new WPcaDetectOctNode() );
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
for ( size_t vertex = 0; vertex < count; vertex++)
......
......@@ -50,7 +50,6 @@ void WPCADetector::setMinPointsPerVoxelToDraw( size_t minPointsPerVoxelToDraw )
}
void WPCADetector::analyze()
{
cout << "Total nodes in set: " << m_analyzableOctree->getRootNode()->getTotalNodeCount();
analyzeNode( ( WPcaDetectOctNode* )( m_analyzableOctree->getRootNode() ) );
}
void WPCADetector::analyzeNode( WPcaDetectOctNode* node )
......@@ -62,9 +61,9 @@ void WPCADetector::analyzeNode( WPcaDetectOctNode* node )
{
WPrincipalComponentAnalysis pca;
pca.analyzeData( node->getInputPoints() );
vector<double> variance = pca.getEigenValues();
if( variance[0] > 0.0 )
node->setEigenValueQuotient( variance[2] / variance[0] );
vector<double> eigenValues = pca.getEigenValues();
if( eigenValues[0] > 0.0 )
node->setEigenValueQuotient( eigenValues[2] / eigenValues[0] );
}
}
else
......
......@@ -127,21 +127,22 @@ void WOctree::groupNeighbourLeafs( WOctNode* node )
for( size_t index = 0; index < neighbors.size(); index++ )
{
WOctNode* neighbor = neighbors[index];
size_t neighborID = neighbor == 0 ?group :m_groupEquivs[neighbor->getGroupNr()];
size_t neighborID = neighbor != 0 && neighbor->hasGroup()
?m_groupEquivs[neighbor->getGroupNr()] :group;
if( group > neighborID && m_detailLevel == neighbor->getRadius() )
if( neighbor->hasGroup() )
if( canGroupNodes( node, neighbor ) )
if( neighbor->hasGroup() && canGroupNodes( node, neighbor ) )
group = neighborID;
}
for( size_t index = 0; index < neighbors.size(); index++ )
{
WOctNode* neighbor = neighbors[index];
size_t neighborID = neighbor == 0 ?group :m_groupEquivs[neighbor->getGroupNr()];
size_t neighborID = neighbor != 0 && neighbor->hasGroup()
?m_groupEquivs[neighbor->getGroupNr()] :group;
if( group < neighborID && neighbor->hasGroup() && m_detailLevel == neighbor->getRadius() )
{
for( size_t newIdx = 0; newIdx < m_groupEquivs.size(); newIdx++ )
if( m_groupEquivs[newIdx] == neighborID )
m_groupEquivs[newIdx] = group;
if( m_groupEquivs[newIdx] == neighborID && canGroupNodes( node, neighbor ) )
m_groupEquivs[newIdx] = group;
}
}
if( group >= m_groupEquivs.size() )
......
......@@ -108,8 +108,8 @@ void WMElevationImageExport::properties()
"depth for the octree search tree.", 0, m_propCondition );
m_detailDepth->setMin( -3 );
m_detailDepth->setMax( 4 );
m_detailDepthLabel = m_properties->addProperty( "Detail Depth meters: ", "Resulting detail depth "
"in meters for the octree search tree.", 1.0 );
m_detailDepthLabel = m_properties->addProperty( "Voxel width meters: ", "Resulting detail depth "
"in meters for the octree search tree.", pow( 2.0, m_detailDepth->get() ) * 2.0 );
m_detailDepthLabel->setPurpose( PV_PURPOSE_INFORMATION );
......@@ -117,7 +117,7 @@ void WMElevationImageExport::properties()
imageModes->addItem( "Minimals", "Minimal elevation values." );
imageModes->addItem( "Maximals", "Maximal elevation values." );
imageModes->addItem( "Point count", "Store point count to each pixel." );
m_elevImageMode = m_properties->addProperty( "Color mode", "Choose one of the available colorings.",
m_elevImageMode = m_properties->addProperty( "Elev. image mode", "Choose one of the available colorings.",
imageModes->getSelectorFirst(), m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_elevImageMode );
m_minElevImageZ = m_properties->addProperty( "Min. Z value: ",
......@@ -176,8 +176,8 @@ void WMElevationImageExport::moduleMain()
size_t count = verts->size()/3;
setProgressSettings( count );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) );
m_elevationImage = new WQuadTree( m_detailDepthLabel->get() );
m_detailDepthLabel->set( pow( 2.0, m_detailDepth->get() ) * 2.0 );
m_elevationImage = new WQuadTree( pow( 2.0, m_detailDepth->get() ) );
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
for( size_t vertex = 0; vertex < count; vertex++)
......
//---------------------------------------------------------------------------
//
// 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 <fstream> // std::ifstream
#include <iostream> // std::cout
#include <vector>
#include <osg/Geometry>
#include "core/kernel/WModule.h"
#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"
#include "WMPointsCrop.xpm"
#include "WMPointsCrop.h"
#include "../datastructures/octree/WOctree.h"
// This line is needed by the module loader to actually find your module.
//W_LOADABLE_MODULE( WMPointsCrop )
//TODO(aschwarzkopf): Reenable above after solving the toolbox problem
WMPointsCrop::WMPointsCrop():
WModule(),
m_propCondition( new WCondition() )
{
}
WMPointsCrop::~WMPointsCrop()
{
}
boost::shared_ptr< WModule > WMPointsCrop::factory() const
{
return boost::shared_ptr< WModule >( new WMPointsCrop() );
}
const char** WMPointsCrop::getXPMIcon() const
{
return WMPointsCrop_xpm;
}
const std::string WMPointsCrop::getName() const
{
return "Points - Crop";
}
const std::string WMPointsCrop::getDescription() const
{
return "Crops point data to a selection.";
}
void WMPointsCrop::connectors()
{
m_input = WModuleInputData< WDataSetPoints >::createAndAdd( shared_from_this(), "input", "The mesh to display" );
m_output = boost::shared_ptr< WModuleOutputData< WDataSetPoints > >(
new WModuleOutputData< WDataSetPoints >(
shared_from_this(), "points", "The loaded points." ) );
addConnector( m_output );
WModule::connectors();
}
void WMPointsCrop::properties()
{
// ---> Put the code for your properties here. See "src/modules/template/" for an extensively documented example.
double number_range = 1000000000.0;
m_fromX = m_properties->addProperty( "X min.: ", "Cut boundary.", -number_range, m_propCondition );
m_toX = m_properties->addProperty( "X max.: ", "Cut boundary.", number_range, m_propCondition );
m_fromY = m_properties->addProperty( "Y min.: ", "Cut boundary.", -number_range, m_propCondition );
m_toY = m_properties->addProperty( "Y max.: ", "Cut boundary.", number_range, m_propCondition );
m_fromZ = m_properties->addProperty( "Z min.: ", "Cut boundary.", -number_range, m_propCondition );
m_toZ = m_properties->addProperty( "Z max.: ", "Cut boundary.", number_range, m_propCondition );
m_cutInsteadOfCrop = m_properties->addProperty( "Cut: ", "Cut instead of crop.", false, m_propCondition );
WModule::properties();
}
void WMPointsCrop::requirements()
{
}
void WMPointsCrop::moduleMain()
{
infoLog() << "Thrsholding example main routine started";
// get notified about data changes
m_moduleState.setResetable( true, true );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
ready();
// graphics setup
m_rootNode = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
// main loop
while( !m_shutdownFlag() )
{
//infoLog() << "Waiting ...";
m_moduleState.wait();
boost::shared_ptr< WDataSetPoints > points = m_input->getData();
// std::cout << "Execute cycle\r\n";
if ( points )
{
m_verts = points->getVertices();
m_colors = points->getColors();
setProgressSettings( m_verts->size() * 2 / 3 );
initBoundingBox();
m_output->updateData( getCroppedPointSet() );
m_progressStatus->finish();
}
// std::cout << "this is WOTree " << std::endl;
// woke up since the module is requested to finish?
if ( m_shutdownFlag() )
{
break;
}
boost::shared_ptr< WDataSetPoints > points2 = m_input->getData();
if ( !points2 )
{
continue;
}
// ---> Insert code doing the real stuff here
}
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
}
void WMPointsCrop::setProgressSettings( size_t steps )
{
m_progress->removeSubProgress( m_progressStatus );
std::string headerText = "Loading data";
m_progressStatus = boost::shared_ptr< WProgress >( new WProgress( headerText, steps ) );
m_progress->addSubProgress( m_progressStatus );
}
void WMPointsCrop::initBoundingBox()
{
size_t count = m_verts->size() / 3;
if( m_verts->size() == 0 )
return;
for( size_t index = 0; index < count; index++ )
{
double x = m_verts->at( index * 3 );
double y = m_verts->at( index * 3 + 1 );
double z = m_verts->at( index * 3 + 2 );
if( index == 0 || x < m_minX ) m_minX = x;
if( index == 0 || x > m_maxX ) m_maxX = x;
if( index == 0 || y < m_minY ) m_minY = y;
if( index == 0 || y > m_maxY ) m_maxY = y;
if( index == 0 || z < m_minZ ) m_minZ = z;
if( index == 0 || z > m_maxZ ) m_maxZ = z;
m_progressStatus->increment( 1 );
}
m_fromX->setMin( m_minX );
m_fromX->setMax( m_maxX );
m_toX->setMin( m_fromX->get() );
m_toX->setMax( m_maxX );
m_fromY->setMin( m_minY );
m_fromY->setMax( m_maxY );
m_toY->setMin( m_fromY->get() );
m_toY->setMax( m_maxY );
m_fromZ->setMin( m_minZ );
m_fromZ->setMax( m_maxZ );
m_toZ->setMin( m_fromZ->get() );
m_toZ->setMax( m_maxZ );
}
boost::shared_ptr< WDataSetPoints > WMPointsCrop::getCroppedPointSet()
{
WDataSetPoints::VertexArray outVertices(
new WDataSetPoints::VertexArray::element_type() );
WDataSetPoints::ColorArray outColors(
new WDataSetPoints::ColorArray::element_type() );
size_t count = m_verts->size() / 3;
for( size_t index = 0; index < count; index++)
{
double x = m_verts->at( index * 3 );
double y = m_verts->at( index * 3 + 1 );
double z = m_verts->at( index * 3 + 2 );
bool isInsideSelection = x >= m_fromX->get() && x <= m_toX->get()
&& y >= m_fromY->get() && y <= m_toY->get()
&& z >= m_fromZ->get() && z <= m_toZ->get();
if( isInsideSelection != m_cutInsteadOfCrop->get() )
for( size_t item = 0; item < 3; item++ )
{
outVertices->push_back( m_verts->at( index * 3 + item ) );
outColors->push_back( m_colors->at( index * 3 + item ) );
}
m_progressStatus->increment( 1 );
}
if( outVertices->size() == 0 )
{
for( size_t item = 0; item < 3; item++ )
{
outVertices->push_back( 0 );
outColors->push_back( 0 );
}
}
boost::shared_ptr< WDataSetPoints > outputPoints(
new WDataSetPoints( outVertices, outColors ) );
return outputPoints;
}
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------
#ifndef WMPOINTSCROP_H
#define WMPOINTSCROP_H
#include <liblas/liblas.hpp>
#include <string>
#include <vector>
#include <fstream> // std::ifstream
#include <iostream> // std::cout
#include "core/kernel/WModule.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/WTriangleMesh.h"
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include "core/dataHandler/WDataSetPoints.h"
#include "../datastructures/octree/WOctree.h"
//!.Unnecessary imports
#include "core/common/WItemSelection.h"
#include "core/common/WItemSelector.h"
#include "core/kernel/WModuleOutputData.h"
#include <osg/Group>
#include <osg/Material>
#include <osg/StateAttribute>
#include "core/kernel/WKernel.h"
#include "core/common/exceptions/WFileNotFound.h"
#include "core/common/WColor.h"
#include "core/common/WPathHelper.h"
#include "core/common/WPropertyHelper.h"
#include "core/common/WItemSelectionItem.h"
#include "core/common/WItemSelectionItemTyped.h"
#include "core/graphicsEngine/WGEUtils.h"
#include "core/graphicsEngine/WGERequirement.h"
// forward declarations to reduce compile dependencies
template< class T > class WModuleInputData;
class WDataSetScalar;
class WGEManagedGroupNode;
/**
* Crops a point data set to a selection or cuts away a cube area.
* \ingroup modules
*/
class WMPointsCrop: public WModule
{
public:
/**
* Creates the module for drawing contour lines.
*/
WMPointsCrop();
/**
* Destroys this module.
*/
virtual ~WMPointsCrop();
/**
* Gives back the name of this module.
* \return the module's name.
*/
virtual const std::string getName() const;
/**
* Gives back a description of this module.
* \return description to module.
*/
virtual const std::string getDescription() const;
/**
* Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
* should never be initialized or modified in some other way. A simple new instance is required.
* \return the prototype used to create every module in OpenWalnut.
*/
virtual boost::shared_ptr< WModule > factory() const;
/**
* Get the icon for this module in XPM format.
* \return The icon.
*/
virtual const char** getXPMIcon() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
*/
virtual void moduleMain();
/**
*Initialize the connectors this module is using.
*/
virtual void connectors();
/**
* Initialize the properties for this module.
*/
virtual void properties();
/**
* Initialize requirements for this module.
*/
virtual void requirements();
private:
/**
* Initializes progress bar settings.
* \param steps Points count as reference to the progress bar.
*/
void setProgressSettings( size_t steps );
/**
* The OSG root node for this module. All other geodes or OSG nodes will be attached on this single node.
*/
osg::ref_ptr< WGEManagedGroupNode > m_rootNode;
/**
* Calculates the bounding box of the input point data set. Minimals and
* maximals of X/Y/Z are set.
*/
void initBoundingBox();
/**
* Returns a cropped data set corresponding to the selection. The selection is
* set by m_<from/to>_<X/Y/Z>. m_cutInsteadOfCrop determines whether to crop to
* a selection or to cut away a cube area.
* \return The cropped or cut point data set.
*/
boost::shared_ptr< WDataSetPoints > getCroppedPointSet();
/**
* WDataSetPoints data input (proposed for LiDAR data).
*/
boost::shared_ptr< WModuleInputData< WDataSetPoints > > m_input;
/**
* Processed point data with cut off outliers.
*/
boost::shared_ptr< WModuleOutputData< WDataSetPoints > > m_output;
/**
* Needed for recreating the geometry, incase when resolution changes.
*/
boost::shared_ptr< WCondition > m_propCondition;
/**
* Plugin progress status that is shared with the reader.
*/
boost::shared_ptr< WProgress > m_progressStatus;
/**
* Input point coordinates to crop.
*/
WDataSetPoints::VertexArray m_verts;
/**
* Colors of the input point data set that are also passed through.
*/
WDataSetPoints::ColorArray m_colors;
/**
* Minimal X value of the selection.
*/
WPropDouble m_fromX;
/**
* Maximal X value of the selection.
*/
WPropDouble m_toX;
/**
* Maximal Y value of the selection.
*/
WPropDouble m_fromY;
/**
* Minimal Y value of the selection.
*/
WPropDouble m_toY;
/**
* Minimal Z value of the selection.
*/
WPropDouble m_fromZ;
/**
* Maximal Z value of the selection.
*/
WPropDouble m_toZ;
/**
* Switch to cut away the selection instead of to crop the area.
*/
WPropBool m_cutInsteadOfCrop;
/**