Commit 70f54ec4 authored by Andreas Schwarzkopf's avatar Andreas Schwarzkopf

[FIX 371] Fixing somen memory leaks and few feature improvements

Main changes:
  - Multithreading for allocating kd-trees at 8 threads.
  - Fixed memory leak when kd-tree is destroyed. Not all memory was freed previously.
  - Added few point transformation features regarding automatical color adjustment.
  - Improved speed of the point file lading feature.
  - Fixed ReadLAS module
      - Previously it could only use greyscale color channel.
      - Made X/Y-sliders more intuitive
parent 8df7397f
......@@ -36,6 +36,8 @@ WPointSaver::WPointSaver()
m_hasGroupInfo = false;
m_filePath = new stringstream();
m_containsData = false;
m_currentInputNumberLine.reserve( 0 );
m_currentInputNumberLine.resize( 0 );
}
WPointSaver::~WPointSaver()
......@@ -98,31 +100,6 @@ void WPointSaver::setFilePath( const char* path )
*m_filePath << path;
}
double WPointSaver::parseDouble( vector<char> charVector )
{
stringstream numberStream;
for( size_t index = 0; index < charVector.size(); index++ )
numberStream << charVector[index];
const string numberString = numberStream.str();
istringstream stream( numberString );
stream.precision( 16 );
double number;
stream >> number;
return number;
}
size_t WPointSaver::parseSizeT( vector<char> charVector )
{
stringstream numberStream;
for( size_t index = 0; index < charVector.size(); index++ )
numberStream << charVector[index];
const string numberString = numberStream.str();
istringstream stream( numberString );
size_t number;
stream >> number;
return number;
}
bool WPointSaver::containsData()
{
return m_containsData;
......@@ -186,21 +163,40 @@ bool WPointSaver::load()
ifstream myfile( path );
while( getline( myfile, line ) )
{
if( ( m_verts->size() / 3 ) % 50000 == 0 )
if( ( m_verts->size() / 3 ) % 100000 == 0 )
cout << "WPointSaver::load() - Current point count: " << m_verts->size() / 3 << endl;
vector<vector<char> > signs = fetchNumberCharsFromLine( line );
if( signs.size() == variablesPerLine )
fetchNumberCharsFromLine( line );
if( m_currentInputNumberLine.size() == variablesPerLine
|| m_currentInputNumberLine.size() == variablesPerLine - 2 )
{
m_containsData = true;
for( size_t dimension = 0; dimension < 3; dimension++ )
m_verts->push_back( parseDouble( signs[dimension] ) );
for( size_t color = 0; color < 3; color++ )
m_colors->push_back( parseDouble( signs[color + 3] ) );
if( m_hasGroupInfo )
m_groups->push_back( parseSizeT( signs[6] ) );
{
m_verts->push_back( 0.0 );
*m_currentInputNumberLine[dimension] >> m_verts->at( m_verts->size() - 1 );
m_colors->push_back( 0.0 );
}
*m_currentInputNumberLine[3] >> m_colors->at( m_colors->size() - 3 );
for( size_t colorChannel = 1; colorChannel < 3; colorChannel++ )
if( m_currentInputNumberLine.size() == variablesPerLine )
{
*m_currentInputNumberLine[3 + colorChannel]
>> m_colors->at( m_colors->size() - 3 + colorChannel );
}
else
{
m_colors->at( m_colors->size() - 3 + colorChannel )
= m_colors->at( m_colors->size() - 3 );
}
if( m_verts->size() > 0 && m_verts->size() % 100000 == 0 )
cout << "Loading points. Current size: " << m_verts->size() << endl;
if( m_hasGroupInfo )
{
m_groups->push_back( 0.0 );
*m_currentInputNumberLine[ m_currentInputNumberLine.size() - 1 ]
>> m_groups->at( m_groups->size() - 1 );
}
}
}
myfile.close();
......@@ -256,9 +252,8 @@ bool WPointSaver::isNumberChar( const char sign )
return sign == '.' || sign == '-' || sign == 'e' || sign == 'E';
}
vector<vector<char> > WPointSaver::fetchNumberCharsFromLine( string line )
void WPointSaver::fetchNumberCharsFromLine( string line )
{
vector<vector<char> > output;
size_t vectorSize = 0;
size_t length = line.length();
const char* text = line.c_str();
......@@ -269,19 +264,21 @@ vector<vector<char> > WPointSaver::fetchNumberCharsFromLine( string line )
bool isNumberSign = WPointSaver::isNumberChar( text[index] );
if( !wasNumberSign && isNumberSign )
{
output.reserve( vectorSize + 1 );
output.resize( vectorSize + 1 );
vector<char> newVector;
output[vectorSize] = newVector;
vectorSize++;
if( vectorSize > m_currentInputNumberLine.size() )
m_currentInputNumberLine.push_back( new stringstream() );
m_currentInputNumberLine[vectorSize - 1]->clear();
}
if( isNumberSign )
{
output[vectorSize - 1].push_back( text[index] );
}
*m_currentInputNumberLine[vectorSize - 1] << text[index];
wasNumberSign = isNumberSign;
}
return output;
if( vectorSize < m_currentInputNumberLine.size() )
{
m_currentInputNumberLine.reserve( vectorSize );
m_currentInputNumberLine.resize( vectorSize );
}
}
const char* WPointSaver::EXTENSION_WDATASETPOINTS = ".points";
......
......@@ -134,20 +134,6 @@ public:
*/
static bool isNumberChar( const char sign );
/**
* Parses a double number from a characer sequence.
* \param charVector Character sequence to be parsed.
* \return parsed double number.
*/
static double parseDouble( vector<char> charVector );
/**
* Parses a size_t number from a characer sequence.
* \param charVector Character sequence to be parsed.
* \return parsed size_t number.
*/
static size_t parseSizeT( vector<char> charVector );
/**
* Tests whether a path ends with a character sequence. Useful to test whether file
* names correspond to an extension.
......@@ -182,7 +168,7 @@ private:
* \param line Line to be separated
* \return Set of several numbers that further have to be parsed.
*/
vector<vector<char> > fetchNumberCharsFromLine( string line );
void fetchNumberCharsFromLine( string line );
/**
......@@ -224,6 +210,11 @@ private:
* Extension for WDataSetPointsGrouped point data files.
*/
static const char* EXTENSION_WDATASETPOINTSGROUPED;
/**
* Current row of read in numbers from a file that has further to be parsed
*/
vector<stringstream*> m_currentInputNumberLine;
};
#endif // WPOINTSAVER_H
......@@ -37,6 +37,7 @@ WKdTreeND::WKdTreeND()
m_allowDoubles = true;
m_points = new vector<WKdPointND* >();
m_parentSplittingDimension = 3;
m_hierarchyLevel = 0;
m_higherChild = 0;
m_lowerChild = 0;
}
......@@ -49,6 +50,7 @@ WKdTreeND::WKdTreeND( size_t dimensions )
m_allowDoubles = true;
m_points = new vector<WKdPointND* >();
m_parentSplittingDimension = dimensions;
m_hierarchyLevel = 0;
m_higherChild = 0;
m_lowerChild = 0;
}
......@@ -287,8 +289,21 @@ void WKdTreeND::addPointsToChildren( vector<WKdPointND* >* newPoints )
higherPoints->push_back( newPoint );
}
}
m_lowerChild->add( lowerPoints );
m_higherChild->add( higherPoints );
size_t hierarchyLevel = m_hierarchyLevel;
if( hierarchyLevel > 2 )
{
m_lowerChild->add( lowerPoints );
m_higherChild->add( higherPoints );
}
else
{
boost::thread lowerChildThread( &WKdTreeND::add, m_lowerChild, lowerPoints );
boost::thread higherChildThread( &WKdTreeND::add, m_higherChild, higherPoints );
lowerChildThread.join();
higherChildThread.join();
}
delete lowerPoints;
delete higherPoints;
}
......@@ -445,4 +460,6 @@ void WKdTreeND::initSubNodes()
{
m_lowerChild->m_parentSplittingDimension = m_splittingDimension;
m_higherChild->m_parentSplittingDimension = m_splittingDimension;
m_lowerChild->m_hierarchyLevel = m_hierarchyLevel + 1;
m_higherChild->m_hierarchyLevel = m_hierarchyLevel + 1;
}
......@@ -28,6 +28,7 @@
#include <vector>
#include <algorithm>
#include "WKdPointND.h"
#include <boost/thread.hpp>
using std::vector;
using std::size_t;
......@@ -228,6 +229,11 @@ private:
*/
size_t m_parentSplittingDimension; //TODO(aschwarzkopf): ggf. wegschmeißen
/**
* Herarchy level of the kd-tree node. It is used for multithreading regulation.
*/
size_t m_hierarchyLevel;
//TODO(aschwarzkopf): Ggf. Sinn: Nicht bis ins Letzte unterteilen, ggf. nur über einem Threshold
/**
* The kd tree node child which is on the lower position across the splitting
......
......@@ -53,6 +53,27 @@ WElevationImageOutliner::~WElevationImageOutliner()
{
}
double WElevationImageOutliner::getSurfaceArea2D( WQuadTree* quadTree )
{
return calculateSurfaceForNode2D( quadTree->getRootNode(), quadTree );
}
double WElevationImageOutliner::calculateSurfaceForNode2D( WQuadNode* node, WQuadTree* quadTree )
{
if( node->getRadius() <= quadTree->getDetailLevel() )
{
return node->getRadius() * node->getRadius() * 4;
}
else
{
double area = 0.0;
for ( size_t child = 0; child < 4; child++ )
if ( node->getChild( child ) != 0 )
area += calculateSurfaceForNode2D( node->getChild( child ), quadTree );
return area;
}
}
void WElevationImageOutliner::importElevationImage( WQuadTree* quadTree, size_t elevImageMode )
{
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
......
......@@ -90,6 +90,22 @@ public:
*/
virtual ~WElevationImageOutliner();
/**
* Returns the 2D surface area in m^2. Area = [node count] * [node radius]^2 * 4.
* \param quadtree Quadtree to calculate the 2D m^2 area for.
* \return 2D surface area in m^2.
*/
double getSurfaceArea2D( WQuadTree* quadtree );
/**
* Calculates quadtree node surface for a node of a quadtree.
* Area = [node count] * [node radius]^2 * 4.
* \param node Quadtree node to calculate childtens node area for.
* \param quadTree Quadtree where node area in m^2should be calculated.
* \return 2D surface area in m^2.
*/
double calculateSurfaceForNode2D( WQuadNode* node, WQuadTree* quadTree );
/**
* Sets the elevation image export settings.
* \param minElevImageZ The elevation height that is mapped to the black color.
......
......@@ -101,12 +101,13 @@ void WMElevationImageExport::properties()
m_yMax = m_infoProperties->addProperty( "Y max.: ", "Maximal y coordinate of all input points.", 0.0 );
m_zMin = m_infoProperties->addProperty( "Z min.: ", "Minimal z coordinate of all input points.", 0.0 );
m_zMax = m_infoProperties->addProperty( "Z max.: ", "Maximal z coordinate of all input points.", 0.0 );
m_infoSurfaceArea2D = m_infoProperties->addProperty( "Area m²: ", "Surface area in m².", 0.0 );
// ---> Put the code for your properties here. See "src/modules/template/" for an extensively documented example.
m_detailDepth = m_properties->addProperty( "Detail Depth 2^n m: ", "Resulting 2^n meters detail "
"depth for the octree search tree.", 0, m_propCondition );
m_detailDepth->setMin( -3 );
m_detailDepth->setMin( -4 );
m_detailDepth->setMax( 4 );
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 );
......@@ -179,12 +180,11 @@ void WMElevationImageExport::moduleMain()
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++)
{
float x = verts->at( vertex*3 );
float y = verts->at( vertex*3+1 );
float z = verts->at( vertex*3+2 );
double x = verts->at( vertex*3 );
double y = verts->at( vertex*3+1 );
double z = verts->at( vertex*3+2 );
m_elevationImage->registerPoint( x, y, z );
m_progressStatus->increment( 1 );
}
......@@ -212,9 +212,13 @@ void WMElevationImageExport::moduleMain()
image->highlightBuildingGroups( m_pointGroups->getData(), m_elevationImage );
WBmpSaver::saveImage( image, m_elevationImageExportablePath->get().c_str() );
delete image;
}
m_infoSurfaceArea2D->set( m_elevationImageOutliner->getSurfaceArea2D( m_elevationImage ) );
m_elevationImageDisplay->updateData( m_elevationImageOutliner->getOutputMesh() );
m_exportTriggerProp->set( WPVBaseTypes::PV_TRIGGER_READY, true );
delete m_elevationImage;
delete m_elevationImageOutliner;
m_progressStatus->finish();
}
......
......@@ -207,6 +207,12 @@ private:
*/
WPropDouble m_zMax;
/**
* Info field for surface area in m^2 of the elevation image.
* Area = [node count] * [node radius]^2 * 4.
*/
WPropDouble m_infoSurfaceArea2D;
/**
* Determines the resolution of the smallest octree nodes in 2^n meters
*/
......
......@@ -75,6 +75,9 @@ template< class T > class WModuleInputData;
class WDataSetScalar;
class WGEManagedGroupNode;
using std::numeric_limits;
/**
* Transforms a point set: Available options: Cropping, stretching, translation and
* rotation.
......@@ -118,6 +121,55 @@ public:
*/
virtual const char** getXPMIcon() const;
/**
* Color adjustment reference constant - Automatical color adjustment.
*/
static const size_t M_COLOR_AUTO;
/**
* Color adjustment reference constant - Automatical color adjustment with the offset
* of 0.
*/
static const size_t M_COLOR_AUTO_ONLY_CONTRAST;
/**
* Color adjustment reference constant - Manual color adjustment.
*/
static const size_t M_COLOR_MANUAL;
/**
* Color adjustment reference constant - Editing colors manually with the same
* aspect ratio between all colors.
*/
static const size_t M_COLOR_MANUAL_JOINED;
/**
* Color adjustment reference constant - manual color adjustment with all enterable
* numbers (without useing sliders).
*/
static const size_t M_COLOR_MANUAL_UNBOUNDED;
/**
* Color adjustment reference constant - manual color adjustment with all enterable
* numbers (without useing sliders). Aspect ratio between colors is kept.
*/
static const size_t M_COLOR_MANUAL_UNBOUNDED_JOINED;
/**
* Color display mode - Colored.
*/
static const size_t M_COLOR_MODE_COLORED;
/**
* Color display mode - Perceptional proportions of Red=30%, Green=59% and Blue=11%.
*/
static const size_t M_COLOR_MODE_GREYSCALE_PERCEPTIONAL;
/**
* Color display mode - Proportional proportions of Red=33%, Green=33% and Blue=33%.
*/
static const size_t M_COLOR_MODE_GREYSCALE_PROPORTIONAL;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
......@@ -186,6 +238,11 @@ private:
*/
void onFileSave();
/**
* Method that handles color intensity correction.
*/
void onColorIntensityCorrect();
/**
* WDataSetPoints data input (proposed for LiDAR data).
*/
......@@ -268,39 +325,29 @@ private:
vector<WPropDouble> m_infoBoundingBoxMax;
/**
* Options for surface features.
* Information about minimal color channel intensity values.
*/
WPropGroup m_pointsCropGroup;
vector<WPropDouble> m_infoColorMin;
/**
* Minimal X value of the selection.
* Information about maximal color channel intensity values.
*/
WPropDouble m_fromX;
vector<WPropDouble> m_infoColorMax;
/**
* Maximal X value of the selection.
*/
WPropDouble m_toX;
/**
* Maximal Y value of the selection.
*/
WPropDouble m_fromY;
/**
* Minimal Y value of the selection.
* Options for surface features.
*/
WPropDouble m_toY;
WPropGroup m_pointsCropGroup;
/**
* Minimal Z value of the selection.
* Minimal Coordinate value of the selection.
*/
WPropDouble m_fromZ;
vector<WPropDouble> m_fromCoord;
/**
* Maximal Z value of the selection.
* Maximal Coordinate value of the selection.
*/
WPropDouble m_toZ;
vector<WPropDouble> m_toCoord;
/**
* Switch to cut away the selection instead of to crop the area.
......@@ -331,19 +378,9 @@ private:
WPropGroup m_translatePointsGroup;
/**
* X coordinate translation offset.
*/
WPropDouble m_translateX;
/**
* Y coordinate translation offset.
* Coordinate translation offset.
*/
WPropDouble m_translateY;
/**
* Z coordinate translation offset.
*/
WPropDouble m_translateZ;
vector<WPropDouble> m_translationOffset;
/**
* Group that multiplies each coordinate by a factor.
......@@ -351,19 +388,9 @@ private:
WPropGroup m_groupMultiplyPoints;
/**
* Each X coordinate is multiplied by this value
*/
WPropDouble m_factorX;
/**
* Each Y coordinate is multiplied by this value
*/
WPropDouble m_factorY;
/**
* Each Z coordinate is multiplied by this value
* Each coordinate is multiplied by this factor.
*/
WPropDouble m_factorZ;
vector<WPropDouble> m_coordFactor;
/**
* Rotation options.
......@@ -386,19 +413,9 @@ private:
WPropDouble m_rotation3AngleXZ;
/**
* Rotation anchor on the X coordinate.
* Rotation anchor coordinate.
*/
WPropDouble m_rotationAnchorX;
/**
* Rotation anchor on the Y coordinate.
*/
WPropDouble m_rotationAnchorY;
/**
* Rotation anchor on the Z coordinate.
*/
WPropDouble m_rotationAnchorZ;
vector<WPropDouble> m_rotationAnchor;
/**
* Color equalizer settings group.
......@@ -406,34 +423,35 @@ private:
WPropGroup m_groupColorEqualizer;
/**
* Red contrast - Factor that is applied before adding the red offset.
*/
WPropDouble m_contrastRed;
/**
* Green contrast - Factor that is applied before adding the green offset.
* Color contrast - Factor that is applied before adding the green offset.
* Colors are sorted in order: Red, green, blue
*/
WPropDouble m_contrastGreen;
vector<WPropDouble> m_contrast;
/**
* Blue contrast - Factor that is applied before adding the blue offset.
* Color offset.- Offset that is added after applying the red factor.
* Colors are sorted in order: Red, green, blue
*/
WPropDouble m_contrastBlue;
vector<WPropDouble> m_colorOffset;
/**
* Red offset.- Offset that is added after applying the red factor.
* Type of the color adjustment:
* M_COLOR_AUTO = 0;
* M_COLOR_AUTO_ONLY_CONTRAST = 1;
* M_COLOR_MANUAL = 2;
* M_COLOR_MANUAL_JOINED = 3;
* M_COLOR_MANUAL_UNBOUNDED = 4;
* M_COLOR_MANUAL_UNBOUNDED_JOINED = 5;
*/
WPropDouble m_offsetRed;
WPropSelection m_colorAdjustmentType;
/**
* Green offset.- Offset that is added after applying the green factor.
* Color modes:
* M_COLOR_MODE_COLORED = 0 (Usual separated color channels).
* M_COLOR_MODE_GREYSCALE_PERCEPTIONAL = 1 (Red=30%, Green=59% and Blue=11%).
* M_COLOR_MODE_GREYSCALE_PROPORTIONAL = 2 (Red=33%, Green=33% and Blue=33%).
*/
WPropDouble m_OffsetGreen;
/**
* Blue offset.- Offset that is added after applying the blue factor.
*/
WPropDouble m_offsetBlue;
WPropSelection m_colorModeType;
/**
* Color equalizer settings group.
......@@ -479,34 +497,24 @@ private:
WPointSubtactionHelper m_pointSubtraction;
/**
* Minimal X coordinate of input points.
*/
double m_minX;
/**
* Maximal X coordinate of input points.
*/
double m_maxX;
/**
* Minimal Y coordinate of input points.
* Minimal coordinate of input points.
*/
double m_minY;
vector<double> m_minCoord;
/**
* Maximal Y coordinate of input points.
* Maximal coordinate of input points.
*/
double m_maxY;
vector<double> m_maxCoord;
/**
* Minimal Z coordinate of input points.
* Minimal Color channel intensity.