Skip to content

Commit 3697804

Browse files
Merge pull request #18 from PauloCarvalhoRJ/SampleProximityHandling
Search for duplicate samples or samples too close to each other.
2 parents 721b144 + 5ec72c1 commit 3697804

File tree

10 files changed

+272
-260
lines changed

10 files changed

+272
-260
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
1+
# These files are kept by Qt Creator and does not actually belong to the source file set.
2+
GammaRay.pro.user*

GammaRay.pro

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ SOURCES += main.cpp\
117117
widgets/fileselectorwidget.cpp \
118118
scripting.cpp \
119119
gslib/gslibparams/gslibparvmodel.cpp \
120-
gslib/gslibparams/widgets/widgetgslibparvmodel.cpp
120+
gslib/gslibparams/widgets/widgetgslibparvmodel.cpp \
121+
spatialindex/spatialindexpoints.cpp
121122

122123
HEADERS += mainwindow.h \
123124
aboutdialog.h \
@@ -216,7 +217,8 @@ HEADERS += mainwindow.h \
216217
scripting.h \
217218
exprtk.hpp \
218219
gslib/gslibparams/gslibparvmodel.h \
219-
gslib/gslibparams/widgets/widgetgslibparvmodel.h
220+
gslib/gslibparams/widgets/widgetgslibparvmodel.h \
221+
spatialindex/spatialindexpoints.h
220222

221223
FORMS += mainwindow.ui \
222224
aboutdialog.ui \
@@ -263,10 +265,17 @@ FORMS += mainwindow.ui \
263265
widgets/fileselectorwidget.ui \
264266
gslib/gslibparams/widgets/widgetgslibparvmodel.ui
265267

268+
# The Boost include path.
269+
BOOST_INSTALL = $$(BOOST_ROOT)
270+
isEmpty(BOOST_INSTALL){
271+
error(BOOST_ROOT environment variable not defined.)
272+
}
273+
INCLUDEPATH += $$BOOST_INSTALL
274+
266275
# The application version
267276
# Don't forget to update the Util::importSettingsFromPreviousVersion() method to
268277
# enable the import of registry/user settings of previous versions.
269-
VERSION = 1.2
278+
VERSION = 1.2.1
270279

271280
# Define a preprocessor macro so we can get the application version in application code.
272281
DEFINES += APP_VERSION=\\\"$$VERSION\\\"

GammaRay.pro.user

Lines changed: 0 additions & 255 deletions
This file was deleted.

docs/GammaRayManual.docx

-891 Bytes
Binary file not shown.

mainwindow.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "gslib/gslibparametersdialog.h"
3333
#include "variogramanalysisdialog.h"
3434
#include "declusteringdialog.h"
35+
#include <QDesktopServices>
3536
#include <QInputDialog>
3637
#include <QLineEdit>
3738
#include "domain/variogrammodel.h"
@@ -44,6 +45,7 @@
4445
#include "bidistributionmodelingdialog.h"
4546
#include "valuespairsdialog.h"
4647
#include "indicatorkrigingdialog.h"
48+
#include "spatialindex/spatialindexpoints.h"
4749

4850
MainWindow::MainWindow(QWidget *parent) :
4951
QMainWindow(parent),
@@ -330,10 +332,12 @@ void MainWindow::onProjectContextMenu(const QPoint &mouse_location)
330332
}
331333
if( _right_clicked_file->getFileType() == "POINTSET" ){
332334
_projectContextMenu->addAction("Create estimation/simulation grid...", this, SLOT(onCreateGrid()));
335+
_projectContextMenu->addAction("Look for duplicate/close samples", this, SLOT(onLookForDuplicates()));
333336
}
334337
if( _right_clicked_file->getFileType() == "CARTESIANGRID" ){
335338
_projectContextMenu->addAction("Convert to point set", this, SLOT(onAddCoord()));
336339
}
340+
_projectContextMenu->addAction("Open with external program", this, SLOT(onEditWithExternalProgram()));
337341
}
338342
//build context menu for an attribute
339343
if ( index.isValid() && (static_cast<ProjectComponent*>( index.internalPointer() ))->isAttribute() ) {
@@ -1151,6 +1155,47 @@ void MainWindow::onCreateCategoryPDF()
11511155
vpd->show();
11521156
}
11531157

