File: AUTOJUST\TRANSFRM.CPP
1 #include "utils\u_utils.h"
2
3 #include "detecuse\detecuse.h"
4 #include "motrstrg\motrstrg.h"
5 #include "swintrac\m_dlg.h"
6
7 // Module für die automatische Justage
8 #include "autojust\autojust.h"
9
10 #include "autojust\matrix.h"
11 #include "autojust\transfrm.h"
12 #include "autojust\m_justag.h"
13
14 #pragma hdrstop
15
16 //--||--\\--||--//--||--\\--||--//--||--\\--||--//--||--\\--||--//--||--\\--||--
17
18 //! definiert in m_justage.cpp
19 extern int nMotorDF, nMotorTL, nMotorCC;
20 extern bool bWriteLogfile;
21
22 const double GOLD= 0.61803;
23
24 // *************************************************************************
25 // ***************** Transformationsklasse *********************************
26 // zur Durchführung von Koordinatentransformationen
27
28
29 // Konstruktor
30 TransformationClass::TransformationClass(void) : buf(0), buf1(0)
31 {
32 TVektor tempVektor(0, 0, 0);
33 PosVektor= tempVektor;
34 anzahl_koordinatentrafos= 0;
35 bIntensityTooHigh= false;
36
37 buf= new char[1024];
38 if (!buf)
39 {
40 MessageBox(GetFocus(), "Fehler bei Speicherreservierung", "TransformationClass", MBSTOP);
41 PostQuitMessage( -1);
42 }
43 else
44 {
45 buf1= new char[1024];
46 if (!buf1)
47 {
48 MessageBox(GetFocus(), "Fehler bei Speicherreservierung", "TransformationClass", MBSTOP);
49 PostQuitMessage( -1);
50 }
51 }
52 }
53
54 // Destruktor
55 TransformationClass::~TransformationClass(void)
56 {
57 _FREELIST(buf);
58 _FREELIST(buf1);
59 }
60
61 // Initialisierung der Intervallgrenzen der Motoren
62 bool TransformationClass::Initialize(double MaxDF, double MaxTL, double MaxCC)
63 {
64 double fPosition, fTemp;
65 // Ermittlung der aktuellen Motorpositionen und
66 // Festlegen der Intervallgrenzen zur Justage
67 // Antrieb:Tilt
68 // setzen der aktuellen Antriebsachse
69 mlSetAxis(nMotorTL);
70 // aktuelle Position des Antriebs bestimmen
71 mGetDistance(fPosition);
72 Wertebereich.OrigTL= fPosition;
73 // Tilt: Wertebereich +/- 20 Minuten
74 Wertebereich.MinTL= ( -1) * MaxTL;
75 Wertebereich.MaxTL= MaxTL;
76 // Antrieb:Beugung fein
77 mlSetAxis(nMotorDF);
78 mGetDistance(fPosition);
79 Wertebereich.OrigDF= fPosition;
80 // DF: Wertebereich +/- 200 Sekunden
81 Wertebereich.MinDF= ( -1) * MaxDF;
82 Wertebereich.MaxDF= MaxDF;
83 // Antrieb:Kollimator
84 mlSetAxis(nMotorCC);
85 mGetDistance(fPosition);
86 Wertebereich.OrigCC= fPosition;
87 // CC: Wertebereich +/- 100 Mikrometer
88 Wertebereich.MinCC= ( -1) * MaxCC;
89 Wertebereich.MaxCC= MaxCC;
90 // Vergleich mit Softwareschranken und ggf. Änderung der Wertebereiche
91 if ((fTemp= mlGetValue(nMotorTL, MinDistance)) > Wertebereich.MinTL +
92 Wertebereich.OrigTL)
93 {
94 Wertebereich.MinTL= fTemp - Wertebereich.OrigTL;
95 }
96 if ((fTemp= mlGetValue(nMotorTL, MaxDistance)) < Wertebereich.MaxTL +
97 Wertebereich.OrigTL)
98 {
99 Wertebereich.MaxTL= fTemp - Wertebereich.OrigTL;
100 }
101 if ((fTemp= mlGetValue(nMotorDF, MinDistance)) > Wertebereich.MinDF +
102 Wertebereich.OrigDF)
103 {
104 Wertebereich.MinDF= fTemp - Wertebereich.OrigDF;
105 }
106 if ((fTemp= mlGetValue(nMotorDF, MaxDistance)) < Wertebereich.MaxDF +
107 Wertebereich.OrigDF)
108 {
109 Wertebereich.MaxDF= fTemp - Wertebereich.OrigDF;
110 }
111 if ((fTemp= mlGetValue(nMotorCC, MinDistance)) > Wertebereich.MinCC +
112 Wertebereich.OrigCC)
113 {
114 Wertebereich.MinCC= fTemp - Wertebereich.OrigCC;
115 }
116 if ((fTemp= mlGetValue(nMotorCC, MaxDistance)) < Wertebereich.MaxCC +
117 Wertebereich.OrigCC)
118 {
119 Wertebereich.MaxCC= fTemp - Wertebereich.OrigCC;
120 }
121 return true;
122 }
123
124
125 // Berechnung der Weltkoordinaten eines Punktes im akt. KS
126 TVektor TransformationClass::translate_from_worldpoints(TVektor OrigVektor)
127 {
128 // 1. vektor homogen machen
129 OrigVektor.mache_homogen();
130
131 // 2. (HIN-Transformation)
132 // Multiplikation des homog. Vektors mit den Trafo-Matrizen von Anfang an
133 // (1. bis letzte Trafo-Matrix durchlaufen)
134 for (unsigned i= 1; i <= trafo_hin.elementanzahl(); i++)
135 {
136 OrigVektor= trafo_hin.zeige(i) * OrigVektor;
137 }
138
139 // 3. Rückgabe des Vektors in kartesischer Form
140 return OrigVektor.mache_kartesisch();
141 }
142
143 // Umrechnung eines Punktes im Welt-KS in Koordinaten im akt. KS
144 TVektor TransformationClass::translate_to_worldpoints(TVektor OrigVektor)
145 {
146 // 1. vektor homogen machen
147 OrigVektor.mache_homogen();
148
149 // 2. (RÜCK-Transformation)
150 // Multiplikation des homog. Vektors mit den Trafo-Matrizen
151 // vom Ende der Liste bis zum Anfang
152 for (unsigned i= trafo_rueck.elementanzahl(); i > 0; i--)
153 {
154 OrigVektor= trafo_rueck.zeige(i) * OrigVektor;
155 }
156
157 // 3. Rückgabe des Vektors in kartesischer Form
158 return OrigVektor.mache_kartesisch();
159 }
160
161
162 // Übersetzung der Originalintervalle in akt. Koordinaten
163 TMotorPositionsWerte TransformationClass::translate_PosBorders(void)
164 {
165 TVektor Punkt3D(3);
166 TMotorPositionsWerte Intervalle;
167 double X, Y, Z;
168
169 // Übersetzung der Intervalle in akt. Koordinaten
170 // unbedingt mit Vergleich der Softwareschranken !!!
171 // d.h. notwendige Rückrechnung (translate_to_worldpoints)
172 // der akt. Schranken in Weltkoordinaten
173 // aktSchranke(x,y,z) -> weltkoord_aktSchranke(x_w,y_w,z_w)
174 // x_w-Werte mit Wertebereich.Min/MaxTL bzw. Softwareschranke vergl. usw.
175
176 // Intervallgrenzen aus Wertebereich für TL umrechnen
177 Punkt3D.set_XYZ(Wertebereich.MinTL, 0, 0);
178 Punkt3D= translate_from_worldpoints(Punkt3D);
179 Punkt3D.get_XYZ(Intervalle.MinTL, Y, Z);
180 Punkt3D.set_XYZ(Wertebereich.MaxTL, 0, 0);
181 Punkt3D= translate_from_worldpoints(Punkt3D);
182 Punkt3D.get_XYZ(Intervalle.MaxTL, Y, Z);
183
184 // Intervallgrenzen für DF umrechnen
185 Punkt3D.set_XYZ(0, Wertebereich.MinDF, 0);
186 Punkt3D= translate_from_worldpoints(Punkt3D);
187 Punkt3D.get_XYZ(X, Intervalle.MinDF, Z);
188 Punkt3D.set_XYZ(0, Wertebereich.MaxDF, 0);
189 Punkt3D= translate_from_worldpoints(Punkt3D);
190 Punkt3D.get_XYZ(X, Intervalle.MaxDF, Z);
191
192 // Intervallgrenzen für TL umrechnen
193 Punkt3D.set_XYZ(0, 0, Wertebereich.MinCC);
194 Punkt3D= translate_from_worldpoints(Punkt3D);
195 Punkt3D.get_XYZ(X, Y, Intervalle.MinCC);
196 Punkt3D.set_XYZ(0, 0, Wertebereich.MaxCC);
197 Punkt3D= translate_from_worldpoints(Punkt3D);
198 Punkt3D.get_XYZ(X, Y, Intervalle.MaxCC);
199
200 return Intervalle;
201 }
202
203 float TransformationClass::GetIntensityOnPosition(unsigned nMeasureCount)
204 // fährt die zu übersetzenden (TRAFO Klasse) Motorpositionen des Vektors an
205 // und gibt Intensität zurück
206 // muss alle 3 Motorachsen anfahren
207 // 1. translate_to_worldpoints(akt.anzufahrenderPosVektor)
208 // 2. worldkoordinaten-Vektor.get_XYZ(&x,&y,&z)
209 // 3. nMotorTL mMoveToDistance (x + Wertebereich.OrigTL) weil Ursprung (0,0,0)
210 // nMotorDF mMoveToDistance (y + Wertebereich.OrigDF)
211 // nMotorCC mMoveToDistance (z + Wertebereich.OrigCC)
212 // 4. Rückgabe der Intensität
213 {
214 float fIntensity;
215 double x, y, z, x2, y2, z2;
216
217 // Infos fürs Logging aufbereiten
218 PosVektor.get_XYZ(x2, y2, z2);
219 sprintf(buf, "Move2Dist:aktVektor (%.2f,%.2f,%.2f) -> ", x2, y2, z2);
220
221 // Umrechnung des PosVektors in Weltkoordinaten
222 PosVektor= translate_to_worldpoints(PosVektor);
223
224 // Infos fürs Logging aufbereiten
225 PosVektor.get_XYZ(x, y, z);
226 sprintf(buf1, "weltVektor (%.2f,%.2f,%.2f)[%d.KS]", x, y, z,
227 get_koordinatentrafos());
228 strcat (buf, buf1);
229 // ins Logfile schreiben
230 if (bWriteLogfile)
231 WriteToJustageLog(buf);
232
233 // Auslesen der Weltkoordinaten des PosVektors
234 PosVektor.get_XYZ(x, y, z);
235
236 // setzen der Antriebsachse TL und Anfahren der TL-Position
237 mlSetAxis(nMotorTL);
238 mMoveToDistance (x + GetOrigPosBorders().OrigTL);
239 // setzen der Antriebsachse DF und Anfahren der DF-Position
240 while (!mIsMoveFinish())
241 ProcessMessages(1)/* wait until finish */;
242 SetCursor( LoadCursor(NULL,IDC_WAIT) );
243
244 mlSetAxis(nMotorDF);
245 mMoveToDistance (y + GetOrigPosBorders().OrigDF);
246 // setzen der Antriebsachse CC und Anfahren der CC-Position
247 while (!mIsMoveFinish())
248 ProcessMessages(1)/* wait until finish */;
249 SetCursor( LoadCursor(NULL,IDC_WAIT) );
250
251 mlSetAxis(nMotorCC);
252 mMoveToDistance (z + GetOrigPosBorders().OrigCC);
253 // Warten bis Bewegung beendet ist
254 while (!mIsMoveFinish())
255 ProcessMessages(1)/* wait until finish */;
256 SetCursor( LoadCursor(NULL,IDC_WAIT) );
257
258 // Median ausgeben
259 fIntensity= MeasureIntensity(nMeasureCount);
260 if ( TCounterWindow::GetWindow() ) TCounterWindow::GetWindow()->ShowCounterSetRequest(fIntensity); // sprintf(buf, "I: %.0f", fIntensity); SetInfo(buf);
261
262 // ins Logfile schreiben
263 strcat(buf, "\n");
264 if (bWriteLogfile)
265 WriteToJustageLog(buf);
266 // Werte für den PosVektor zurückschreiben
267 PosVektor.set_XYZ(x2, y2, z2);
268 return fIntensity;
269 }
270
271
272 int TransformationClass::Goldener_Schnitt(ELaufachse achse,
273 double & intervall_li, double & intervall_re,
274 unsigned nMeasureCount)
275 {
276 double a, b, u, v, fu, fv, x, y, z;
277 int step;
278
279 a= intervall_li;
280 b= intervall_re;
281
282 u= GOLD * a + (1 - GOLD) * b;
283 v= (1 - GOLD) * a + GOLD * b;
284
285 // Komponenten des Positionsvektors auslesen
286 PosVektor.get_XYZ(x, y, z);
287
288 // # Logging #
289 sprintf(buf, ">>GoldenerSchnitt: PosVektor (%.2f,%.2f,%.2f)\n", x, y, z);
290 if (bWriteLogfile)
291 WriteToJustageLog(buf);
292
293 switch (achse)
294 {
295 case Laufachse_X: // Setzen der jew. Komponente im PosVektor
296 PosVektor.set_XYZ(u, y, z);
297 // Bestimmung der Intensität
298 fu= GetIntensityOnPosition(nMeasureCount);
299 PosVektor.set_XYZ(v, y, z);
300 fv= GetIntensityOnPosition(nMeasureCount);
301 break;
302
303 case Laufachse_Y:
304 PosVektor.set_XYZ(x, u, z);
305 fu= GetIntensityOnPosition(nMeasureCount);
306 PosVektor.set_XYZ(x, v, z);
307 fv= GetIntensityOnPosition(nMeasureCount);
308 break;
309
310 case Laufachse_Z:
311 PosVektor.set_XYZ(x, y, u);
312 fu= GetIntensityOnPosition(nMeasureCount);
313 PosVektor.set_XYZ(x, y, v);
314 fv= GetIntensityOnPosition(nMeasureCount);
315 break;
316
317 default:
318 return -1;
319 }
320
321 step= 2;
322
323 while ( (fabs(a - b) > toleranz) )
324 {
325 if (fu > fv)
326 {
327 b= v; // re. Intervallgrenze nach links verschieben
328 v= u;
329 u= GOLD * a + (1 - GOLD) * b; // neue li. Intervall-Position
330 fv= fu;
331 // Bestimmung des neuen Funktionswertes (Intensität)
332 switch (achse)
333 {
334 case Laufachse_X:
335 PosVektor.set_XYZ(u, y, z);
336 fu= GetIntensityOnPosition(nMeasureCount);
337 break;
338
339 case Laufachse_Y:
340 PosVektor.set_XYZ(x, u, z);
341 fu= GetIntensityOnPosition(nMeasureCount);
342 break;
343
344 case Laufachse_Z:
345 PosVektor.set_XYZ(x, y, u);
346 fu= GetIntensityOnPosition(nMeasureCount);
347 break;
348 }
349 step++;
350 }
351 else // wenn (fu <= fv)
352 {
353 a= u; // li. Intervallgrenze nach rechts verschieben
354 u= v;
355 v= (1 - GOLD) * a + GOLD * b; // neue re. Intervall-Position
356 fu= fv;
357 // Bestimmung des neuen Funktionswertes (Intensität)
358 switch (achse)
359 {
360 case Laufachse_X:
361 PosVektor.set_XYZ(v, y, z);
362 fv= GetIntensityOnPosition(nMeasureCount);
363 break;
364
365 case Laufachse_Y:
366 PosVektor.set_XYZ(x, v, z);
367 fv= GetIntensityOnPosition(nMeasureCount);
368 break;
369
370 case Laufachse_Z:
371 PosVektor.set_XYZ(x, y, v);
372 fv= GetIntensityOnPosition(nMeasureCount);
373 break;
374 }
375 step++;
376 }
377 }
378 intervall_li= u;
379 intervall_re= v;
380 return step;
381 }
382
383 float TransformationClass::MeasureIntensity(unsigned nMeasureCount)
384 {
385 float fIntensity, fIntensity_temp, ftemp, fMedian;
386 unsigned counter= 0;
387 float *Medianliste= 0;
388
389 // Speicher für Medianliste reservieren
390 Medianliste= new float[nMeasureCount+1];
391 if (!Medianliste)
392 {
393 MessageBox(GetFocus(), "Fehler bei Speicherreservierung", "MeasureIntensity", MBSTOP);
394 PostQuitMessage( -1);
395 }
396 // aktuelles Zählergerät setzen
397 TDetector *Detektor= TDetectorManager::DetectorManager().GetDetector();
398 do
399 {
400 // Zähler starten
401 Detektor->MeasureStart();
402
403 // Auslesen der Detektorkarte veranlassen
404 // im Fehlerfall muss die Messung neugestartet werden
405 while (Detektor->PollDetector() != R_MeasOk)
406 {
407 // Messung neustarten
408 // Detektor->MeasureStop();
409 SetInfo("Warte auf Messwerte...");
410 //Detektor->MeasureStart();
411 }
412 // Intensität auslesen (Membervariable fIntensity von Sensor)
413 while (Detektor->GetIntegral(fIntensity) != R_OK)
414 {
415 SetInfo("Hole Daten vom Counter...");
416 }
417
418 // erfolgreiche Messung
419 counter++;
420
421 // Medianliste erweitern & sortieren *****
422 fIntensity_temp= fIntensity;
423
424 if (fIntensity > 100000.0)
425 {
426 if (!bIntensityTooHigh)
427 {
428 MessageBox(GetFocus(), "MeasureIntensity: Die Maximalanzahl von 100.000\n"
429 "Detektorcounts wurde überschritten.\n\n"
430 "Die 'Automatische Justage' wird abgebrochen.\n"
431 "Bitte regeln Sie die Spannung des Röntgengenerators nach.\n",
432 "Überschreitung des Detektormaximums", MBINFO);
433 bIntensityTooHigh= true;
434 }
435 }
436
437 // noch keine Messwerte in der Liste
438 if ((counter - 1) == 0)
439 {
440 Medianliste[0]= fIntensity_temp;
441 }
442 // Messwertliste besteht schon
443 else
444 {
445 // solange bis alle bisherigen Messwerte durchgelaufen wurden
446 for (int i= 0; i < counter - 1; i++)
447 {
448 // kleine Elemente zuerst einsortieren
449 if (fIntensity_temp < Medianliste[i])
450 {
451 // Wert an der akt. Stelle merken
452 ftemp= Medianliste[i];
453 // Wert an der akt. Stelle durch Messwert ersetzen
454 Medianliste[i]= fIntensity_temp;
455 // Trick, um die weiteren Elemente durchzusortieren
456 fIntensity_temp= ftemp;
457 }
458 }
459 // übrig gebliebener Wert wird ans Ende angehängt
460 Medianliste[counter - 1]= fIntensity_temp;
461 }
462
463 // Medianbestimmung
464 // ungerade Anzahl von Messungen
465 if ((counter % 2) == 1)
466 {
467 if (counter == 1)
468 {
469 // einziges Element
470 fMedian= Medianliste[counter - 1];
471 }
472 else
473 {
474 // mittleres Element der Medianliste
475 fMedian= Medianliste[((counter + 1) / 2) - 1];
476 }
477 }
478 // gerade Anzahl von Messungen
479 else
480 {
481 // Mittelwert der beiden mittleren Elemente
482 fMedian= (Medianliste[(counter / 2) - 1] + Medianliste[((counter / 2) + 1) - 1]) / 2;
483 }
484 // Infos ins Logfile schreiben
485 if (bWriteLogfile)
486 {
487 sprintf(buf, "\r\nM:%d I:%.2f Median:%.2f ", counter, fIntensity, fMedian);
488 WriteToJustageLog(buf);
489 }
490
491 }
492 while (counter < nMeasureCount);
493 _FREELIST(Medianliste);
494 return fMedian;
495 }
496
497 // Durchführung einer kompletten Koordinatentransformation um best. Achse
498 bool TransformationClass::KoordinatenTransformation(EDrehachse achse,
499 TVektor VerschiebeVektor)
500 {
501 TVektor Einheitsvektor(3);
502 TMatrix Matrix;
503 double winkel;
504
505 switch (achse)
506 {
507 case Drehachse_X: // Einheitsvektor der Z-Achse
508 Einheitsvektor.set_XYZ(0, 0, 1);
509 break;
510
511 case Drehachse_Z: // Einheitsvektor der X-Achse
512 Einheitsvektor.set_XYZ(1, 0, 0);
513 break;
514
515 default: // bei Automatischer Justage wird nur um X bzw. Z gedreht
516 return false;
517 }
518
519 // Berechnung des Winkels von Vektor zur Koordinatenachse (Einheitsvektor)
520 winkel= VerschiebeVektor.winkel(Einheitsvektor);
521
522 // Ausführung der jew. KS-Transformation (Hin - und Rück)
523 // Drehung um X-Achse
524 if (achse == Drehachse_X)
525 {
526 // Abspeichern der Hintransformation
527 Matrix.transformiere(XYZ, ( -1)*VerschiebeVektor, -winkel, 0, 0);
528 trafo_hin.push(Matrix);
529 // Abspeichern der Rücktransformation
530 Matrix.transformiere(ZYX, VerschiebeVektor, winkel, 0, 0);
531 trafo_rueck.push(Matrix);
532 }
533 // Drehung um Z-Achse
534 else if (achse == Drehachse_Z)
535 {
536 // Abspeichern der Hintransformation
537 Matrix.transformiere(XYZ, ( -1)*VerschiebeVektor, 0, 0, -winkel);
538 trafo_hin.push(Matrix);
539 // Abspeichern der Rücktransformation
540 Matrix.transformiere(ZYX, VerschiebeVektor, 0, 0, winkel);
541 trafo_rueck.push(Matrix);
542 }
543
544 anzahl_koordinatentrafos ++;
545
546 // # Logging #
547 sprintf(buf, "%d. KS-Drehung: Winkel= %.2f Grad\n", anzahl_koordinatentrafos,
548 winkel*180 / M_PI);
549 if (bWriteLogfile)
550 WriteToJustageLog(buf);
551
552 return true;
553 }
554
555 void TransformationClass::DFCorrection(unsigned nMeasureCount, double & fDFPos,
556 float & fInt)
557 {
558 double a, b, u, v, fu, fv;
559 double fPosition, toleranz= .1;
560
561 // Intervallgrösse selbst angeben
562 // Bereich kann klein sein (DF: sek)
563 a= -5;
564 b= 5;
565
566 u= GOLD * a + (1 - GOLD) * b;
567 v= (1 - GOLD) * a + GOLD * b;
568
569 // Position festlegen
570 mlSetAxis(nMotorDF);
571 mGetDistance(fPosition);
572 mMoveToDistance(u + fPosition);
573 while (!mIsMoveFinish())
574 ProcessMessages(1)/* wait until finish */;
575 SetCursor( LoadCursor(NULL,IDC_WAIT) );
576 fu= MeasureIntensity(nMeasureCount);
577
578 mMoveToDistance(v + fPosition);
579 while (!mIsMoveFinish())
580 ProcessMessages(1)/* wait until finish */;
581 SetCursor( LoadCursor(NULL,IDC_WAIT) );
582 fv= MeasureIntensity(nMeasureCount);
583
584 while ((fabs(a - b) > toleranz))
585 {
586 if (fu > fv)
587 {
588 b= v; // re. Intervallgrenze nach links verschieben
589 v= u;
590 u= GOLD * a + (1 - GOLD) * b; // neue li. Intervall-Position
591 fv= fu;
592 // Bestimmung des neuen Funktionswertes (Intensität)
593 mMoveToDistance(u + fPosition);
594 while (!mIsMoveFinish())
595 ProcessMessages(1)/* wait until finish */;
596 SetCursor( LoadCursor(NULL,IDC_WAIT) );
597 fu= MeasureIntensity(nMeasureCount);
598 }
599 else // if (fu <= fv)
600 {
601 a= u; // li. Intervallgrenze nach rechts verschieben
602 u= v;
603 v= (1 - GOLD) * a + GOLD * b; // neue re. Intervall-Position
604 fu= fv;
605 // Bestimmung des neuen Funktionswertes (Intensität)
606 mMoveToDistance(v + fPosition);
607 while (!mIsMoveFinish())
608 ProcessMessages(1)/* wait until finish */;
609 SetCursor( LoadCursor(NULL,IDC_WAIT) );
610 fv= MeasureIntensity(nMeasureCount);
611 }
612 }
613 // Intensität & Position zurückliefern
614 fInt= fv;
615 fDFPos= v + fPosition;
616 // Position angefahren
617 }
618
619
620