UltraScan III
us_noise.cpp
Go to the documentation of this file.
1 
3 #include "us_noise.h"
4 #include "us_constants.h"
5 #include "us_settings.h"
6 #include "us_util.h"
7 
8 #define isNan(a) (a!=a)
9 
10 // constructor - initialize empty
12 {
13  type = TI;
14  description = "New Noise";
15  noiseGUID = "";
16  modelGUID = "";
17  minradius = 0.0;
18  maxradius = 0.0;
19  count = 0;
20  values.clear();
21 }
22 
23 // equality operator
24 bool US_Noise::operator== ( const US_Noise& n ) const
25 {
26  if ( type != n.type ) return false;
27  if ( description != n.description ) return false;
28  if ( noiseGUID != n.noiseGUID ) return false;
29  if ( modelGUID != n.modelGUID ) return false;
30  if ( minradius != n.minradius ) return false;
31  if ( maxradius != n.maxradius ) return false;
32  if ( values.size() != n.values.size() ) return false;
33 
34  for ( int ii = 0; ii < values.size(); ii++ )
35  if ( values[ ii ] != n.values[ ii ] ) return false;
36 
37  return true;
38 }
39 
40 // load noise from db or local disk
41 int US_Noise::load( bool db_access, const QString& guid, US_DB2* db )
42 {
43  if ( db_access ) return load_db ( guid, db );
44  else return load_disk( guid );
45 }
46 
47 // load noise from db
48 int US_Noise::load( const QString& id, US_DB2* db )
49 {
50  QStringList q;
51 
52  q << "get_noise_info" << id;
53  db->query( q );
54 
55  if ( db->lastErrno() != US_DB2::OK ) return db->lastErrno();
56 
57  db->next();
58  QByteArray contents = db->value( 5 ).toString().toAscii();
59 
60  QXmlStreamReader xml( contents );
61 
62  return load_stream( xml );
63 }
64 
65 // load noise from local disk
66 int US_Noise::load( const QString& filename )
67 {
68  QFile file( filename );
69 
70  if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text) )
71  {
72  qDebug() << "Cannot open file for reading: " << filename;
73  return -1;
74  }
75 
76  QXmlStreamReader xml( &file );
77 
78  return load_stream( xml );
79 }
80 
81 // load noise from an XML stream
82 int US_Noise::load_stream( QXmlStreamReader& xml )
83 {
84  QXmlStreamAttributes a;
85  bool read_next = true;
86  QString typen = "ti";
87 
88  while ( ! xml.atEnd() )
89  {
90  if ( read_next ) xml.readNext();
91  read_next = true;
92 
93  if ( xml.isStartElement() )
94  {
95  if ( xml.name() == "noise" )
96  {
97  a = xml.attributes();
98 
99  typen = a.value( "type" ).toString();
100  type = typen.compare( "ti" ) == 0 ? TI : RI;
101 
102  description = a.value( "description" ).toString();
103  noiseGUID = a.value( "noiseGUID" ).toString();
104  modelGUID = a.value( "modelGUID" ).toString();
105  minradius = a.value( "minradius" ).toString().toDouble();
106  maxradius = a.value( "maxradius" ).toString().toDouble();
107  values.clear();
108  }
109 
110  else if ( xml.name() == "d" )
111  {
112  a = xml.attributes();
113 
114  values << a.value( "v" ).toString().toDouble();
115  }
116  }
117  }
118 
119  count = values.size();
120 //qDebug() << "NOI: ldTemp: count" << count;
121  if ( US_Settings::us_debug() > 2 )
122  debug();
123 
124  return US_DB2::OK;
125 }
126 
127 // write noise to db or local disk
128 int US_Noise::write( bool db_access, const QString& filename, US_DB2* db )
129 {
130  if ( db_access ) return write( db );
131  else return write( filename );
132 }
133 
134 // write noise to db
136 {
137  // Create the noise xml file in a string
138  QByteArray temp_contents;
139  QXmlStreamWriter xml( &temp_contents );
140  write_stream( xml );
141 
142  QByteArray contents;
143  QStringList q;
144 
145  // Get type and model IDD
146  QString typen = ( type == TI ) ? "ti_noise" : "ri_noise";
147 
148  q << "get_modelID" << modelGUID;
149  db->query( q );
150  db->next();
151  QString modelID = db->value( 0 ).toString();
152 
153  // Encapsulate the XML contents
154  db->mysqlEscapeString( contents, temp_contents, temp_contents.size() );
155 
156  // Determine the edit ID
157  QString invID = QString::number( US_Settings::us_inv_ID() );
158  QString editID = "0";
159  q.clear();
160  q << "get_model_desc" << invID;
161  db->query( q );
162  while( db->next() )
163  {
164  if ( db->value( 0 ).toString() == modelID )
165  {
166  editID = db->value( 6 ).toString();
167  break;
168  }
169  }
170 
171  // Generate a noise guid if necessary
172  // The guid may be valid from a disk read, but is not in the DB
173  if ( noiseGUID.size() != 36 ) noiseGUID = US_Util::new_guid();
174 
175  q.clear();
176  q << "get_noiseID" << noiseGUID;
177 
178  db->query( q );
179 
180  q.clear();
181 
182  if ( db->lastErrno() != US_DB2::OK )
183  {
184  q << "new_noise" << noiseGUID << editID << modelID << modelGUID
185  << typen << description << contents;
186  message = QObject::tr( "created" );
187 //qDebug() << "get_noiseID stat GUID" << db->lastErrno() << noiseGUID;
188  }
189  else
190  {
191  db->next();
192  QString noiseID = db->value( 0 ).toString();
193  q << "update_noise" << noiseID << noiseGUID << editID << modelID
194  << modelGUID << typen << description << contents;
195  message = QObject::tr( "updated" );
196 //qDebug() << "get_noiseID ID GUID" << noiseID << noiseGUID;
197  }
198 
199  return db->statusQuery( q );
200 //int updstat = db->statusQuery( q );
201 //qDebug() << "new/update_noise stat" << updstat;
202 //return updstat;
203 }
204 
205 // write noise to local disk
206 int US_Noise::write( const QString& filename )
207 {
208  QFile file( filename );
209 
210  if ( ! file.open( QIODevice::WriteOnly | QIODevice::Text) )
211  return US_DB2::ERROR;
212 
213  QXmlStreamWriter xml( &file );
214  write_stream( xml );
215  file.close();
216 
217  return US_DB2::OK;
218 }
219 
220 // apply noise to EditedData by add/subtract noise values from readings
221 int US_Noise::apply_to_data( US_DataIO::EditedData& editdata, bool remove )
222 {
223  int rCount = editdata.pointCount(); // readings count
224  int sCount = editdata.scanCount(); // scan count
225  int ii;
226  int jj;
227  double vnoise;
228  double applyf = remove ? -1.0 : 1.0; // apply factor
229  count = values.size();
230 
231  if ( count == 0 )
232  {
233  message = QObject::tr( "No noise applied, since its count is zero" );
234  return 1;
235  }
236 
237  if ( type == TI )
238  { // Time-invariant: subtract same value all scans at reading position
239 
240  if ( count != rCount )
241  {
242  message = QObject::tr( "Noise count does not equal data readings count" );
243  return -1;
244  }
245 
246  for ( jj = 0; jj < rCount; jj++ )
247  { // get constant noise value for each reading and apply to scans
248  vnoise = ( values[ jj ] * applyf );
249 
250  for ( ii = 0; ii < sCount; ii++ )
251  { // apply to all scans at reading position
252  editdata.scanData[ ii ].rvalues[ jj ] += vnoise;
253  }
254  }
255  }
256 
257  else
258  { // Radially-invariant: subtract same value all readings at scan position
259 
260  if ( count != sCount )
261  {
262  message = QObject::tr( "Noise count does not equal data scan count" );
263  return -2;
264  }
265 
266  for ( ii = 0; ii < sCount; ii++ )
267  { // get constant noise value for each scan and apply to readings
268  vnoise = ( values[ ii ] * applyf );
269 
270  for ( jj = 0; jj < rCount; jj++ )
271  { // apply to all readings at scan position
272  editdata.scanData[ ii ].rvalues[ jj ] += vnoise;
273  }
274  }
275  }
276 
277  return 0;
278 }
279 
280 // remove/add noise vector from/to edited data
282  US_Noise* noise, bool remove )
283 {
284  if ( noise != 0 )
285  {
286  return noise->apply_to_data( editdata, remove );
287  }
288 
289  else
290  {
291  return 1;
292  }
293 }
294 
295 // test noise file path and create directory if need be
296 bool US_Noise::noise_path( QString& path )
297 {
298  QDir dir;
299  path = US_Settings::dataDir() + "/noises";
300 
301  if ( ! dir.exists( path ) )
302  {
303  if ( ! dir.mkpath( path ) )
304  {
305  return false;
306  }
307  }
308 
309  return true;
310 }
311 
312 // load noise that matches guid from disk
313 int US_Noise::load_disk( const QString& guid )
314 {
315  int error = US_DB2::ERROR; // Error by default
316 
317  QString path;
318 
319  if ( ! noise_path( path ) )
320  {
321  message = QObject::tr ( "Could not create noises directory" );
322  return error;
323  }
324 
325  QDir f( path );
326  QStringList filter( "N*.xml" );
327  QStringList names = f.entryList( filter, QDir::Files, QDir::Name );
328  QString filename;
329  bool found = false;
330 
331  for ( int ii = 0; ii < names.size(); ii++ )
332  {
333  filename = path + "/" + names[ ii ];
334  QFile file( filename );
335 
336  if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text) ) continue;
337 
338  QXmlStreamReader xml( &file );
339 
340  while ( ! xml.atEnd() )
341  {
342  xml.readNext();
343 
344  if ( xml.isStartElement() )
345  {
346  if ( xml.name() == "noise" )
347  {
348  QXmlStreamAttributes a = xml.attributes();
349 
350  if ( a.value( "noiseGUID" ).toString() == guid ) found = true;
351  break;
352  }
353  }
354  }
355 
356  file.close();
357 
358  if ( found ) return load( filename );
359  }
360 
361  qDebug() << "Could not find noise GUID";
362  message = QObject::tr ( "Could not find noise guid" );
363  return error;
364 }
365 
366 // load noise that matches guid from db
367 int US_Noise::load_db( const QString& guid, US_DB2* db )
368 {
369  QStringList q;
370 
371  q << "get_noiseID" << guid;
372  db->query( q );
373 
374  if ( db->lastErrno() != US_DB2::OK ) return db->lastErrno();
375 
376  db->next();
377  QString id = db->value( 0 ).toString();
378  return load( id, db );
379 }
380 
381 // write noise to an XML stream
382 void US_Noise::write_stream( QXmlStreamWriter& xml )
383 {
384  QString typen( "ti" );
385 
386  if ( type == RI )
387  typen = QString( "ri" );
388 
389  //file.open();// QIODevice::WriteOnly | QIODevice::Text );
390  //QXmlStreamWriter xml( &file );
391  xml.setAutoFormatting( true );
392 
393  xml.writeStartDocument();
394  xml.writeDTD ( "<!DOCTYPE US_Noise>" );
395  xml.writeStartElement( "NoiseData" );
396  xml.writeAttribute ( "version", "1.0" );
397 
398  xml.writeStartElement( "noise" );
399  xml.writeAttribute ( "type", typen );
400  xml.writeAttribute ( "description", description );
401  xml.writeAttribute ( "modelGUID", modelGUID );
402  xml.writeAttribute ( "noiseGUID", noiseGUID );
403 
404  if ( type == TI )
405  {
406  xml.writeAttribute ( "minradius", QString::number( minradius ) );
407  xml.writeAttribute ( "maxradius", QString::number( maxradius ) );
408  }
409 
410  // Write values
411  for ( int ii = 0; ii < values.size(); ii++ )
412  {
413  xml.writeStartElement( "d" );
414 
415  xml.writeAttribute( "v", QString::number( values[ ii ] ) );
416 
417  xml.writeEndElement(); // data value
418  }
419 
420  xml.writeEndElement(); // noise
421  xml.writeEndElement(); // NoiseData
422  xml.writeEndDocument();
423 //qDebug() << " wr_stream count" << values.size();
424 }
425 
426 // output debug prints
427 void US_Noise::debug( void )
428 {
429  QString typen( "no" );
430  typen = ( type == RI ) ? QString( "RI" ) : typen;
431  typen = ( type == TI ) ? QString( "TI" ) : typen;
432 
433  qDebug() << "type" << (int)type << typen;
434  qDebug() << "desc" << description;
435  qDebug() << "model guid" << modelGUID;
436  qDebug() << "noise guid" << noiseGUID;;
437  qDebug() << "values size" << values.size();
438 
439  for ( int ii = 0; ii < values.size(); ii++ )
440  {
441  qDebug() << " v[" << ii << "]" << values[ ii ];
442  }
443 }
444 
445 // sum second noise into this vector
446 bool US_Noise::sum_noise( US_Noise noise2, bool always_sum )
447 {
448  bool ok = true;
449  bool match = true;
450 
451  if ( type != noise2.type )
452  ok = false; // cannot sum if noises are different types
453 
454  else
455  { // determine if they match in count and any radius range
456  double difflo = qAbs( minradius - noise2.minradius );
457  double diffhi = qAbs( maxradius - noise2.maxradius );
458  if ( count != noise2.count ||
459  ( type == TI && ( difflo > 0.0001 || diffhi > 0.0001 ) ) )
460  {
461  match = false;
462 qDebug() << "SM-NOI: difflo diffhi" << difflo << diffhi;
463  }
464  }
465 
466  if ( match )
467  { // if they match, simply sum vector values;
468  for ( int ii = 0; ii < values.size(); ii++ )
469  {
470  values[ ii ] += noise2.values[ ii ];
471 if(isNan(values[ii]))
472  qDebug() << "SM-NOI: ii" << ii << "noi o i" << values[ii] << noise2.values[ii];
473  }
474  }
475 
476  else if ( always_sum )
477  { // otherwise, we may need to interpolate or only sum a portion
478 
479  if ( type == RI )
480  { // for radially-invariant, just sum for minimum count
481  int mcount = qMin( count, noise2.count );
482 
483  for ( int ii = 0; ii < mcount; ii++ )
484  values[ ii ] += noise2.values[ ii ];
485 
486  }
487 
488  else
489  { // for time-invariant, interpolate by radius location
490 qDebug() << "SM-NOI: *NTRP* count count2" << count << noise2.count
491  << "type" << type << "mnmx r" << minradius << noise2.minradius
492  << maxradius << noise2.maxradius;
493  double radval = minradius;
494  double radinc = ( maxradius - minradius ) / (double)( count - 1 );
495  double radlo2 = noise2.minradius;
496  int limk2 = noise2.count - 1;
497  double radin2 = ( noise2.maxradius - radlo2 ) / (double)( limk2 );
498 
499  for ( int ii = 0; ii < count; ii++ )
500  {
501  // calculate index of noise1 radius in noise2 range
502  double xrad2 = ( radval - radlo2 ) / radin2;
503  int j1 = (int)xrad2;
504  int j2 = j1 + 1;
505  // get interpolation factors and noise2 values around index
506  double fac1 = (double)j2 - xrad2;
507  double fac2 = 1.0 - fac1;
508  double val1 = ( j1 < 0 ) ? noise2.values[ 0 ] :
509  ( ( j1 > limk2 ) ? noise2.values[ limk2 ] :
510  noise2.values[ j1 ] );
511  double val2 = ( j2 < 0 ) ? noise2.values[ 0 ] :
512  ( ( j2 > limk2 ) ? noise2.values[ limk2 ] :
513  noise2.values[ j2 ] );
514  // sum in an interpolated value and bump noise1 radius
515  values[ ii ] += ( val1 * fac1 + val2 * fac2 );
516  radval += radinc;
517  }
518  }
519  }
520 
521  else // no summing done
522  ok = false;
523 
524  return ok;
525 }
526 
527 // sum second noise into an original noise
528 bool US_Noise::sum_noises( US_Noise& noise1, US_Noise noise2, bool always_sum )
529 {
530 
531  return noise1.sum_noise( noise2, always_sum );
532 }
533