QXRD  0.11.16
qxrdcenterfinder.cpp
Go to the documentation of this file.
1 #include "qxrdcenterfinder.h"
4 #include "qxrdwindow.h"
5 #include <qwt_plot_marker.h>
6 #include "qcepmutexlocker.h"
7 #include "levmar.h"
8 #include <QMessageBox>
9 #include "qxrdapplication.h"
10 #include <QtConcurrentMap>
11 #include "qxrddebug.h"
12 #include "qxrdfitterpeakpoint.h"
13 #include "qxrdfitterringpoint.h"
14 #include "qxrdfitterringcircle.h"
15 #include "qxrdfitterringellipse.h"
16 #include <QVector>
17 #include "triangulate.h"
18 #include "qxrdplanefitter.h"
19 #include "qcepdatasetmodel-ptr.h"
20 #include "qcepdatasetmodel.h"
21 #include "qxrdcalibrantlibrary.h"
22 
23 # ifdef LINSOLVERS_RETAIN_MEMORY
24 # ifdef _MSC_VER
25 # pragma message("LINSOLVERS_RETAIN_MEMORY is not safe in a multithreaded environment and should be turned off!")
26 # else
27 # warning LINSOLVERS_RETAIN_MEMORY is not safe in a multithreaded environment and should be turned off!
28 # endif /* _MSC_VER */
29 # endif /* LINSOLVERS_RETAIN_MEMORY */
30 
32  : QxrdDetectorGeometry("centering", NULL),
33  m_CenterX(saver, this, "centerX", 0, "X Center"),
34  m_CenterY(saver, this, "centerY", 0, "Y Center"),
35  m_CenterStep(saver, this, "centerStep", 1, "Center Step"),
36  m_DetectorXPixelSize(saver, this, "detectorXPixelSize", 200, "Detector X Pixels (um)"),
37  m_DetectorYPixelSize(saver, this, "detectorYPixelSize", 200, "Detector Y Pixels (um)"),
38  m_DetectorDistance(saver, this, "detectorDistance", 1000, "Sample-Detector Distance (mm)"),
39  m_DetectorDistanceStep(saver, this, "detectorDistanceStep", 100, "Sample-Detector Distance Step (mm)"),
40  m_Energy(saver, this, "energy", 20000, "Beam Energy (eV)"),
41  m_ImplementTilt(saver, this,"implementTilt", false, "Implement Detector Tilt?"),
42  m_DetectorTilt(saver, this, "detectorTilt", 0, "Tilt Angle (deg)"),
43  m_DetectorTiltStep(saver, this, "detectorTiltStep", 0.1, "Tilt Angle Step(deg)"),
44  m_TiltPlaneRotation(saver, this, "tiltPlaneRotation", 90, "Tilt Plane Rotation (deg)"),
45  m_TiltPlaneRotationStep(saver, this, "tiltPlaneRotationStep", 10, "Tilt Plane Rotation Step (deg)"),
46  m_MarkedPoints(saver, this, "markedPoints", QxrdPowderPointVector(), "Marker Points"),
47  m_FittedRings(saver, this, "fittedRings", QxrdPowderPointVector(), "Fitted Powder Rings"),
48  m_RingRadius(saver, this, "ringRadius", 0.0, "Estimated Powder Ring Radius"),
49  m_RingRadiusA(saver, this, "ringRadiusA", 0.0, "Estimated Powder Ellipse Major Axis Radius"),
50  m_RingRadiusB(saver, this, "ringRadiusB", 0.0, "Estimated Powder Ellipse Minor Axis Radius"),
51  m_RingRotation(saver, this, "ringRotation", 0.0, "Estimated Powder Ellipse Major Axis Rotation"),
52  m_PeakFitRadius(saver, this, "peakFitRadius", 10, "Half size of fitted area for peak fitting"),
53  m_PeakHeight(saver, this, "peakHeight", 100.0, "Height of fitted peak"),
54  m_PeakCenterX(saver, this, "peakCenterX", 0, "X Center of fitted peak"),
55  m_PeakCenterY(saver, this, "peakCenterY", 0, "Y Center of fitted peak"),
56  m_PeakWidth(saver, this, "peakWidth", 2.0, "Width of fitted peak"),
57  m_PeakBackground(saver, this, "peakBackground", 0, "Background Height of fitted peak"),
58  m_PeakBackgroundX(saver, this, "peakBackgroundX", 0, "X Slope of Background"),
59  m_PeakBackgroundY(saver, this, "peakBackgroundY", 0, "Y Slope of Background"),
60  m_PeakFitDebug(saver, this, "peakFitDebug", false, "Debug Print for peak fitting"),
61  m_PeakFitIterations(saver, this, "peakFitIterations", 200, "Max Iterations during fitting"),
62  m_RingAngles(saver, this, "ringAngles", QcepDoubleVector(), "Diffraction ring angles"),
63  m_RingAngleTolerance(saver, this, "ringAngleTolerance", 0.1, "Diffraction ring angle tolerance"),
64  m_PowderFitOptions(saver, this, "powderFitOptions", 0, "Powder fitting options"),
65  m_RingIndex(saver, this, "ringIndex", 0, "Fitted Powder Ring Index"),
66  m_SubtractRingAverages(saver, this, "subtractRingAverages", false, "Plot deviations of each ring from average"),
67  m_RingAverageDisplacement(saver, this, "ringAverageDisplacement", 0.0, "Extra displacement between curves in ring radius plot"),
68  m_FittedWidthMin(saver, this, "fittedWidthMin", 0.5, "Minimum acceptable fitted width (pixels)"),
69  m_FittedWidthMax(saver, this, "fittedWidthMax", 3.0, "Maximum acceptable fitted width (pixels)"),
70  m_FittedHeightMinRatio(saver, this, "fittedHeightMinRatio", 0.25, "Minimum acceptable peak height ratio"),
71  m_FittedPositionMaxDistance(saver, this, "fittedPositionMaxDistance", 2.0, "Maximum acceptable fitted position shift (pixels)"),
72  m_FitPowderPointPosition(saver, this, "fitPowderPointPosition", true, "Fit to nearby peak when adding powder points individually"),
73  m_Experiment(expt)
74 {
75  qRegisterMetaType<QPointF>("QPointF");
76 
77 // m_CenterX.setDebug(true);
78 // m_CenterY.setDebug(true);
79 
80  connect(prop_CenterX(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
81  connect(prop_CenterY(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
82  connect(prop_DetectorXPixelSize(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
83  connect(prop_DetectorYPixelSize(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
84  connect(prop_DetectorDistance(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
85  connect(prop_Energy(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
86  connect(prop_ImplementTilt(), &QcepBoolProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
87  connect(prop_DetectorTilt(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
88  connect(prop_TiltPlaneRotation(), &QcepDoubleProperty::valueChanged, this, &QxrdCenterFinder::parameterChanged, Qt::DirectConnection);
89 }
90 
92 {
93 #ifndef QT_NO_DEBUG
94  printf("Deleting center finder\n");
95 #endif
96 }
97 
99 {
100  return m_Experiment;
101 }
102 
104 {
105  return m_Data;
106 }
107 
109 {
110  int wd, ht;
111 
112  if (m_Data) {
113  wd = m_Data->get_Width();
114  ht = m_Data->get_Height();
115  } else {
116  wd = 2048;
117  ht = 2048;
118  }
119 
121 
122  if (expt) {
123  QxrdDataProcessorPtr proc(expt->dataProcessor());
124 
125  if (proc) {
126  QcepDoubleImageDataPtr res = proc->takeNextFreeImage(wd,ht);
127 
128  return res;
129  }
130  }
131 
132  return QcepDoubleImageDataPtr();
133 }
134 
135 void QxrdCenterFinder::writeSettings(QSettings *settings, QString section)
136 {
137  QcepMutexLocker lock(__FILE__, __LINE__, &m_Mutex);
138 
139  QxrdDetectorGeometry::writeSettings(settings, section);
140 }
141 
142 void QxrdCenterFinder::readSettings(QSettings *settings, QString section)
143 {
144  QcepMutexLocker lock(__FILE__, __LINE__, &m_Mutex);
145 
146  QxrdDetectorGeometry::readSettings(settings, section);
147 }
148 
150 {
151  set_CenterX(pt.x());
152  set_CenterY(pt.y());
153 }
154 
155 double QxrdCenterFinder::getTTH(QPointF pt) const
156 {
157  return getTTH(pt.x(), pt.y());
158 }
159 
160 double QxrdCenterFinder::getTTH(double x, double y) const
161 {
162  if (get_ImplementTilt()) {
163  double beta = get_DetectorTilt()*M_PI/180.0;
164  double rot = get_TiltPlaneRotation()*M_PI/180.0;
165 
166  return getTwoTheta(get_CenterX(), get_CenterY(), get_DetectorDistance(),
167  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
168  cos(beta), sin(beta), cos(rot), sin(rot));
169  } else {
170  return getTwoTheta(get_CenterX(), get_CenterY(), get_DetectorDistance(),
171  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
172  1.0, 0.0, 1.0, 0.0);
173  }
174 }
175 
176 QPointF QxrdCenterFinder::getXY(double tth, double chi)
177 {
178  double x,y;
179  double beta = get_DetectorTilt()*M_PI/180.0;
180  double rot = get_TiltPlaneRotation()*M_PI/180.0;
181 
182  if (get_ImplementTilt()) {
183 
184  QxrdDetectorGeometry::getXY(get_CenterX(), get_CenterY(), get_DetectorDistance(),
185  get_Energy(),
186  convertTwoThetaToQ(tth, convertEnergyToWavelength(get_Energy())), chi,
187  get_DetectorXPixelSize(), get_DetectorYPixelSize(),
188  rot, cos(beta), sin(beta), 1.0, 0.0, cos(rot), sin(rot),
189  &x, &y);
190  } else {
191  QxrdDetectorGeometry::getXY(get_CenterX(), get_CenterY(), get_DetectorDistance(),
192  get_Energy(),
193  convertTwoThetaToQ(tth, convertEnergyToWavelength(get_Energy())), chi,
194  get_DetectorXPixelSize(), get_DetectorYPixelSize(),
195  rot, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
196  &x, &y);
197  }
198 
199  return QPointF(x,y);
200 }
201 
202 double QxrdCenterFinder::getQ(QPointF pt) const
203 {
204  return getQ(pt.x(), pt.y());
205 }
206 
207 double QxrdCenterFinder::getQ(double x, double y) const
208 {
209  double q,chi;
210  double beta = get_DetectorTilt()*M_PI/180.0;
211  double rot = get_TiltPlaneRotation()*M_PI/180.0;
212 
213  if (get_ImplementTilt()) {
214  getQChi(get_CenterX(), get_CenterY(), get_DetectorDistance(),
215  get_Energy(),
216  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
217  rot, cos(beta), sin(beta), 1.0, 0.0, cos(rot), sin(rot),
218  &q, &chi);
219  } else {
220  getQChi(get_CenterX(), get_CenterY(), get_DetectorDistance(),
221  get_Energy(),
222  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
223  0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
224  &q, &chi);
225  }
226 
227  return q;
228 }
229 
230 double QxrdCenterFinder::getChi(QPointF pt) const
231 {
232  return getChi(pt.x(), pt.y());
233 }
234 
235 double QxrdCenterFinder::getChi(double x, double y) const
236 {
237  double q,chi;
238  double beta = get_DetectorTilt()*M_PI/180.0;
239  double rot = get_TiltPlaneRotation()*M_PI/180.0;
240 
241  if (get_ImplementTilt()) {
242  getQChi(get_CenterX(), get_CenterY(), get_DetectorDistance(),
243  get_Energy(),
244  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
245  rot, cos(beta), sin(beta), 1.0, 0.0, cos(rot), sin(rot),
246  &q, &chi);
247  } else {
248  getQChi(get_CenterX(), get_CenterY(), get_DetectorDistance(),
249  get_Energy(),
250  x, y, get_DetectorXPixelSize(), get_DetectorYPixelSize(),
251  0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
252  &q, &chi);
253  }
254 
255  return chi;
256 }
257 
258 double QxrdCenterFinder::getDist(QPointF pt) const
259 {
260  return getDist(pt.x(), pt.y());
261 }
262 
263 double QxrdCenterFinder::getDist(double x, double y) const
264 {
265  double tth = getTTH(x,y);
266 
267  return get_DetectorDistance()/cos(tth*M_PI/180.0);
268 }
269 
270 double QxrdCenterFinder::getR(QPointF pt) const
271 {
272  return getR(pt.x(), pt.y());
273 }
274 
275 double QxrdCenterFinder::getR(double x, double y) const
276 {
277  double tth = getTTH(x, y);
278  double r = get_DetectorDistance()*tan(tth*M_PI/180.0);
279 
280  return r;
281 }
282 
284 {
285  if (get_FitPowderPointPosition()) {
286  fitPeakNear(pt.x(), pt.y());
287  } else {
288  appendPowderPoint(pt.x(), pt.y());
289  }
290 }
291 
292 void QxrdCenterFinder::printMessage(QString msg, QDateTime ts) const
293 {
295 
296  if (exp) {
297  exp->printMessage(msg, ts);
298  }
299 }
300 
301 void QxrdCenterFinder::statusMessage(QString msg, QDateTime ts) const
302 {
304 
305  if (exp) {
306  exp->statusMessage(msg, ts);
307  }
308 }
309 
311 {
312  QxrdFitterRingCircle fitter(this, n, get_CenterX(), get_CenterY());
313 
314  int niter = fitter.fit();
315 
316  int update = false;
317  QString message;
318 
319  if (fitter.reason() == QxrdFitter::Successful) {
320  message.append(tr("Circle Fitting Succeeded after %1 iterations\n").arg(niter));
321  message.append(tr("Old Center = [%1,%2]\n").arg(get_CenterX()).arg(get_CenterY()));
322  message.append(tr("New Center = [%1,%2], New Radius = %3\n").arg(fitter.fittedX()).arg(fitter.fittedY()).arg(fitter.fittedR()));
323  double dx = fitter.fittedX() - get_CenterX();
324  double dy = fitter.fittedY() - get_CenterY();
325  message.append(tr("Moved by [%1,%2] = %3\n").arg(dx).arg(dy).arg(sqrt(dx*dx + dy*dy)));
326  } else {
327  message.append(tr("Circle Fitting Failed: Reason = %1\n").arg(fitter.reasonString()));
328  }
329 
330  printMessage(message);
331 
332  QxrdApplication *app = qobject_cast<QxrdApplication*>(g_Application);
333 
334  if (app && app->get_GuiWanted()) {
335  if (niter >= 0) {
336  message.append(tr("Do you want to update the beam centering parameters?"));
337 
338  if (QMessageBox::question(NULL, "Update Fitted Center?", message, QMessageBox::Ok | QMessageBox::No, QMessageBox::Ok) == QMessageBox::Ok) {
339  update = true;
340  }
341  } else {
342  QMessageBox::information(NULL, "Fitting Failed", message);
343  }
344  } else if (niter >= 0){
345  update = true;
346  }
347 
348  if (update) {
349  set_CenterX(fitter.fittedX());
350  set_CenterY(fitter.fittedY());
351  set_RingRadius(fitter.fittedR());
352  }
353 }
354 
356 {
357  QxrdFitterRingEllipse fitter(this, n, get_CenterX(), get_CenterY());
358 
359  int niter = fitter.fit();
360 
361  int update = false;
362  QString message;
363 
364  if (fitter.reason() == QxrdFitter::Successful) {
365  message.append(tr("Ellipse Fitting Succeeded after %1 iterations\n").arg(niter));
366  message.append(tr("Old Center = [%1,%2]\n").arg(get_CenterX()).arg(get_CenterY()));
367  message.append(tr("New Center = [%1,%2], New Radii = %3,%4\n")
368  .arg(fitter.fittedX()).arg(fitter.fittedY()).arg(fitter.fittedA()).arg(fitter.fittedB()));
369  message.append(tr("Major Axis rotation = %1 deg\n").arg(fitter.fittedRot()*180.0/M_PI));
370 
371  double dx = fitter.fittedX() - get_CenterX();
372  double dy = fitter.fittedY() - get_CenterY();
373  message.append(tr("Moved by [%1,%2] = %3\n").arg(dx).arg(dy).arg(sqrt(dx*dx + dy*dy)));
374  } else {
375  message.append(tr("Ellipse Fitting Failed: Reason = %1\n").arg(fitter.reasonString()));
376  }
377 
378  printMessage(message);
379 
380  QxrdApplication *app = qobject_cast<QxrdApplication*>(g_Application);
381 
382  if (app && app->get_GuiWanted()) {
383  if (fitter.reason() == QxrdFitter::Successful) {
384  message.append(tr("Do you want to update the beam centering parameters?"));
385  if (QMessageBox::question(NULL, "Update Fitted Center?", message, QMessageBox::Ok | QMessageBox::No, QMessageBox::Ok) == QMessageBox::Ok) {
386  update = true;
387  }
388  } else {
389  QMessageBox::information(NULL, "Fitting Failed", message);
390  }
391  } else if (niter >= 0){
392  update = true;
393  }
394 
395  if (update) {
396  set_CenterX(fitter.fittedX());
397  set_CenterY(fitter.fittedY());
398  set_RingRadiusA(fitter.fittedA());
399  set_RingRadiusB(fitter.fittedB());
400  set_RingRotation(fitter.fittedRot());
401  }
402 }
403 
405 {
406  int nrings = countPowderRings();
407 
408  QVector<QxrdFitterRingEllipse> fits;
409 
410  for (int i=0; i<nrings; i++) {
411  fits.append(QxrdFitterRingEllipse(this, i, get_CenterX(), get_CenterY()));
412  }
413 
415  for (int i=0; i<nrings; i++) {
416  fits[i].fit();
417  }
418  } else {
419  QFuture<void> fitDone = QtConcurrent::map(fits, &QxrdFitterRingEllipse::fit);
420 
421  fitDone.waitForFinished();
422  }
423 
425 
426  for (int i=0; i<nrings; i++) {
427  QxrdFitterRingEllipse &r = fits[i];
428 
429  if (qcepDebug(DEBUG_FITTING) || get_PeakFitDebug()) {
430  printMessage(tr("Fitted Ring %1: x: %2, y: %3, a: %4, b: %5, rot: %6, rzn: %7")
431  .arg(i).arg(r.fittedX()).arg(r.fittedY())
432  .arg(r.fittedA()).arg(r.fittedB()).arg(r.fittedRot())
433  .arg(r.reasonString()));
434  }
435 
436  if (r.reason() == QxrdFitter::Successful) {
437  pts.append(QxrdPowderPoint(i, 0, 0, r.fittedX(), r.fittedY(), r.fittedA(), r.fittedB(), r.fittedRot()));
438  }
439  }
440 
441  set_FittedRings(pts);
442 }
443 
445 {
446  double tth = powderRingAverageTTH(n);
447  double th = tth/2.0;
448  double dlatt = calibrantDSpacing(n);
449  double caltth = calibrantTTH(n);
450 
451  double newLambda = 2.0*dlatt*sin(th*M_PI/180.0);
452  double newEnergy = 12398.4187/newLambda;
453 
454  QString message;
455 
456  message.append(tr("Ring %1 average TTH = %2\n").arg(n).arg(tth));
457  message.append(tr("Calibrant Peak %1 TTH = %2\n").arg(n).arg(caltth));
458  message.append(tr("Adjust Energy from %1 to %2\n").arg(get_Energy()).arg(newEnergy));
459  message.append(tr("to improve fit to ring %1").arg(n));
460 
461  if (QMessageBox::question(NULL, "Update Energy?",
462  message, QMessageBox::Ok | QMessageBox::No, QMessageBox::Ok)
463  == QMessageBox::Ok) {
464  set_Energy(newEnergy);
465  }
466 }
467 
469 {
470  double r = powderRingAverageR(n);
471  double tth = calibrantTTH(n);
472  double d = r/tan(tth*M_PI/180.0);
473 
474  QString message;
475 
476  message.append(tr("Ring %1 average radius = %2\n").arg(n).arg(r));
477  message.append(tr("Calibrant Peak %1 TTH = %2\n").arg(n).arg(tth));
478  message.append(tr("Adjust sample - detector distance from %1 to %2\n")
479  .arg(get_DetectorDistance()).arg(d));
480  message.append(tr("to improve fit to ring %1").arg(n));
481 
482  if (QMessageBox::question(NULL, "Update Detector Distance?",
483  message, QMessageBox::Ok | QMessageBox::No, QMessageBox::Ok)
484  == QMessageBox::Ok) {
485  set_DetectorDistance(d);
486  }
487 }
488 
490 {
491  return get_MarkedPoints().value(i);
492 }
493 
495 {
496  int nearest = -1;
497  double nearestDist;
498  QxrdPowderPointVector pts = get_MarkedPoints();
499 
500  for (int i=0; i<pts.count(); i++) {
501  QxrdPowderPoint pt = pts.value(i);
502  double dist = sqrt(pow(x-pt.x(), 2) + pow(y-pt.y(), 2));
503 
504  if (nearest == -1 || dist < nearestDist) {
505  nearest = i;
506  nearestDist = dist;
507  }
508  }
509 
510  return nearest;
511 }
512 
514 {
515  return get_MarkedPoints().value(nearestPowderPointIndex(x,y));
516 }
517 
519 {
520  int nearest = nearestPowderPointIndex(x, y);
521 
522  if (nearest >= 0) {
523  QxrdPowderPointVector pts = get_MarkedPoints();
524 
525  pts.remove(nearest);
526 
527  set_MarkedPoints(pts);
528  }
529 }
530 
531 void QxrdCenterFinder::appendPowderPoint(double x, double y)
532 {
533  m_MarkedPoints.appendValue(QxrdPowderPoint(get_RingIndex(), 0, 0, x,y, 0,0,0));
534 }
535 
536 void QxrdCenterFinder::appendPowderPoint(int n1, int n2, int n3, double x, double y, double r1, double r2, double az)
537 {
538  m_MarkedPoints.appendValue(QxrdPowderPoint(n1,n2,n3, x, y, r1, r2, az));
539 }
540 
542 {
543  QxrdPowderPointVector pts = get_MarkedPoints();
544 
546 
547  foreach (QxrdPowderPoint pt, pts) {
548  if (pt.n1() < n) {
549  res.append(pt);
550  } else if (pt.n1() > n) {
551  res.append(QxrdPowderPoint(pt.n1()-1, pt.n2(), pt.n3(), pt.x(), pt.y(), pt.r1(), pt.r2(), pt.az()));
552  }
553  }
554 
555  set_MarkedPoints(res);
556 }
557 
559 {
560  QxrdPowderPointVector pts = get_MarkedPoints();
561 
562  int np = 0;
563 
564  for (int i=0; i<pts.count(); i++) {
565  if (pts[i].n1() == n) {
566  pts[i].n2() = -1;
567  np++;
568  }
569  }
570 
571  printMessage(tr("Disabled %1 points in ring %2").arg(np).arg(n));
572 
573  set_MarkedPoints(pts);
574 }
575 
577 {
578  QxrdPowderPointVector pts = get_MarkedPoints();
579 
580  int np=0;
581 
582  for (int i=0; i<pts.count(); i++) {
583  if (pts[i].n1() == n) {
584  pts[i].n2() = np++;
585  }
586  }
587 
588  printMessage(tr("Enabled %1 points in ring %2").arg(np).arg(n));
589 
590  set_MarkedPoints(pts);
591 }
592 
594 {
595  m_MarkedPoints.clear();
596 
597  set_RingIndex(0);
598 }
599 
601 {
602  QxrdPowderPointVector pts = get_MarkedPoints();
603 
604  double maxR = 0;
605 
606  foreach(QxrdPowderPoint pt, pts) {
607  double r = getR(pt.x(), pt.y());
608 
609  if (r > maxR) {
610  maxR = r;
611  }
612  }
613 
614  if (maxR > 0 && maxR < 10000) {
615  int nbins = (int) maxR + 5;
616  QVector<int> npts(nbins);
617 
618  npts.fill(0);
619 
620  foreach(QxrdPowderPoint pt, pts) {
621  double r = getR(pt.x(), pt.y());
622  npts[(int) r] ++;
623  }
624 
625  int ringIndex = 0;
626 
627  for (int i=0; i<nbins-1; i++) {
628  if (npts[i] > 0) {
629  if (npts[i+1] == 0) {
630  npts[i] = ringIndex++;
631  } else {
632  npts[i] = ringIndex;
633  }
634  }
635  }
636 
637 // for (int i=0; i<nbins; i++) {
638 // if (npts[i] > 0) {
639 // printMessage(tr("i: %1, r: %2").arg(i).arg(npts[i]));
640 // }
641 // }
642 
643  int n = pts.count();
644 
645  for (int i=0; i<n; i++) {
646  QxrdPowderPoint &pt = pts[i];
647 
648  double r = getR(pt.x(), pt.y());
649  int idx = npts[(int) r];
650 
651  pt.n1() = idx;
652  }
653 
654  set_MarkedPoints(pts);
655  set_RingIndex(ringIndex);
656  }
657 }
658 
659 bool QxrdCenterFinder::fitPeakNear(double x, double y)
660 {
661  printMessage(tr("centering.fitPeakNear(%1,%2)").arg(x).arg(y));
662 
663  QxrdFitterPeakPoint fit(this, 0, x, y, 0, 0);
664  fit.fit();
665 
666  if (fit.reason() == QxrdFitter::Successful) {
667  set_PeakCenterX(fit.fittedX());
668  set_PeakCenterY(fit.fittedY());
669  set_PeakWidth(fit.fittedWidth());
670  set_PeakHeight(fit.fittedHeight());
671  set_PeakBackground(fit.fittedBkgd());
672  set_PeakBackgroundX(fit.fittedBkgdX());
673  set_PeakBackgroundY(fit.fittedBkgdY());
674 
675  appendPowderPoint(fit.fittedX(), fit.fittedY());
676 
677  return true;
678  } else {
679  printMessage(tr("Fitting Failed"));
680 
681  return false;
682  }
683 }
684 
685 bool QxrdCenterFinder::fitRingNear(double x0, double y0)
686 {
687  printMessage(tr("centering.fitRingNear(%1,%2)").arg(x0).arg(y0));
688 
689  QxrdFitterRingPoint fit(this, 0, x0, y0, 0, 0);
690  fit.fit();
691 
692  if (fit.reason() == QxrdFitter::Successful) {
693  set_PeakCenterX(fit.fittedX());
694  set_PeakCenterY(fit.fittedY());
695  set_PeakWidth(fit.fittedWidth());
696  set_PeakHeight(fit.fittedHeight());
697  set_PeakBackground(fit.fittedBkgd());
698  set_PeakBackgroundX(fit.fittedBkgdX());
699  set_PeakBackgroundY(fit.fittedBkgdY());
700 
701  appendPowderPoint(fit.fittedX(), fit.fittedY());
702 
703  return true;
704  } else {
705  printMessage(tr("Fitting Failed"));
706 
707  return false;
708  }
709 }
710 
711 bool QxrdCenterFinder::traceRingNear(double x0, double y0, double step)
712 {
713  printMessage(tr("centering.traceRingNear(%1,%2,%3)").arg(x0).arg(y0).arg(step));
714 
715  double x=x0, y=y0;
716  double xc = get_CenterX();
717  double yc = get_CenterY();
718  double dx = x0-xc;
719  double dy = y0-yc;
720  double az = atan2(dy, dx);
721  double az0 = az;
722  double r = sqrt(dx*dx + dy*dy);
723  double ast = step/r;
724  double dr = get_PeakFitRadius();
725 
726  QxrdFitterRingPoint fit(this, 0, x0, y0, 0, 0);
727  fit.fit();
728 
729  printMessage(tr("Initial fit: az: %1, x: %2, y: %3, nx: %4, ny: %5, wd: %6, ht: %7, rz: %8")
730  .arg(az).arg(x).arg(y).arg(fit.fittedX()).arg(fit.fittedY())
731  .arg(fit.fittedWidth()).arg(fit.fittedHeight())
732  .arg(fit.reasonString()));
733 
734  double bkgd = ( imageValue(xc+(r+dr)*cos(az), yc+(r+dr)*sin(az))
735  +imageValue(xc+(r-dr)*cos(az), yc+(r-dr)*sin(az)))/2.0;
736 
737  double pkht = imageValue(x0,y0) - bkgd;
738 
739  int width = 0, height = 0;
740 
741  if (m_Data) {
742  width = m_Data->get_Width()+1;
743  height = m_Data->get_Height()+1;
744  }
745 
746  QVector<QxrdFitterRingPoint> fits;
747 
748  while (true) {
749  if (x >= 0 && y >= 0 && x <= width && y <= height) {
750  QxrdFitterRingPoint fit(this, 0, x, y, pkht, bkgd);
751  fit.fit();
752  fits.append(fit);
753 
754  if (qcepDebug(DEBUG_FITTING) || get_PeakFitDebug()) {
755  printMessage(tr("Fit Ring Near: az: %1, x: %2, y: %3, nx: %4, ny: %5, wd: %6, ht: %7, rz: %8")
756  .arg(az).arg(x).arg(y).arg(fit.fittedX()).arg(fit.fittedY())
757  .arg(fit.fittedWidth()).arg(fit.fittedHeight())
758  .arg(fit.reasonString()));
759  }
760 
761  x = fit.fittedX();
762  y = fit.fittedY();
763 
764  if (fit.reason()==QxrdFitter::Successful) {
765  r = sqrt((x-xc)*(x-xc) + (y-yc)*(y-yc));
766  }
767  }
768 
769  az += ast;
770 
771  if (step > 0) {
772  if ((az-az0) >= 2*M_PI) break;
773  } else {
774  if ((az-az0) <= -2*M_PI) break;
775  }
776 
777  x = xc + r*cos(az);
778  y = yc + r*sin(az);
779  }
780 
781  int npts = fits.count();
782  int nok = 0;
783 
784  QxrdPowderPointVector pts = get_MarkedPoints();
785 
786  QVector<int> nreason(QxrdFitter::LastReason);
787 
788  for(int i=0; i<fits.count(); i++) {
789  QxrdFitterRingPoint &fit = fits[i];
790 
791  if (fit.reason() == QxrdFitter::Successful) {
792  nok += 1;
793  pts.append(QxrdPowderPoint(get_RingIndex(), 0, 0, fit.fittedX(), fit.fittedY(), fit.fittedR(), fit.fittedR(), fit.fittedAz()));
794  }
795 
796  nreason[fit.reason()] += 1;
797  }
798 
800 
801  if (expt) {
802  QcepDatasetModelPtr data = expt->dataset();
803 
804  if (data) {
805  QcepDataColumnScanPtr scan = data->columnScan(tr("fitted/ring%1").arg(get_RingIndex()));
806 
807  if (scan == NULL) {
808  scan = data->newColumnScan(tr("fitted/ring%1").arg(get_RingIndex()));
809  }
810 
811  if (scan) {
812  scan->clear();
813 
814  scan->appendColumn("i");
815  scan->appendColumn("index");
816  scan->appendColumn("Reason");
817  scan->appendColumn("X0");
818  scan->appendColumn("Y0");
819  scan->appendColumn("pkht");
820  scan->appendColumn("bkgd");
821  scan->appendColumn("XFit");
822  scan->appendColumn("YFit");
823  scan->appendColumn("WdFit");
824  scan->appendColumn("HtFit");
825  scan->appendColumn("BkgdFit");
826  scan->appendColumn("BkgdXFit");
827  scan->appendColumn("BkgdYFit");
828  scan->appendColumn("RFit");
829  scan->appendColumn("AzFit");
830  scan->appendColumn("dx");
831  scan->appendColumn("dy");
832  scan->appendColumn("dr");
833 
834  scan->resizeRows(fits.count());
835 
836  for (int i=0; i<fits.count(); i++) {
837  QxrdFitterRingPoint &fit = fits[i];
838  int col=0;
839 
840  double dx = fit.fittedX() - fit.x0();
841  double dy = fit.fittedY() - fit.y0();
842  double dr = sqrt(dx*dx + dy*dy);
843 
844  scan->setValue(col++, i, i);
845  scan->setValue(col++, i, fit.index());
846  scan->setValue(col++, i, fit.reason());
847  scan->setValue(col++, i, fit.x0());
848  scan->setValue(col++, i, fit.y0());
849  scan->setValue(col++, i, fit.pkht());
850  scan->setValue(col++, i, fit.bkgd());
851  scan->setValue(col++, i, fit.fittedX());
852  scan->setValue(col++, i, fit.fittedY());
853  scan->setValue(col++, i, fit.fittedWidth());
854  scan->setValue(col++, i, fit.fittedHeight());
855  scan->setValue(col++, i, fit.fittedBkgd());
856  scan->setValue(col++, i, fit.fittedBkgdX());
857  scan->setValue(col++, i, fit.fittedBkgdY());
858  scan->setValue(col++, i, fit.fittedR());
859  scan->setValue(col++, i, fit.fittedAz()*180.0/M_PI);
860  scan->setValue(col++, i, dx);
861  scan->setValue(col++, i, dy);
862  scan->setValue(col++, i, dr);
863  }
864  }
865  }
866  }
867 
868  if (npts) {
869  QString msg(tr("centering.traceRingNear : %1/%2 fitted points").arg(nok).arg(npts));
870 
871  printMessage(msg);
872  statusMessage(msg);
873 
874  for (int i=0; i<QxrdFitter::LastReason; i++) {
875  if (nreason[i] > 0) {
876  QString msg(tr(" %1 : %2").arg(nreason[i]).arg(QxrdFitter::reasonString((QxrdFitter::FitResult) i)));
877  printMessage(msg);
878  }
879  }
880 
881  if (nok) {
882  prop_RingIndex()->incValue(1);
883  set_MarkedPoints(pts);
884  }
885  }
886 
887  return nok;
888 }
889 
890 bool QxrdCenterFinder::missingRingNear(double x, double y)
891 {
892  appendPowderPoint(get_RingIndex(), -1, 0, x, y, getR(x,y), getR(x,y), getChi(x,y));
893  prop_RingIndex()->incValue(1);
894 
895  return true;
896 }
897 
898 //bool QxrdCenterFinder::traceRingNearParallel(double x0, double y0, double step)
899 //{
900 // printMessage(tr("centering.traceRingNearParallel(%1,%2,%3)")
901 // .arg(x0).arg(y0).arg(step));
902 
903 // double xc = get_CenterX();
904 // double yc = get_CenterY();
905 // double dx = x0-xc;
906 // double dy = y0-yc;
907 // double dr = get_PeakFitRadius();
908 // double r = sqrt(dx*dx+dy*dy);
909 // double az = atan2(dy, dx);
910 // double ast = step/r;
911 
912 // QxrdFitterRingPoint fit(this, 0, x0, y0, 0, 0);
913 
914 // fit.fit();
915 
916 // double bkgd = ( imageValue(xc+(r+dr)*cos(az), yc+(r+dr)*sin(az))
917 // +imageValue(xc+(r-dr)*cos(az), yc+(r-dr)*sin(az)))/2.0;
918 
919 // double pkht = imageValue(x0,y0) - bkgd;
920 
921 // int nsteps = (int) ((2.0*M_PI)/ast)+1;
922 
923 // QVector<QxrdFitterRingPoint> fits;
924 
925 // double tth = getTTH(x0, y0);
926 // for (int i=0; i<nsteps; i++) {
927 // double chi = ast*i*180.0/M_PI;
928 // QPointF xy = getXY(tth, chi);
929 
930 // fits.append(QxrdFitterRingPoint(this, i, xy.x(), xy.y(), pkht, bkgd));
931 
935 // }
936 
937 // if (qcepDebug(DEBUG_NOPARALLEL)) {
938 // for (int i=0; i<nsteps; i++) {
939 // fits[i].fit();
940 // }
941 // } else {
942 // QFuture<void> fitDone = QtConcurrent::map(fits, &QxrdFitterRingPoint::fit);
943 
944 // fitDone.waitForFinished();
945 // }
946 
947 // int sums[6];
948 
949 // for (int i=0; i<6; i++) {
950 // sums[i]=0;
951 // }
952 
953 // QxrdPowderPointVector pts = get_MarkedPoints();
954 
955 // for (int i=0; i<nsteps; i++) {
956 // QxrdFitterRingPoint &r = fits[i];
957 
958 // if (qcepDebug(DEBUG_FITTING) || get_PeakFitDebug()) {
959 // printMessage(tr("Fitted %1 : x %2, y %3, w %4, ht %5, bk %6, bkx %7, bky %8, rzn %9")
960 // .arg(i).arg(r.fittedX()).arg(r.fittedY())
961 // .arg(r.fittedWidth()).arg(r.fittedHeight())
962 // .arg(r.fittedBkgd()).arg(r.fittedBkgdX()).arg(r.fittedBkgdY())
963 // .arg(r.reasonString()));
967 // }
968 
969 // int rz = r.reason();
970 // if (rz>=0 && rz<6) {
971 // sums[rz]++;
972 // }
973 
974 // if (r.reason() == QxrdFitter::Successful) {
975 // pts.append(QxrdPowderPoint(get_RingIndex(), 0, r.fittedX(), r.fittedY(), r.fittedR(), r.fittedR(), r.fittedAz()));
976 // }
977 // }
978 
979 // QString msg(tr("centering.traceRingNearParallel : Fitted %1/%2 : NR %3, OR %4, BdW %5, BdP %6, BdH %7")
980 // .arg(sums[QxrdFitter::Successful])
981 // .arg(nsteps)
982 // .arg(sums[QxrdFitter::NoResult])
983 // .arg(sums[QxrdFitter::OutsideData])
984 // .arg(sums[QxrdFitter::BadWidth])
985 // .arg(sums[QxrdFitter::BadPosition])
986 // .arg(sums[QxrdFitter::BadHeight])
987 // );
988 
989 // printMessage(msg);
990 // statusMessage(msg);
991 
992 // if (sums[QxrdFitter::Successful]) {
993 // prop_RingIndex()->incValue(1);
994 // set_MarkedPoints(pts);
995 // }
996 
997 // return true;
998 //}
999 
1001 {
1002  QxrdPowderPoint res = get_MarkedPoints().value(i);
1003 
1004  return res.n1();
1005 }
1006 
1008 {
1009  QxrdPowderPoint res = get_MarkedPoints().value(i);
1010 
1011  return res.n2();
1012 }
1013 
1015 {
1016  QxrdPowderPoint res = get_MarkedPoints().value(i);
1017 
1018  return res.x();
1019 }
1020 
1022 {
1023  QxrdPowderPoint res = get_MarkedPoints().value(i);
1024 
1025  return res.y();
1026 }
1027 
1028 void QxrdCenterFinder::setPowderPoint(int i, int n1, int n2, int n3, double x, double y, double r1, double r2, double az)
1029 {
1030  QxrdPowderPointVector pts = get_MarkedPoints();
1031 
1032  if (i>=0 && i<pts.count()) {
1033  pts[i] = QxrdPowderPoint(n1,n2,n3,x,y,r1,r2,az);
1034  } else {
1035  pts.append(QxrdPowderPoint(n1,n2,n3,x,y,r1,r2,az));
1036  }
1037 
1038  set_MarkedPoints(pts);
1039 }
1040 
1042 {
1044 
1045  if (exp) {
1046  QxrdScriptEnginePtr eng(exp->scriptEngine());
1047  QxrdPowderPointVector pts = get_MarkedPoints();
1048 
1049  if (eng) {
1050  if (i>=0 && i<get_MarkedPoints().count()) {
1051  QScriptValue val = eng->newObject();
1052 
1053  QxrdPowderPoint &pt = pts[i];
1054  val.setProperty("n1", pt.n1());
1055  val.setProperty("n2", pt.n2());
1056  val.setProperty("x", pt.x());
1057  val.setProperty("y", pt.y());
1058  val.setProperty("r1", pt.r1());
1059  val.setProperty("r2", pt.r2());
1060  val.setProperty("az", pt.az());
1061 
1062  return val;
1063  }
1064  }
1065  }
1066 
1067  return QScriptValue();
1068 }
1069 
1071 {
1073 
1074  if (exp) {
1075  QxrdScriptEnginePtr eng(exp->scriptEngine());
1076 
1077  if (eng) {
1078  QxrdPowderPointVector pts = get_MarkedPoints();
1079 
1080  QScriptValue val = eng->newArray();
1081 
1082  for (int i=0; i<pts.count(); i++) {
1083  QScriptValue item = eng->newObject();
1084 
1085  QxrdPowderPoint &pt = pts[i];
1086  item.setProperty("n1", pt.n1());
1087  item.setProperty("n2", pt.n2());
1088  item.setProperty("x", pt.x());
1089  item.setProperty("y", pt.y());
1090  item.setProperty("r1", pt.r1());
1091  item.setProperty("r2", pt.r2());
1092  item.setProperty("az", pt.az());
1093 
1094  val.setProperty(tr("%1").arg(i), item);
1095  }
1096 
1097  return val;
1098  }
1099  }
1100 
1101  return QScriptValue();
1102 }
1103 
1104 void QxrdCenterFinder::setPowderPoint(int i, QScriptValue val)
1105 {
1106  int n1 = val.property("n1").toInteger();
1107  int n2 = val.property("n2").toInteger();
1108  int n3 = val.property("n3").toInteger();
1109  double x = val.property("x").toNumber();
1110  double y = val.property("y").toNumber();
1111  double r1 = val.property("r1").toNumber();
1112  double r2 = val.property("r2").toNumber();
1113  double az = val.property("az").toNumber();
1114 
1115  setPowderPoint(i, n1, n2, n3, x, y, r1, r2, az);
1116 }
1117 
1118 
1120 {
1121  m_Data = data;
1122 }
1123 
1124 double QxrdCenterFinder::imageValue(double x, double y)
1125 {
1126  if (m_Data) {
1127  return m_Data->value(x,y);
1128  } else {
1129  return 0;
1130  }
1131 }
1132 
1134 {
1135  switch (n) {
1136  case 1:
1137  return "Stopped by Small Gradient";
1138  break;
1139 
1140  case 2:
1141  return "Stopped by Small Dp";
1142  break;
1143 
1144  case 3:
1145  return "Stopped by iteration limit";
1146  break;
1147 
1148  case 4:
1149  return "Stopped by singular matrix";
1150  break;
1151 
1152  case 5:
1153  return "No further error reduction possible";
1154  break;
1155 
1156  case 6:
1157  return "Stopped by small ||e||^2";
1158  break;
1159 
1160  case 7:
1161  return "Stopped by invalid (i.e. NaN or Inf) function values";
1162  break;
1163 
1164  default:
1165  return "Unknown reason for failure";
1166  }
1167 }
1168 
1170 {
1171  int max = -1;
1172 
1173  QxrdPowderPointVector pts = get_MarkedPoints();
1174 
1175  int n = pts.count();
1176 
1177  for (int i=0; i<n; i++) {
1178  QxrdPowderPoint pt = pts.value(i);
1179 
1180  if (pt.n1()>max) {
1181  max = pt.n1();
1182  }
1183  }
1184 
1185  if (max>1000) {
1186  return 1000;
1187  } else {
1188  return max+1;
1189  }
1190 }
1191 
1193 {
1194  return get_MarkedPoints().count();
1195 }
1196 
1198 {
1199  QxrdPowderPointVector pts = get_MarkedPoints();
1200 
1201  int sum = 0;
1202 
1203  foreach (QxrdPowderPoint pt, pts) {
1204  if (pt.n1() == r || r < 0) {
1205  sum += 1;
1206  }
1207  }
1208 
1209  return sum;
1210 }
1211 
1213 {
1214  return get_MarkedPoints().value(i);
1215 }
1216 
1218 {
1219  QxrdPowderPointVector pts = get_MarkedPoints();
1220 
1221  int sum = 0;
1222 
1223  foreach (QxrdPowderPoint pt, pts) {
1224  if (pt.n1() == r || r < 0) {
1225  if (sum == i) {
1226  return pt;
1227  } else {
1228  sum += 1;
1229  }
1230  }
1231  }
1232 
1233  return QxrdPowderPoint();
1234 }
1235 
1237 {
1238  QxrdPowderPointVector pts = get_MarkedPoints();
1239 
1240  double sum = 0, npts = 0;
1241 
1242  foreach (QxrdPowderPoint pt, pts) {
1243  if (pt.n1() == r) {
1244  npts += 1;
1245  sum += getR(pt.x(), pt.y());
1246  }
1247  }
1248 
1249  return sum/npts;
1250 }
1251 
1253 {
1254  QxrdPowderPointVector pts = get_MarkedPoints();
1255 
1256  double sum = 0, npts = 0;
1257 
1258  foreach (QxrdPowderPoint pt, pts) {
1259  if (pt.n1() == r) {
1260  npts += 1;
1261  sum += getQ(pt.x(), pt.y());
1262  }
1263  }
1264 
1265  return sum/npts;
1266 }
1267 
1269 {
1270  QxrdPowderPointVector pts = get_MarkedPoints();
1271 
1272  double sum = 0, npts = 0;
1273 
1274  foreach (QxrdPowderPoint pt, pts) {
1275  if (pt.n1() == r) {
1276  npts += 1;
1277  sum += getTTH(pt.x(), pt.y());
1278  }
1279  }
1280 
1281  return sum/npts;
1282 }
1283 
1284 class QuadInt {
1285 public:
1286  QuadInt(int n=0, int h=-1, int k=-1, int l=-1) : m_N(n), m_H(h), m_K(k), m_L(l) {}
1287 
1288  int & n() { return m_N; }
1289  int & h() { return m_H; }
1290  int & k() { return m_K; }
1291  int & l() { return m_L; }
1292 
1293 private:
1294  int m_N;
1295  int m_H;
1296  int m_K;
1297  int m_L;
1298 };
1299 
1300 //void QxrdCenterFinder::updateCalibrantDSpacings()
1301 //{
1302 // double a = get_CalibrantLattice();
1303 // int s = get_CalibrantSymmetry();
1304 // double lambda = 12398.4187/get_Energy();
1305 
1306 // int mmax = 2.0*a/lambda + 1;
1307 
1308 // if (qcepDebug(DEBUG_CALIBRANT)) {
1309 // printMessage(tr("mmax = %1").arg(mmax));
1310 // }
1311 
1312 // QVector<QuadInt> ex(mmax*mmax);
1313 
1314 // for (int h=1; h<=mmax; h++) {
1315 // for (int k=0; k<=h; k++) {
1316 // for (int l=0; l<=k; l++) {
1317 // int r = h*h+k*k+l*l;
1318 
1319 // if (r < mmax*mmax) {
1320 // bool ok=false;
1321 
1322 // switch (s) {
1323 // case 0: // Simple cubic - all OK
1324 // ok = true;
1325 // break;
1326 
1327 // case 1: // BCC h+k+l even
1328 // ok = ((h + k + l) % 2) == 0;
1329 // break;
1330 
1331 // case 2: // FCC h,k,l all even or all odd
1332 // int n = h%2 + k%2 + l%2;
1333 // ok = (n==0) || (n==3);
1334 // break;
1335 // }
1336 
1337 // if (ok) {
1338 // if (ex[r].n() == 0) {
1339 // ex[r] = QuadInt(1, h,k,l);
1340 // } else {
1341 // ex[r].n()++;
1342 // }
1343 // }
1344 // }
1345 // }
1346 // }
1347 // }
1348 
1349 // QxrdPowderPointVector pts;
1350 
1351 // for (int i=1; i<mmax*mmax; i++) {
1352 // QuadInt e = ex[i];
1353 // if (e.n() > 0) {
1354 // double d = a/sqrt(i);
1355 // double tth = 2.0*asin(lambda/(2.0*d))*180.0/M_PI;
1356 
1357 // if (tth <= 180) {
1358 // pts.append(QxrdPowderPoint(e.h(), e.k(), e.l(), d, tth, 0, 0, 0));
1359 
1360 // if (qcepDebug(DEBUG_CALIBRANT)) {
1361 // printMessage(tr("%1(%2): [%3,%4,%5], d:%6, tth:%7").arg(i).arg(e.n()).arg(e.h()).arg(e.k()).arg(e.l()).arg(d).arg(tth));
1362 // }
1363 // }
1364 // }
1365 // }
1366 
1367 // set_CalibrantDSpacings(pts);
1368 //}
1369 
1371 {
1372  double res = qQNaN();
1373 
1375 
1376  if (expt) {
1377  QxrdCalibrantDSpacingsPtr dsp(expt->calibrantDSpacings());
1378 
1379  if (dsp) {
1380  res = dsp->calibrantDSpacing(n);
1381  }
1382  }
1383 
1384  return res;
1385 }
1386 
1388 {
1389  double res = qQNaN();
1390 
1392 
1393  if (expt) {
1394  QxrdCalibrantDSpacingsPtr dsp(expt->calibrantDSpacings());
1395 
1396  if (dsp) {
1397  res = dsp->calibrantTTH(n);
1398  }
1399  }
1400 
1401  return res;
1402 }
1403 
1404 static int XYZCompare(const void *v1, const void *v2)
1405 {
1406  XYZ *p1,*p2;
1407  p1 = (XYZ*) v1;
1408  p2 = (XYZ*) v2;
1409  if (p1->x < p2->x)
1410  return(-1);
1411  else if (p1->x > p2->x)
1412  return(1);
1413  else
1414  return(0);
1415 }
1416 
1417 static int compareXYX(const XYZ& a, const XYZ& b)
1418 {
1419  return a.x < b.x;
1420 }
1421 
1422 static int differentVertices(const XYZ& a, const XYZ& b)
1423 {
1424  return (a.x != b.x) || (a.y != b.y);
1425 }
1426 
1427 static int nearby(double x1, double y1, double x2, double y2)
1428 {
1429  double dx = x1 - x2;
1430  double dy = y1 - y2;
1431 
1432  return sqrt(dx*dx + dy*dy) < 100;
1433 }
1434 
1436 {
1437  printMessage("centering.calculateCalibration()");
1439 
1440  if (expt) {
1441  QxrdDataProcessorPtr proc(expt->dataProcessor());
1442 
1443  if (proc) {
1445  res -> fill(nan(""));
1446 
1447  int wd = res->get_Width();
1448  int ht = res->get_Height();
1449 
1450  QxrdPlaneFitter f00, f01, f10, f11;
1451 
1452  int np = countPowderRingPoints();
1453 
1454  QVector<XYZ> verts;
1455 
1456  for (int i=0; i<np; i++) {
1457  QxrdPowderPoint pt = powderPoint(i);
1458 
1459  if (pt.isValid()) {
1460  double x = pt.x();
1461  double y = pt.y();
1462  double tth = getTTH(x, y);
1463  double tthNom = calibrantTTH(pt.n1());
1464  double disp = get_DetectorDistance()*(tan(tth*M_PI/180.0)/tan(tthNom*M_PI/180.0)-1.0);
1465 
1466  XYZ p;
1467  p.x = x;
1468  p.y = y;
1469  p.z = disp;
1470  verts.append(p);
1471 
1472  if (nearby(x,y,0,0)) {
1473  f00.addPoint(x,y,disp);
1474  }
1475 
1476  if (nearby(x,y,0,ht)) {
1477  f01.addPoint(x,y,disp);
1478  }
1479 
1480  if (nearby(x,y,wd,0)) {
1481  f10.addPoint(x,y,disp);
1482  }
1483 
1484  if (nearby(x,y,wd,ht)) {
1485  f11.addPoint(x,y,disp);
1486  }
1487  }
1488  }
1489 
1490  XYZ pc;
1491 
1492  pc.x = 0; pc.y = 0; pc.z = f00.value(0,0); verts.append(pc); printMessage(tr("appended (%1,%2,%3)").arg(pc.x).arg(pc.y).arg(pc.z));
1493  pc.x = 0; pc.y = ht; pc.z = f01.value(0,ht); verts.append(pc); printMessage(tr("appended (%1,%2,%3)").arg(pc.x).arg(pc.y).arg(pc.z));
1494  pc.x = wd; pc.y = 0; pc.z = f10.value(wd,0); verts.append(pc); printMessage(tr("appended (%1,%2,%3)").arg(pc.x).arg(pc.y).arg(pc.z));
1495  pc.x = wd; pc.y = ht; pc.z = f11.value(wd,ht); verts.append(pc); printMessage(tr("appended (%1,%2,%3)").arg(pc.x).arg(pc.y).arg(pc.z));
1496 
1497  XYZ p = {0,0,0};
1498 
1499  std::sort(verts.begin(), verts.end(), compareXYX);
1500 
1501  int n = verts.count();
1502 
1503  QVector<XYZ> uniq;
1504 
1505  for (int i=0; i<n; i++) {
1506  if (i==0 || differentVertices(verts[i], verts[i-1])) {
1507  uniq.append(verts[i]);
1508  }
1509  }
1510 
1511  int drop = verts.count() - uniq.count();
1512 
1513  if (drop > 0) {
1514  printMessage(tr("Dropped %1 duplicated vertices").arg(drop));
1515  }
1516 
1517  n = uniq.count();
1518 
1519  uniq.append(p);
1520  uniq.append(p);
1521  uniq.append(p);
1522 
1523  QVector<ITRIANGLE> tris(n*3);
1524 
1525  int ntri = 0;
1526 
1527  Triangulate(n, uniq.data(), tris.data(), &ntri);
1528 
1529  printMessage(tr("Formed %1 triangles").arg(ntri));
1530 
1531  int ndup = 0, nMsg = 0;
1532 
1533  for (int i=0; i<ntri; i++) {
1534  int p1 = tris[i].p1;
1535  int p2 = tris[i].p2;
1536  int p3 = tris[i].p3;
1537 
1538  // printMessage(tr("%1: (%2,%3) - (%4,%5) - (%6,%7)")
1539  // .arg(i)
1540  // .arg(uniq[p1].x).arg(uniq[p1].y)
1541  // .arg(uniq[p2].x).arg(uniq[p2].y)
1542  // .arg(uniq[p3].x).arg(uniq[p3].y)
1543  // );
1544 
1545  double x1 = uniq[p1].x;
1546  double x2 = uniq[p2].x;
1547  double x3 = uniq[p3].x;
1548  double y1 = uniq[p1].y;
1549  double y2 = uniq[p2].y;
1550  double y3 = uniq[p3].y;
1551  double z1 = uniq[p1].z;
1552  double z2 = uniq[p2].z;
1553  double z3 = uniq[p3].z;
1554 
1555  double minX = qMax((double) 0,floor(qMin(qMin(x1,x2),x3)));
1556  double maxX = qMin((double) wd,ceil(qMax(qMax(x1,x2),x3)));
1557  double minY = qMax((double) 0,floor(qMin(qMin(y1,y2),y3)));
1558  double maxY = qMin((double) ht,ceil(qMax(qMax(y1,y2),y3)));
1559 
1560  double detT = (y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3);
1561 
1562  int ndupt = 0;
1563  int nptst = 0;
1564 
1565  for (double y=minY; y<=maxY; y++) {
1566  for (double x=minX; x<=maxX; x++) {
1567  double l1 = ((y2 - y3)*(x - x3) + (x3 - x2)*(y - y3))/detT;
1568  double l2 = ((y3 - y1)*(x - x3) + (x1 - x3)*(y - y3))/detT;
1569  double l3 = 1 - l1 - l2;
1570 
1571  if (0 < l1 && l1 < 1.0 &&
1572  0 < l2 && l2 < 1.0 &&
1573  0 < l3 && l3 < 1.0) {
1574  double z = l1*z1 + l2*z2 + l3*z3;
1575 
1576  double val = res->getImageData(x,y);
1577 
1578  if (val == val) {
1579  ndup += 1;
1580  ndupt += 1;
1581  res -> setImageData(x,y, i);
1582  } else {
1583  res -> setImageData(x,y, z);
1584  }
1585 
1586  nptst += 1;
1587  }
1588  }
1589  }
1590 
1591  if (ndupt > 0 && nMsg++ < 50) {
1592  printMessage(tr("Triangle %1 : (%2,%3) - (%4,%5) - (%6,%7) : %8/%9 dups")
1593  .arg(i)
1594  .arg(uniq[p1].x).arg(uniq[p1].y)
1595  .arg(uniq[p2].x).arg(uniq[p2].y)
1596  .arg(uniq[p3].x).arg(uniq[p3].y)
1597  .arg(ndupt).arg(nptst));
1598  }
1599  }
1600 
1601  int nunset = 0;
1602 
1603  for (int y=0; y<ht; y++) {
1604  for (int x=0; x<wd; x++) {
1605  double val = res->getImageData(x,y);
1606 
1607  if (val!=val) {
1608  nunset += 1;
1609  }
1610  }
1611  }
1612 
1613  for (int y=0; y<ht; y+=ht-1) {
1614  for (int x=0; x<wd; x+=wd-1) {
1615  double val = res->getImageData(x,y);
1616 
1617  if (val!=val) {
1618  printMessage(tr("[%1,%2] unset").arg(x).arg(y));
1619  }
1620  }
1621  }
1622 
1623  printMessage(tr("%1 duplicated points, %2 unset pixels").arg(ndup).arg(nunset));
1624  proc->newData(res, QcepMaskDataPtr());
1625  }
1626  }
1627 }
1628 
1629 QScriptValue QxrdCenterFinder::toScriptValue(QScriptEngine *engine, const QxrdCenterFinderPtr &proc)
1630 {
1631  return engine->newQObject(proc.data());
1632 }
1633 
1634 void QxrdCenterFinder::fromScriptValue(const QScriptValue &obj, QxrdCenterFinderPtr &proc)
1635 {
1636  QObject *qobj = obj.toQObject();
1637 
1638  if (qobj) {
1639  QxrdCenterFinder *f = qobject_cast<QxrdCenterFinder*>(qobj);
1640 
1641  if (f) {
1642  proc = QxrdCenterFinderPtr(f);
1643  }
1644  }
1645 }
1646 
QSharedPointer< QxrdExperiment > QxrdExperimentPtr
double getChi(double x, double y) const
virtual ~QxrdCenterFinder()
double y() const
QSharedPointer< QxrdCenterFinder > QxrdCenterFinderPtr
double getTTH(double x, double y) const
double az() const
void disablePowderRing(int n)
static double convertEnergyToWavelength(double energy)
qint64 qcepDebug(int cond)
Definition: qcepdebug.cpp:26
QcepDoubleImageDataPtr data() const
int countPowderRingPoints() const
static int nearby(double x1, double y1, double x2, double y2)
int n2() const
void fitPowderCircle(int n=0)
FitResult reason() const
Definition: qxrdfitter.h:25
static int XYZCompare(const void *v1, const void *v2)
double getQ(double x, double y) const
virtual void readSettings(QSettings *set, QString section)
Definition: qcepobject.cpp:119
void adjustDistance(int n)
QSharedPointer< QcepDataColumnScan > QcepDataColumnScanPtr
void addPoint(double x, double y, double z)
QSharedPointer< QxrdDataProcessor > QxrdDataProcessorPtr
double getR(double x, double y) const
QSharedPointer< QxrdScriptEngine > QxrdScriptEnginePtr
int countPowderRings() const
double r2() const
double fittedWidth() const
void setData(QcepDoubleImageDataPtr data)
static void getQChi(double xCenter, double yCenter, double distance, double energy, double xPixel, double yPixel, double pixelLength, double pixelHeight, double rotation, double cos_beta, double sin_beta, double cos_alpha, double sin_alpha, double cos_rotation, double sin_rotation, double *q, double *chi)
double calibrantDSpacing(int n)
int Triangulate(int nv, XYZ *pxyz, ITRIANGLE *v, int *ntri)
Definition: triangulate.c:41
void printMessage(QString msg, QDateTime ts=QDateTime::currentDateTime()) const
QWeakPointer< QxrdExperiment > QxrdExperimentWPtr
static QString levmarFailureReason(int n)
bool traceRingNear(double x0, double y0, double step=25.0)
void onPointSelected(QPointF pt)
void writeSettings(QSettings *settings, QString section)
QScriptValue getPowderPoint(int i)
static void fromScriptValue(const QScriptValue &obj, QxrdCenterFinderPtr &proc)
QVector< double > QcepDoubleVector
Definition: qcepmacros.h:19
int n3() const
QScriptValue getPowderPoints()
double powderRingAverageQ(int r) const
double x
Definition: triangulate.c:14
bool missingRingNear(double x, double y)
static double convertTwoThetaToQ(double twoTheta, double wavelength)
static int differentVertices(const XYZ &a, const XYZ &b)
double getPowderPointY(int i)
double z
Definition: triangulate.c:14
static QScriptValue toScriptValue(QScriptEngine *engine, const QxrdCenterFinderPtr &proc)
QPointF getXY(double tth, double chi)
double powderRingAverageTTH(int r) const
bool fitPeakNear(double x, double y)
QxrdCenterFinder(QcepSettingsSaverWPtr saver, QxrdExperimentWPtr expt)
void setPowderPoint(int i, int n1, int n2, int n3, double x, double y, double r1, double r2, double az)
QcepDoubleImageDataPtr m_Data
QSharedPointer< QxrdCalibrantDSpacings > QxrdCalibrantDSpacingsPtr
static double getTwoTheta(double xCenter, double yCenter, double distance, double xPixel, double yPixel, double pixelLength, double pixelHeight, double cos_beta, double sin_beta, double cos_rotation, double sin_rotation)
double fittedBkgdX() const
double calibrantTTH(int n)
QxrdPowderPoint nearestPowderPoint(double x, double y)
void readSettings(QSettings *settings, QString section)
void onCenterChanged(QPointF pt)
void parameterChanged()
QxrdPowderPoint powderRingPoint(int i) const
QxrdExperimentWPtr m_Experiment
bool fitRingNear(double x0, double y0)
bool isValid() const
QString reasonString() const
Definition: qxrdfitter.cpp:15
double x() const
double y
Definition: triangulate.c:14
int n1() const
virtual void writeSettings(QSettings *set, QString section)
Definition: qcepobject.cpp:114
void adjustEnergy(int n)
QxrdExperimentWPtr experiment() const
QuadInt(int n=0, int h=-1, int k=-1, int l=-1)
void deletePowderRing(int n)
double r1() const
double powderRingAverageR(int r) const
static int compareXYX(const XYZ &a, const XYZ &b)
QcepApplication * g_Application
double getDist(double x, double y) const
void statusMessage(QString msg, QDateTime ts=QDateTime::currentDateTime()) const
QxrdPowderPoint powderPoint(int i)
int nearestPowderPointIndex(double x, double y)
void enablePowderRing(int n)
void valueChanged(double val, int index)
static void getXY(double xCenter, double yCenter, double distance, double energy, double q, double chi, double pixelLength, double pixelHeight, double rotation, double cos_beta, double sin_beta, double cos_alpha, double sin_alpha, double cos_rotation, double sin_rotation, double *xPixel, double *yPixel)
void appendPowderPoint(double x, double y)
QSharedPointer< QcepMaskData > QcepMaskDataPtr
void deletePowderPointNear(double x, double y)
double imageValue(double x, double y)
double fittedBkgd() const
double getPowderPointX(int i)
double fittedBkgdY() const
double fittedHeight() const
QSharedPointer< QcepDatasetModel > QcepDatasetModelPtr
void fitPowderEllipse(int n=0)
void valueChanged(bool val, int index)
QWeakPointer< QcepSettingsSaver > QcepSettingsSaverWPtr
QcepDoubleImageDataPtr newData()
double value(double x, double y)
QSharedPointer< QcepDoubleImageData > QcepDoubleImageDataPtr