1158+
void MainWindow::onLookForDuplicates()
1159+
{
1160+
bool ok;
1161+
double tolerance = QInputDialog::getDouble(this, "Duplicate tolerance",
1162+
"Enter the location tolerance around the X,Y,Z coordinates:",
1163+
0.1, 0.0, 10.0, 3, &ok);
1164+
1165+
if(! ok ) return;
1166+
1167+
double distance = QInputDialog::getDouble(this, "Duplicate separation",
1168+
"Enter the distance between two points to be considered too close:",
1169+
0.001, 0.0, 1000.0, 3, &ok);
1170+
if( ok ){
1171+
PointSet* ps = (PointSet*)_right_clicked_file;
1172+
SpatialIndexPoints::fill( ps, tolerance );
1173+
uint totFileDataLines = ps->getDataLineCount();
1174+
uint headerLineCount = Util::getHeaderLineCount( ps->getPath() );
1175+
Application::instance()->logInfo( "=======BEGIN OF REPORT============" );
1176+
QStringList messages;
1177+
for( uint iFileDataLine = 0; iFileDataLine < totFileDataLines; ++iFileDataLine){
1178+
QList<uint> nearSamples = SpatialIndexPoints::getNearestWithin( iFileDataLine, 5, distance);
1179+
QList<uint>::iterator it = nearSamples.begin();
1180+
for(; it != nearSamples.end(); ++it){
1181+
messages.append( "Sample at line " + QString::number(iFileDataLine+1+headerLineCount) +
1182+
" is too close to sample at line " + QString::number(*it+1+headerLineCount) + "." );
1183+
}
1184+
}
1185+
//output the messages, since the distance is symmetrical (A->B == B->A),
1186+
//only half of the messages are necessary.
1187+
for( int i = 0; i < messages.count()/2; ++i){
1188+
Application::instance()->logInfo( messages[i] );
1189+
}
1190+
Application::instance()->logInfo( "=======END OF REPORT============" );
1191+
}
1192+
}
1193+
1194+
void MainWindow::onEditWithExternalProgram()
1195+
{
1196+
QDesktopServices::openUrl(QUrl( _right_clicked_file->getPath() ));
1197+
}
1198+
11541199
void MainWindow::createOrReviewVariogramModel(VariogramModel *vm)
11551200
{
11561201

mainwindow.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ private slots:
118118
void onCreateThresholdCDF();
119119
void onEdit();
120120
void onCreateCategoryPDF();
121+
void onLookForDuplicates();
122+
void onEditWithExternalProgram();
123+
121124
private:
122125
/**
123126
* This method is used to create (vm == nullptr) or review (vm != nullptr)

spatialindex/spatialindexpoints.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "spatialindexpoints.h"
2+
3+
#include <vector>
4+
#include <boost/geometry.hpp>
5+
#include <boost/geometry/index/rtree.hpp>
6+
7+
#include "domain/pointset.h"
8+
#include "domain/application.h"
9+
10+
namespace bg = boost::geometry;
11+
namespace bgi = boost::geometry::index;
12+
13+
typedef bg::model::point<double, 3, bg::cs::cartesian> Point3D;
14+
typedef bg::model::box<Point3D> Box;
15+
typedef std::pair<Box, size_t> Value;
16+
17+
// create the R* variant of the rtree
18+
bgi::rtree< Value, bgi::rstar<16> > rtree;
19+
20+
//the query pointset
21+
PointSet* pointset = nullptr;
22+
23+
//the GEO-EAS columns of the X, Y, Z variables of the point set file
24+
int iX;
25+
int iY;
26+
int iZ;
27+
28+
void setPointSet( PointSet* ps ){
29+
pointset = ps;
30+
//loads the PointSet data.
31+
ps->loadData();
32+
//get the GEO-EAS indexes -1 for the X, Y and Z coordinates
33+
iX = ps->getXindex() - 1;
34+
iY = ps->getYindex() - 1;
35+
iZ = ps->getZindex() - 1;
36+
}
37+
38+
SpatialIndexPoints::SpatialIndexPoints()
39+
{
40+
41+
}
42+
43+
void SpatialIndexPoints::fill(PointSet *ps, double tolerance)
44+
{
45+
//first clear the index.
46+
clear();
47+
48+
setPointSet( ps );
49+
50+
//for each data line...
51+
uint totlines = ps->getDataLineCount();
52+
for( uint iLine = 0; iLine < totlines; ++iLine){
53+
//...make a Point3D for the index
54+
double x = ps->data( iLine, iX );
55+
double y = ps->data( iLine, iY );
56+
double z = 0.0; //put 2D data in the z==0.0 plane
57+
if( iZ >= 0 )
58+
z = ps->data( iLine, iZ );
59+
//make a bounding box around the point.
60+
Box box( Point3D(x-tolerance, y-tolerance, z-tolerance),
61+
Point3D(x+tolerance, y+tolerance, z+tolerance));
62+
//insert the box representing the point into the spatial index.
63+
rtree.insert( std::make_pair(box, iLine) );
64+
}
65+
}
66+
67+
QList<uint> SpatialIndexPoints::getNearest(uint index, uint n)
68+
{
69+
QList<uint> result;
70+
71+
//get the location of the point.
72+
double x = pointset->data( index, iX );
73+
double y = pointset->data( index, iY );
74+
double z = 0.0; //put 2D data in the z==0.0 plane
75+
if( iZ >= 0 )
76+
z = pointset->data( index, iZ );
77+
78+
// find n nearest values to a point
79+
std::vector<Value> result_n;
80+
rtree.query(bgi::nearest(Point3D(x, y, z), n), std::back_inserter(result_n));
81+
82+
// collect the point indexes
83+
std::vector<Value>::iterator it = result_n.begin();
84+
for(; it != result_n.end(); ++it){
85+
//do not return itself
86+
if( index != (*it).second )
87+
result.push_back( (*it).second );
88+
}
89+
90+
//return the point indexes
91+
return result;
92+
}
93+
94+
QList<uint> SpatialIndexPoints::getNearestWithin(uint index, uint n, double distance )
95+
{
96+
QList<uint> result;
97+
98+
//get the location of the query point.
99+
double qx = pointset->data( index, iX );
100+
double qy = pointset->data( index, iY );
101+
double qz = 0.0; //put 2D data in the z==0.0 plane
102+
if( iZ >= 0 )
103+
qz = pointset->data( index, iZ );
104+
Point3D qPoint(qx, qy, qz);
105+
106+
//get the n-nearest points
107+
QList<uint> nearestSamples = SpatialIndexPoints::getNearest( index, n );
108+
109+
//test the distance to each of the n-nearest points
110+
QList<uint>::iterator it = nearestSamples.begin();
111+
for(; it != nearestSamples.end(); ++it){
112+
//get the location of a near point.
113+
uint nIndex = *it;
114+
double nx = pointset->data( nIndex, iX );
115+
double ny = pointset->data( nIndex, iY );
116+
double nz = 0.0; //put 2D data in the z==0.0 plane
117+
if( iZ >= 0 )
118+
nz = pointset->data( nIndex, iZ );
119+
//compute the distance between the query point and a nearest point
120+
double dist = boost::geometry::distance( qPoint, Point3D(nx, ny, nz) );
121+
if( dist < distance ){
122+
result.push_back( nIndex );
123+
}
124+
}
125+
return result;
126+
}
127+
128+
void SpatialIndexPoints::clear()
129+
{
130+
rtree.clear();
131+
pointset = nullptr;
132+
}

spatialindex/spatialindexpoints.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#ifndef SPATIALINDEX_H
2+
#define SPATIALINDEX_H
3+
4+
#include <QList>
5+
6+
class PointSet;
7+
8+
/**
9+
* This class exposes functionalities related to spatial indexes and queries with GammaRay objects.
10+
*/
11+
class SpatialIndexPoints
12+
{
13+
public:
14+
SpatialIndexPoints();
15+
16+
/** Fills the index with the PointSet points (bulk load).
17+
* It erases any previously indexed points.
18+
* @param tolerance Sets the size of the bouding boxes around each point.
19+
*/
20+
static void fill( PointSet* ps, double tolerance );
21+
22+
/**
23+
* Returns the indexes of the n-nearest points to the point given by its index.
24+
* The indexes are the point indexes (file data lines) of the PointSet used fill
25+
* the index.
26+
*/
27+
static QList<uint> getNearest( uint index, uint n );
28+
29+
/**
30+
* Returns the indexes of the n-nearest points within the diven distance
31+
* to the point given by its index. The indexes are the point indexes
32+
* (file data lines) of the PointSet used fill the index. May return
33+
* an empty list.
34+
* @param distance The distance the returned points must be within.
35+
*/
36+
static QList<uint> getNearestWithin(uint index, uint n, double distance);
37+
38+
/** Clears the spatial index. */
39+
static void clear();
40+
41+
};
42+
43+
#endif // SPATIALINDEX_H

util.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ void Util::importSettingsFromPreviousVersion()
665665
QSettings currentSettings;
666666
//The list of previous versions (order from latest to oldest version is advised)
667667
QStringList previousVersions;
668-
previousVersions << "1.1.0" << "1.0.1" << "1.0";
668+
previousVersions << "1.2" << "1.1.0" << "1.0.1" << "1.0";
669669
//Iterate through the list of previous versions
670670
QList<QString>::iterator itVersion = previousVersions.begin();
671671
for(; itVersion != previousVersions.end(); ++itVersion){
@@ -721,3 +721,32 @@ QString Util::getProgramInstallDir()
721721
return QString("/usr");
722722
#endif
723723
}
724+
725+
uint Util::getHeaderLineCount( QString file_path )
726+
{
727+
QFile file( file_path );
728+
file.open( QFile::ReadOnly | QFile::Text );
729+
QTextStream in(&file);
730+
int n_vars = 0;
731+
int var_count = 0;
732+
733+
for (int i = 0; !in.atEnd(); ++i)
734+
{
735+
//read file line by line
736+
QString line = in.readLine();
737+
738+
if( i == 0 ){} //first line is ignored
739+
else if( i == 1 ){ //second line is the number of variables
740+
n_vars = Util::getFirstNumber( line );
741+
} else if ( i > 1 && var_count < n_vars ){ //the variables names
742+
++var_count;
743+
} else { //begin lines containing data
744+
file.close();
745+
return i;
746+
}
747+
}
748+
//it is not supposed to reach the end of file.
749+
Application::instance()->logWarn("WARNING: Util::getHeaderLineCount(): unexpected reach EOF.");
750+
file.close();
751+
return 0;
752+
}

util.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ class Util
228228
* Returns the PROGRAMFILES environmental variable in Windows or /usr otherwise.
229229
*/
230230
static QString getProgramInstallDir();
231+
232+
/**
233+
* Returns the number of file lines that make up the header of the given GEO-EAS file.
234+
*/
235+
static uint getHeaderLineCount( QString file_path );
231236
};
232237

233238
#endif // UTIL_H

0 commit comments

Comments
 (0)