Instrument Neutral Distributed Interface INDI  2.0.2
BasicMathPlugin.cpp
Go to the documentation of this file.
1 
5 #include "BasicMathPlugin.h"
6 
7 #include "DriverCommon.h"
8 #include "libastro.h"
9 #include <libnova/julian_day.h>
10 
11 #include <gsl/gsl_blas.h>
12 #include <gsl/gsl_permutation.h>
13 #include <gsl/gsl_linalg.h>
14 
15 #include "indicom.h"
16 
17 #include <limits>
18 #include <iostream>
19 #include <map>
20 
21 namespace INDI
22 {
23 namespace AlignmentSubsystem
24 {
26 {
27  pActualToApparentTransform = gsl_matrix_alloc(3, 3);
28  pApparentToActualTransform = gsl_matrix_alloc(3, 3);
29 }
30 
31 // Destructor
32 
34 {
35  gsl_matrix_free(pActualToApparentTransform);
36  gsl_matrix_free(pApparentToActualTransform);
37 }
38 
39 // Public methods
40 
42 {
45 
55  switch (SyncPoints.size())
56  {
57  // JM 2021-07-04: No Transformation required.
58  case 0:
59  return true;
60 
61  // JM 2021-07-04: For 1 point, it should be direct reciporical transformation.
62  case 1:
63  {
64  AlignmentDatabaseEntry &Entry1 = SyncPoints[0];
66  INDI::IHorizontalCoordinates ActualSyncPoint1;
67  TelescopeDirectionVector ActualDirectionCosine1;
68  IGeographicCoordinates Position;
70  return false;
71  RaDec.declination = Entry1.Declination;
72  RaDec.rightascension = Entry1.RightAscension;
74  {
75  EquatorialToHorizontal(&RaDec, &Position, Entry1.ObservationJulianDate, &ActualSyncPoint1);
76  // Now express this coordinate as a normalised direction vector (a.k.a direction cosines)
77  ActualDirectionCosine1 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint1);
78  }
79  else
80  {
81  ActualDirectionCosine1 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec);
82  }
83  TelescopeDirectionVector DummyActualDirectionCosine2;
84  TelescopeDirectionVector DummyApparentDirectionCosine2;
85  TelescopeDirectionVector DummyActualDirectionCosine3;
86  TelescopeDirectionVector DummyApparentDirectionCosine3;
87 
89  {
90  case ZENITH:
91  DummyActualDirectionCosine2.x = 0.0;
92  DummyActualDirectionCosine2.y = 0.0;
93  DummyActualDirectionCosine2.z = 1.0;
94  DummyApparentDirectionCosine2 = DummyActualDirectionCosine2;
95  break;
96 
98  {
100  //INDI::IHorizontalCoordinates DummyAltAz;
101  DummyRaDec.rightascension = 0.0;
102  DummyRaDec.declination = 90.0;
103  //EquatorialToHorizontal(&DummyRaDec, &Position, ln_get_julian_from_sys(), &DummyAltAz);
104  DummyActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(DummyRaDec);
105  DummyApparentDirectionCosine2 = DummyActualDirectionCosine2;
106  break;
107  }
109  {
110  INDI::IEquatorialCoordinates DummyRaDec;
111  //INDI::IHorizontalCoordinates DummyAltAz;
112  DummyRaDec.rightascension = 0.0;
113  DummyRaDec.declination = -90.0;
114  //EquatorialToHorizontal(&DummyRaDec, &Position, ln_get_julian_from_sys(), &DummyAltAz);
115  DummyActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(DummyRaDec);
116  DummyApparentDirectionCosine2 = DummyActualDirectionCosine2;
117  break;
118  }
119  }
120  DummyActualDirectionCosine3 = ActualDirectionCosine1 * DummyActualDirectionCosine2;
121  DummyActualDirectionCosine3.Normalise();
122  DummyApparentDirectionCosine3 = Entry1.TelescopeDirection * DummyApparentDirectionCosine2;
123  DummyApparentDirectionCosine3.Normalise();
124  CalculateTransformMatrices(ActualDirectionCosine1, DummyActualDirectionCosine2, DummyActualDirectionCosine3,
125  Entry1.TelescopeDirection, DummyApparentDirectionCosine2,
126  DummyApparentDirectionCosine3, pActualToApparentTransform,
128  return true;
129  }
130  case 2:
131  {
132  // First compute local horizontal coordinates for the two sync points
133  AlignmentDatabaseEntry &Entry1 = SyncPoints[0];
134  AlignmentDatabaseEntry &Entry2 = SyncPoints[1];
137  TelescopeDirectionVector ActualDirectionCosine1;
138  TelescopeDirectionVector ActualDirectionCosine2;
139  RaDec1.declination = Entry1.Declination;
140  RaDec1.rightascension = Entry1.RightAscension;
141  RaDec2.declination = Entry2.Declination;
142  RaDec2.rightascension = Entry2.RightAscension;
143  IGeographicCoordinates Position { 0, 0, 0 };
145  return false;
147  {
148  INDI::IHorizontalCoordinates ActualSyncPoint1;
149  INDI::IHorizontalCoordinates ActualSyncPoint2;
150  EquatorialToHorizontal(&RaDec1, &Position, Entry1.ObservationJulianDate, &ActualSyncPoint1);
151  EquatorialToHorizontal(&RaDec2, &Position, Entry2.ObservationJulianDate, &ActualSyncPoint2);
152  ActualDirectionCosine1 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint1);
153  ActualDirectionCosine2 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint2);
154  }
155  else
156  {
157  ActualDirectionCosine1 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec1);
158  ActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec2);
159  }
160 
161  // Now express these coordinates as normalised direction vectors (a.k.a direction cosines)
162  TelescopeDirectionVector DummyActualDirectionCosine3;
163  TelescopeDirectionVector DummyApparentDirectionCosine3;
164  DummyActualDirectionCosine3 = ActualDirectionCosine1 * ActualDirectionCosine2;
165  DummyActualDirectionCosine3.Normalise();
166  DummyApparentDirectionCosine3 = Entry1.TelescopeDirection * Entry2.TelescopeDirection;
167  DummyApparentDirectionCosine3.Normalise();
168 
169  // The third direction vectors is generated by taking the cross product of the first two
170  CalculateTransformMatrices(ActualDirectionCosine1, ActualDirectionCosine2, DummyActualDirectionCosine3,
171  Entry1.TelescopeDirection, Entry2.TelescopeDirection,
172  DummyApparentDirectionCosine3, pActualToApparentTransform,
174  return true;
175  }
176 
177  case 3:
178  {
179  // First compute local horizontal coordinates for the three sync points
180  AlignmentDatabaseEntry &Entry1 = SyncPoints[0];
181  AlignmentDatabaseEntry &Entry2 = SyncPoints[1];
182  AlignmentDatabaseEntry &Entry3 = SyncPoints[2];
183  INDI::IEquatorialCoordinates RaDec1, RaDec2, RaDec3;
184  TelescopeDirectionVector ActualDirectionCosine1, ActualDirectionCosine2, ActualDirectionCosine3;
185  RaDec1.declination = Entry1.Declination;
186  RaDec1.rightascension = Entry1.RightAscension;
187  RaDec2.declination = Entry2.Declination;
188  RaDec2.rightascension = Entry2.RightAscension;
189  RaDec3.declination = Entry3.Declination;
190  RaDec3.rightascension = Entry3.RightAscension;
191  IGeographicCoordinates Position { 0, 0, 0 };
193  return false;
195  {
196  INDI::IHorizontalCoordinates ActualSyncPoint1;
197  INDI::IHorizontalCoordinates ActualSyncPoint2;
198  INDI::IHorizontalCoordinates ActualSyncPoint3;
199  EquatorialToHorizontal(&RaDec1, &Position, Entry1.ObservationJulianDate, &ActualSyncPoint1);
200  EquatorialToHorizontal(&RaDec2, &Position, Entry2.ObservationJulianDate, &ActualSyncPoint2);
201  EquatorialToHorizontal(&RaDec3, &Position, Entry3.ObservationJulianDate, &ActualSyncPoint3);
202 
203  // Now express these coordinates as normalised direction vectors (a.k.a direction cosines)
204  ActualDirectionCosine1 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint1);
205  ActualDirectionCosine2 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint2);
206  ActualDirectionCosine3 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint3);
207  }
208  else
209  {
210  ActualDirectionCosine1 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec1);
211  ActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec2);
212  ActualDirectionCosine3 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec3);
213  }
214 
215  CalculateTransformMatrices(ActualDirectionCosine1, ActualDirectionCosine2, ActualDirectionCosine3,
218  return true;
219  }
220 
221  default:
222  {
223  IGeographicCoordinates Position { 0, 0, 0 };
225  return false;
226 
227  // Compute Hulls etc.
230  ActualDirectionCosines.clear();
231 
232  // Add a dummy point at the nadir
233  ActualConvexHull.MakeNewVertex(0.0, 0.0, -1.0, 0);
234  ApparentConvexHull.MakeNewVertex(0.0, 0.0, -1.0, 0);
235 
236  int VertexNumber = 1;
237  // Add the rest of the vertices
238  for (InMemoryDatabase::AlignmentDatabaseType::const_iterator Itr = SyncPoints.begin();
239  Itr != SyncPoints.end(); Itr++)
240  {
242  TelescopeDirectionVector ActualDirectionCosine;
243  RaDec.declination = (*Itr).Declination;
244  RaDec.rightascension = (*Itr).RightAscension;
246  {
247  INDI::IHorizontalCoordinates ActualSyncPoint;
248  EquatorialToHorizontal(&RaDec, &Position, (*Itr).ObservationJulianDate, &ActualSyncPoint);
249  // Now express this coordinate as normalised direction vectors (a.k.a direction cosines)
250  ActualDirectionCosine = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint);
251  }
252  else
253  {
254  ActualDirectionCosine = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec);
255  }
256  ActualDirectionCosines.push_back(ActualDirectionCosine);
257  ActualConvexHull.MakeNewVertex(ActualDirectionCosine.x, ActualDirectionCosine.y,
258  ActualDirectionCosine.z, VertexNumber);
259  ApparentConvexHull.MakeNewVertex((*Itr).TelescopeDirection.x, (*Itr).TelescopeDirection.y,
260  (*Itr).TelescopeDirection.z, VertexNumber);
261  VertexNumber++;
262  }
263  // I should only need to do this once but it is easier to do it twice
265  return false;
268 
270  return false;
271 
274 
275  // Make the matrices
277 #ifdef CONVEX_HULL_DEBUGGING
278  int ActualFaces = 0;
279 #endif
280  if (nullptr != CurrentFace)
281  {
282  do
283  {
284 #ifdef CONVEX_HULL_DEBUGGING
285  ActualFaces++;
286 #endif
287  if ((0 == CurrentFace->vertex[0]->vnum) || (0 == CurrentFace->vertex[1]->vnum) ||
288  (0 == CurrentFace->vertex[2]->vnum))
289  {
290 #ifdef CONVEX_HULL_DEBUGGING
291  ASSDEBUGF("Initialise - Ignoring actual face %d", ActualFaces);
292 #endif
293  }
294  else
295  {
296 #ifdef CONVEX_HULL_DEBUGGING
297  ASSDEBUGF("Initialise - Processing actual face %d v1 %d v2 %d v3 %d", ActualFaces,
298  CurrentFace->vertex[0]->vnum, CurrentFace->vertex[1]->vnum,
299  CurrentFace->vertex[2]->vnum);
300 #endif
302  ActualDirectionCosines[CurrentFace->vertex[1]->vnum - 1],
303  ActualDirectionCosines[CurrentFace->vertex[2]->vnum - 1],
304  SyncPoints[CurrentFace->vertex[0]->vnum - 1].TelescopeDirection,
305  SyncPoints[CurrentFace->vertex[1]->vnum - 1].TelescopeDirection,
306  SyncPoints[CurrentFace->vertex[2]->vnum - 1].TelescopeDirection,
307  CurrentFace->pMatrix, nullptr);
308  }
309  CurrentFace = CurrentFace->next;
310  }
311  while (CurrentFace != ActualConvexHull.faces);
312  }
313 
314  // One of these days I will optimise this
315  CurrentFace = ApparentConvexHull.faces;
316 #ifdef CONVEX_HULL_DEBUGGING
317  int ApparentFaces = 0;
318 #endif
319  if (nullptr != CurrentFace)
320  {
321  do
322  {
323 #ifdef CONVEX_HULL_DEBUGGING
324  ApparentFaces++;
325 #endif
326  if ((0 == CurrentFace->vertex[0]->vnum) || (0 == CurrentFace->vertex[1]->vnum) ||
327  (0 == CurrentFace->vertex[2]->vnum))
328  {
329 #ifdef CONVEX_HULL_DEBUGGING
330  ASSDEBUGF("Initialise - Ignoring apparent face %d", ApparentFaces);
331 #endif
332  }
333  else
334  {
335 #ifdef CONVEX_HULL_DEBUGGING
336  ASSDEBUGF("Initialise - Processing apparent face %d v1 %d v2 %d v3 %d", ApparentFaces,
337  CurrentFace->vertex[0]->vnum, CurrentFace->vertex[1]->vnum,
338  CurrentFace->vertex[2]->vnum);
339 #endif
340  CalculateTransformMatrices(SyncPoints[CurrentFace->vertex[0]->vnum - 1].TelescopeDirection,
341  SyncPoints[CurrentFace->vertex[1]->vnum - 1].TelescopeDirection,
342  SyncPoints[CurrentFace->vertex[2]->vnum - 1].TelescopeDirection,
343  ActualDirectionCosines[CurrentFace->vertex[0]->vnum - 1],
344  ActualDirectionCosines[CurrentFace->vertex[1]->vnum - 1],
345  ActualDirectionCosines[CurrentFace->vertex[2]->vnum - 1],
346  CurrentFace->pMatrix, nullptr);
347  }
348  CurrentFace = CurrentFace->next;
349  }
350  while (CurrentFace != ApparentConvexHull.faces);
351  }
352 
353 #ifdef CONVEX_HULL_DEBUGGING
354  ASSDEBUGF("Initialise - ActualFaces %d ApparentFaces %d", ActualFaces, ApparentFaces);
355  ActualConvexHull.PrintObj("ActualHull.obj");
357  ApparentConvexHull.PrintObj("ApparentHull.obj");
359 #endif
360  return true;
361  }
362  }
363 }
364 
365 bool BasicMathPlugin::TransformCelestialToTelescope(const double RightAscension, const double Declination,
366  double JulianOffset,
367  TelescopeDirectionVector &ApparentTelescopeDirectionVector)
368 {
369  INDI::IEquatorialCoordinates ActualRaDec;
370  ActualRaDec.rightascension = RightAscension;
371  ActualRaDec.declination = Declination;
372  IGeographicCoordinates Position { 0, 0, 0 };
373 
374  // Should check that this the same as the current observing position
375  if ((nullptr == pInMemoryDatabase) || !pInMemoryDatabase->GetDatabaseReferencePosition(Position))
376  return false;
377 
379  switch (SyncPoints.size())
380  {
381  case 0:
382  {
383  // 0 sync points
385  {
386  case ZENITH:
387  INDI::IHorizontalCoordinates ActualAltAz;
388  EquatorialToHorizontal(&ActualRaDec, &Position, ln_get_julian_from_sys() + JulianOffset, &ActualAltAz);
389  ApparentTelescopeDirectionVector = TelescopeDirectionVectorFromAltitudeAzimuth(ActualAltAz);
390  ASSDEBUGF("Celestial to telescope - Actual Az %lf Alt %lf", ActualAltAz.azimuth, ActualAltAz.altitude);
391  break;
392 
394  // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 minus
395  // the (positive)observatory latitude. The vector itself is rotated anticlockwise
396  //ApparentTelescopeDirectionVector.RotateAroundY(Position.latitude - 90.0);
398  // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 plus
399  // the (negative)observatory latitude. The vector itself is rotated clockwise
400  //ApparentTelescopeDirectionVector.RotateAroundY(Position.latitude + 90.0);
401  ApparentTelescopeDirectionVector = TelescopeDirectionVectorFromEquatorialCoordinates(ActualRaDec);
402  break;
403  }
404  break;
405  }
406  case 1:
407  case 2:
408  case 3:
409  {
410  TelescopeDirectionVector ActualVector;
412  {
413  INDI::IHorizontalCoordinates ActualAltAz;
414  EquatorialToHorizontal(&ActualRaDec, &Position, ln_get_julian_from_sys() + JulianOffset, &ActualAltAz);
415  ActualVector = TelescopeDirectionVectorFromAltitudeAzimuth(ActualAltAz);
416  }
417  else
418  {
419  ActualVector = TelescopeDirectionVectorFromEquatorialCoordinates(ActualRaDec);
420  }
421  gsl_vector *pGSLActualVector = gsl_vector_alloc(3);
422  gsl_vector_set(pGSLActualVector, 0, ActualVector.x);
423  gsl_vector_set(pGSLActualVector, 1, ActualVector.y);
424  gsl_vector_set(pGSLActualVector, 2, ActualVector.z);
425  gsl_vector *pGSLApparentVector = gsl_vector_alloc(3);
426  MatrixVectorMultiply(pActualToApparentTransform, pGSLActualVector, pGSLApparentVector);
427  ApparentTelescopeDirectionVector.x = gsl_vector_get(pGSLApparentVector, 0);
428  ApparentTelescopeDirectionVector.y = gsl_vector_get(pGSLApparentVector, 1);
429  ApparentTelescopeDirectionVector.z = gsl_vector_get(pGSLApparentVector, 2);
430  ApparentTelescopeDirectionVector.Normalise();
431  gsl_vector_free(pGSLActualVector);
432  gsl_vector_free(pGSLApparentVector);
433  break;
434  }
435 
436  default:
437  {
438  TelescopeDirectionVector ActualVector;
440  {
441  INDI::IHorizontalCoordinates ActualAltAz;
442  EquatorialToHorizontal(&ActualRaDec, &Position, ln_get_julian_from_sys() + JulianOffset, &ActualAltAz);
443  ActualVector = TelescopeDirectionVectorFromAltitudeAzimuth(ActualAltAz);
444  }
445  else
446  {
447  ActualVector = TelescopeDirectionVectorFromEquatorialCoordinates(ActualRaDec);
448  }
449 
450  gsl_matrix *pTransform;
451  gsl_matrix *pComputedTransform = nullptr;
452  // Scale the actual telescope direction vector to make sure it traverses the unit sphere.
453  TelescopeDirectionVector ScaledActualVector = ActualVector * 2.0;
454  // Shoot the scaled vector in the into the list of actual facets
455  // and use the conversuion matrix from the one it intersects
457 #ifdef CONVEX_HULL_DEBUGGING
458  int ActualFaces = 0;
459 #endif
460  if (nullptr != CurrentFace)
461  {
462  do
463  {
464 #ifdef CONVEX_HULL_DEBUGGING
465  ActualFaces++;
466 #endif
467  // Ignore faces containg vertex 0 (nadir).
468  if ((0 == CurrentFace->vertex[0]->vnum) || (0 == CurrentFace->vertex[1]->vnum) ||
469  (0 == CurrentFace->vertex[2]->vnum))
470  {
471 #ifdef CONVEX_HULL_DEBUGGING
472  ASSDEBUGF("Celestial to telescope - Ignoring actual face %d", ActualFaces);
473 #endif
474  }
475  else
476  {
477 #ifdef CONVEX_HULL_DEBUGGING
478  ASSDEBUGF("Celestial to telescope - Processing actual face %d v1 %d v2 %d v3 %d", ActualFaces,
479  CurrentFace->vertex[0]->vnum, CurrentFace->vertex[1]->vnum,
480  CurrentFace->vertex[2]->vnum);
481 #endif
482  if (RayTriangleIntersection(ScaledActualVector,
483  ActualDirectionCosines[CurrentFace->vertex[0]->vnum - 1],
484  ActualDirectionCosines[CurrentFace->vertex[1]->vnum - 1],
485  ActualDirectionCosines[CurrentFace->vertex[2]->vnum - 1]))
486  break;
487  }
488  CurrentFace = CurrentFace->next;
489  }
490  while (CurrentFace != ActualConvexHull.faces);
491  if (CurrentFace == ActualConvexHull.faces)
492  {
493  // Find the three nearest points and build a transform
494  std::map<double, const AlignmentDatabaseEntry *> NearestMap;
495  for (InMemoryDatabase::AlignmentDatabaseType::const_iterator Itr = SyncPoints.begin();
496  Itr != SyncPoints.end(); Itr++)
497  {
499  TelescopeDirectionVector ActualDirectionCosine;
500  RaDec.rightascension = (*Itr).RightAscension;
501  RaDec.declination = (*Itr).Declination;
503  {
504  INDI::IHorizontalCoordinates ActualPoint;
505  EquatorialToHorizontal(&RaDec, &Position, (*Itr).ObservationJulianDate, &ActualPoint);
506  ActualDirectionCosine = TelescopeDirectionVectorFromAltitudeAzimuth(ActualPoint);
507  }
508  else
509  {
510  ActualDirectionCosine = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec);
511  }
512  NearestMap[(ActualDirectionCosine - ActualVector).Length()] = &(*Itr);
513  }
514  // First compute local horizontal coordinates for the three sync points
515  std::map<double, const AlignmentDatabaseEntry *>::const_iterator Nearest = NearestMap.begin();
516  const AlignmentDatabaseEntry *pEntry1 = (*Nearest).second;
517  Nearest++;
518  const AlignmentDatabaseEntry *pEntry2 = (*Nearest).second;
519  Nearest++;
520  const AlignmentDatabaseEntry *pEntry3 = (*Nearest).second;
524  TelescopeDirectionVector ActualDirectionCosine1;
525  TelescopeDirectionVector ActualDirectionCosine2;
526  TelescopeDirectionVector ActualDirectionCosine3;
527  RaDec1.declination = pEntry1->Declination;
528  RaDec1.rightascension = pEntry1->RightAscension;
529  RaDec2.declination = pEntry2->Declination;
530  RaDec2.rightascension = pEntry2->RightAscension;
531  RaDec3.declination = pEntry3->Declination;
532  RaDec3.rightascension = pEntry3->RightAscension;
533 
535  {
536  INDI::IHorizontalCoordinates ActualSyncPoint1;
537  INDI::IHorizontalCoordinates ActualSyncPoint2;
538  INDI::IHorizontalCoordinates ActualSyncPoint3;
539  EquatorialToHorizontal(&RaDec1, &Position, pEntry1->ObservationJulianDate, &ActualSyncPoint1);
540  EquatorialToHorizontal(&RaDec2, &Position, pEntry2->ObservationJulianDate, &ActualSyncPoint2);
541  EquatorialToHorizontal(&RaDec3, &Position, pEntry3->ObservationJulianDate, &ActualSyncPoint3);
542 
543  // Now express these coordinates as normalised direction vectors (a.k.a direction cosines)
544  ActualDirectionCosine1 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint1);
545  ActualDirectionCosine2 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint2);
546  ActualDirectionCosine3 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint3);
547  }
548  else
549  {
550  ActualDirectionCosine1 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec1);
551  ActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec2);
552  ActualDirectionCosine3 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec3);
553  }
554 
555  pComputedTransform = gsl_matrix_alloc(3, 3);
556  CalculateTransformMatrices(ActualDirectionCosine1, ActualDirectionCosine2, ActualDirectionCosine3,
557  pEntry1->TelescopeDirection, pEntry2->TelescopeDirection,
558  pEntry3->TelescopeDirection, pComputedTransform, nullptr);
559  pTransform = pComputedTransform;
560  }
561  else
562  pTransform = CurrentFace->pMatrix;
563  }
564  else
565  return false;
566 
567  // OK - got an intersection - CurrentFace is pointing at the face
568  gsl_vector *pGSLActualVector = gsl_vector_alloc(3);
569  gsl_vector_set(pGSLActualVector, 0, ActualVector.x);
570  gsl_vector_set(pGSLActualVector, 1, ActualVector.y);
571  gsl_vector_set(pGSLActualVector, 2, ActualVector.z);
572  gsl_vector *pGSLApparentVector = gsl_vector_alloc(3);
573  MatrixVectorMultiply(pTransform, pGSLActualVector, pGSLApparentVector);
574  ApparentTelescopeDirectionVector.x = gsl_vector_get(pGSLApparentVector, 0);
575  ApparentTelescopeDirectionVector.y = gsl_vector_get(pGSLApparentVector, 1);
576  ApparentTelescopeDirectionVector.z = gsl_vector_get(pGSLApparentVector, 2);
577  ApparentTelescopeDirectionVector.Normalise();
578  gsl_vector_free(pGSLActualVector);
579  gsl_vector_free(pGSLApparentVector);
580  if (nullptr != pComputedTransform)
581  gsl_matrix_free(pComputedTransform);
582  break;
583  }
584  }
585 
586  // INDI::IHorizontalCoordinates ApparentAltAz;
587  // AltitudeAzimuthFromTelescopeDirectionVector(ApparentTelescopeDirectionVector, ApparentAltAz);
588  // ASSDEBUGF("Celestial to telescope - Apparent Az %lf Alt %lf", ApparentAltAz.azimuth, ApparentAltAz.altitude);
589 
590  return true;
591 }
592 
594  double &RightAscension, double &Declination)
595 {
596  IGeographicCoordinates Position;
597 
598  //INDI::IHorizontalCoordinates ApparentAltAz;
599  INDI::IHorizontalCoordinates ActualAltAz;
600  INDI::IEquatorialCoordinates ActualRaDec;
601 
602  // AltitudeAzimuthFromTelescopeDirectionVector(ApparentTelescopeDirectionVector, ApparentAltAz);
603  // ASSDEBUGF("Telescope to celestial - Apparent Az %lf Alt %lf", ApparentAltAz.azimuth, ApparentAltAz.altitude);
604 
605  if ((nullptr == pInMemoryDatabase) || !pInMemoryDatabase->GetDatabaseReferencePosition(Position))
606  {
607  // Should check that this the same as the current observing position
608  ASSDEBUG("No database or no position in database");
609  return false;
610  }
612  switch (SyncPoints.size())
613  {
614  case 0:
615  {
616  // 0 sync points
617 
619  {
620  // For Alt-Az mounts, get Alt-Az from the telescope direction vector first
621  // Then transform to actual RA/DE
622  case ZENITH:
623  {
624  ASSDEBUGF("ApparentVector x %lf y %lf z %lf", ApparentTelescopeDirectionVector.x,
625  ApparentTelescopeDirectionVector.y, ApparentTelescopeDirectionVector.z);
626  //ASSDEBUGF("ActualVector x %lf y %lf z %lf", RotatedTDV.x, RotatedTDV.y, RotatedTDV.z);
627  AltitudeAzimuthFromTelescopeDirectionVector(ApparentTelescopeDirectionVector, ActualAltAz);
628  HorizontalToEquatorial(&ActualAltAz, &Position, ln_get_julian_from_sys(), &ActualRaDec);
629  }
630  break;
631 
632  // For equatorial mount with zero sync points, just convert back from telescope
633  // direction vector to equatorial coordinates.
636  EquatorialCoordinatesFromTelescopeDirectionVector(ApparentTelescopeDirectionVector, ActualRaDec);
637  break;
638  }
639 
640  RightAscension = ActualRaDec.rightascension;
641  Declination = ActualRaDec.declination;
642  break;
643  }
644  case 1:
645  case 2:
646  case 3:
647  {
648  gsl_vector *pGSLApparentVector = gsl_vector_alloc(3);
649  gsl_vector_set(pGSLApparentVector, 0, ApparentTelescopeDirectionVector.x);
650  gsl_vector_set(pGSLApparentVector, 1, ApparentTelescopeDirectionVector.y);
651  gsl_vector_set(pGSLApparentVector, 2, ApparentTelescopeDirectionVector.z);
652  gsl_vector *pGSLActualVector = gsl_vector_alloc(3);
653  MatrixVectorMultiply(pApparentToActualTransform, pGSLApparentVector, pGSLActualVector);
654 
655  Dump3("ApparentVector", pGSLApparentVector);
656  Dump3("ActualVector", pGSLActualVector);
657 
658  TelescopeDirectionVector ActualTelescopeDirectionVector;
659  ActualTelescopeDirectionVector.x = gsl_vector_get(pGSLActualVector, 0);
660  ActualTelescopeDirectionVector.y = gsl_vector_get(pGSLActualVector, 1);
661  ActualTelescopeDirectionVector.z = gsl_vector_get(pGSLActualVector, 2);
662  ActualTelescopeDirectionVector.Normalise();
664  {
665  AltitudeAzimuthFromTelescopeDirectionVector(ActualTelescopeDirectionVector, ActualAltAz);
666  HorizontalToEquatorial(&ActualAltAz, &Position, ln_get_julian_from_sys(), &ActualRaDec);
667  }
668  else
669  {
670  EquatorialCoordinatesFromTelescopeDirectionVector(ActualTelescopeDirectionVector, ActualRaDec);
671  }
672  RightAscension = ActualRaDec.rightascension;
673  Declination = ActualRaDec.declination;
674  gsl_vector_free(pGSLActualVector);
675  gsl_vector_free(pGSLApparentVector);
676  break;
677  }
678 
679  default:
680  {
681  gsl_matrix *pTransform;
682  gsl_matrix *pComputedTransform = nullptr;
683  // Scale the apparent telescope direction vector to make sure it traverses the unit sphere.
684  TelescopeDirectionVector ScaledApparentVector = ApparentTelescopeDirectionVector * 2.0;
685  // Shoot the scaled vector in the into the list of apparent facets
686  // and use the conversuion matrix from the one it intersects
688 #ifdef CONVEX_HULL_DEBUGGING
689  int ApparentFaces = 0;
690 #endif
691  if (nullptr != CurrentFace)
692  {
693  do
694  {
695 #ifdef CONVEX_HULL_DEBUGGING
696  ApparentFaces++;
697 #endif
698  // Ignore faces containg vertex 0 (nadir).
699  if ((0 == CurrentFace->vertex[0]->vnum) || (0 == CurrentFace->vertex[1]->vnum) ||
700  (0 == CurrentFace->vertex[2]->vnum))
701  {
702 #ifdef CONVEX_HULL_DEBUGGING
703  ASSDEBUGF("Celestial to telescope - Ignoring apparent face %d", ApparentFaces);
704 #endif
705  }
706  else
707  {
708 #ifdef CONVEX_HULL_DEBUGGING
709  ASSDEBUGF("TelescopeToCelestial - Processing apparent face %d v1 %d v2 %d v3 %d", ApparentFaces,
710  CurrentFace->vertex[0]->vnum, CurrentFace->vertex[1]->vnum,
711  CurrentFace->vertex[2]->vnum);
712 #endif
713  if (RayTriangleIntersection(ScaledApparentVector,
714  SyncPoints[CurrentFace->vertex[0]->vnum - 1].TelescopeDirection,
715  SyncPoints[CurrentFace->vertex[1]->vnum - 1].TelescopeDirection,
716  SyncPoints[CurrentFace->vertex[2]->vnum - 1].TelescopeDirection))
717  break;
718  }
719  CurrentFace = CurrentFace->next;
720  }
721  while (CurrentFace != ApparentConvexHull.faces);
722  if (CurrentFace == ApparentConvexHull.faces)
723  {
724  // Find the three nearest points and build a transform
725  std::map<double, const AlignmentDatabaseEntry *> NearestMap;
726  for (InMemoryDatabase::AlignmentDatabaseType::const_iterator Itr = SyncPoints.begin();
727  Itr != SyncPoints.end(); Itr++)
728  {
729  NearestMap[((*Itr).TelescopeDirection - ApparentTelescopeDirectionVector).Length()] = &(*Itr);
730  }
731  // First compute local horizontal coordinates for the three sync points
732  std::map<double, const AlignmentDatabaseEntry *>::const_iterator Nearest = NearestMap.begin();
733  const AlignmentDatabaseEntry *pEntry1 = (*Nearest).second;
734  Nearest++;
735  const AlignmentDatabaseEntry *pEntry2 = (*Nearest).second;
736  Nearest++;
737  const AlignmentDatabaseEntry *pEntry3 = (*Nearest).second;
741  TelescopeDirectionVector ActualDirectionCosine1;
742  TelescopeDirectionVector ActualDirectionCosine2;
743  TelescopeDirectionVector ActualDirectionCosine3;
744  RaDec1.declination = pEntry1->Declination;
745  RaDec1.rightascension = pEntry1->RightAscension;
746  RaDec2.declination = pEntry2->Declination;
747  RaDec2.rightascension = pEntry2->RightAscension;
748  RaDec3.declination = pEntry3->Declination;
749  RaDec3.rightascension = pEntry3->RightAscension;
750 
752  {
753  INDI::IHorizontalCoordinates ActualSyncPoint1;
754  INDI::IHorizontalCoordinates ActualSyncPoint2;
755  INDI::IHorizontalCoordinates ActualSyncPoint3;
756  EquatorialToHorizontal(&RaDec1, &Position, pEntry1->ObservationJulianDate, &ActualSyncPoint1);
757  EquatorialToHorizontal(&RaDec2, &Position, pEntry2->ObservationJulianDate, &ActualSyncPoint2);
758  EquatorialToHorizontal(&RaDec3, &Position, pEntry3->ObservationJulianDate, &ActualSyncPoint3);
759 
760  // Now express these coordinates as normalised direction vectors (a.k.a direction cosines)
761  ActualDirectionCosine1 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint1);
762  ActualDirectionCosine2 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint2);
763  ActualDirectionCosine3 = TelescopeDirectionVectorFromAltitudeAzimuth(ActualSyncPoint3);
764  }
765  else
766  {
767  ActualDirectionCosine1 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec1);
768  ActualDirectionCosine2 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec2);
769  ActualDirectionCosine3 = TelescopeDirectionVectorFromEquatorialCoordinates(RaDec3);
770  }
771  pComputedTransform = gsl_matrix_alloc(3, 3);
773  pEntry3->TelescopeDirection, ActualDirectionCosine1,
774  ActualDirectionCosine2, ActualDirectionCosine3, pComputedTransform,
775  nullptr);
776  pTransform = pComputedTransform;
777  }
778  else
779  pTransform = CurrentFace->pMatrix;
780  }
781  else
782  return false;
783 
784  // OK - got an intersection - CurrentFace is pointing at the face
785  gsl_vector *pGSLApparentVector = gsl_vector_alloc(3);
786  gsl_vector_set(pGSLApparentVector, 0, ApparentTelescopeDirectionVector.x);
787  gsl_vector_set(pGSLApparentVector, 1, ApparentTelescopeDirectionVector.y);
788  gsl_vector_set(pGSLApparentVector, 2, ApparentTelescopeDirectionVector.z);
789  gsl_vector *pGSLActualVector = gsl_vector_alloc(3);
790  MatrixVectorMultiply(pTransform, pGSLApparentVector, pGSLActualVector);
791  TelescopeDirectionVector ActualTelescopeDirectionVector;
792  ActualTelescopeDirectionVector.x = gsl_vector_get(pGSLActualVector, 0);
793  ActualTelescopeDirectionVector.y = gsl_vector_get(pGSLActualVector, 1);
794  ActualTelescopeDirectionVector.z = gsl_vector_get(pGSLActualVector, 2);
795  ActualTelescopeDirectionVector.Normalise();
797  {
798  AltitudeAzimuthFromTelescopeDirectionVector(ActualTelescopeDirectionVector, ActualAltAz);
799  HorizontalToEquatorial(&ActualAltAz, &Position, ln_get_julian_from_sys(), &ActualRaDec);
800  }
801  else
802  {
803  EquatorialCoordinatesFromTelescopeDirectionVector(ActualTelescopeDirectionVector, ActualRaDec);
804  }
805  // libnova works in decimal degrees so conversion is needed here
806  RightAscension = ActualRaDec.rightascension;
807  Declination = ActualRaDec.declination;
808  gsl_vector_free(pGSLActualVector);
809  gsl_vector_free(pGSLApparentVector);
810  if (nullptr != pComputedTransform)
811  gsl_matrix_free(pComputedTransform);
812  break;
813  }
814  }
815  //ASSDEBUGF("Telescope to Celestial - Actual Az %lf Alt %lf", ActualAltAz.azimuth, ActualAltAz.altitude);
816  return true;
817 }
818 
819 // Private methods
820 
821 void BasicMathPlugin::Dump3(const char *Label, gsl_vector *pVector)
822 {
823  ASSDEBUGF("Vector dump - %s", Label);
824  ASSDEBUGF("%lf %lf %lf", gsl_vector_get(pVector, 0), gsl_vector_get(pVector, 1), gsl_vector_get(pVector, 2));
825 }
826 
827 void BasicMathPlugin::Dump3x3(const char *Label, gsl_matrix *pMatrix)
828 {
829  ASSDEBUGF("Matrix dump - %s", Label);
830  ASSDEBUGF("Row 0 %lf %lf %lf", gsl_matrix_get(pMatrix, 0, 0), gsl_matrix_get(pMatrix, 0, 1),
831  gsl_matrix_get(pMatrix, 0, 2));
832  ASSDEBUGF("Row 1 %lf %lf %lf", gsl_matrix_get(pMatrix, 1, 0), gsl_matrix_get(pMatrix, 1, 1),
833  gsl_matrix_get(pMatrix, 1, 2));
834  ASSDEBUGF("Row 2 %lf %lf %lf", gsl_matrix_get(pMatrix, 2, 0), gsl_matrix_get(pMatrix, 2, 1),
835  gsl_matrix_get(pMatrix, 2, 2));
836 }
837 
839 double BasicMathPlugin::Matrix3x3Determinant(gsl_matrix *pMatrix)
840 {
841  gsl_permutation *pPermutation = gsl_permutation_alloc(3);
842  gsl_matrix *pDecomp = gsl_matrix_alloc(3, 3);
843  int Signum;
844  double Determinant;
845 
846  gsl_matrix_memcpy(pDecomp, pMatrix);
847 
848  gsl_linalg_LU_decomp(pDecomp, pPermutation, &Signum);
849 
850  Determinant = gsl_linalg_LU_det(pDecomp, Signum);
851 
852  gsl_matrix_free(pDecomp);
853  gsl_permutation_free(pPermutation);
854 
855  return Determinant;
856 }
857 
859 bool BasicMathPlugin::MatrixInvert3x3(gsl_matrix *pInput, gsl_matrix *pInversion)
860 {
861  bool Retcode = true;
862  gsl_permutation *pPermutation = gsl_permutation_alloc(3);
863  gsl_matrix *pDecomp = gsl_matrix_alloc(3, 3);
864  int Signum;
865 
866  gsl_matrix_memcpy(pDecomp, pInput);
867 
868  gsl_linalg_LU_decomp(pDecomp, pPermutation, &Signum);
869 
870  // Test for singularity
871  if (0 == gsl_linalg_LU_det(pDecomp, Signum))
872  {
873  Retcode = false;
874  }
875  else
876  gsl_linalg_LU_invert(pDecomp, pPermutation, pInversion);
877 
878  gsl_matrix_free(pDecomp);
879  gsl_permutation_free(pPermutation);
880 
881  return Retcode;
882 }
883 
886 void BasicMathPlugin::MatrixMatrixMultiply(gsl_matrix *pA, gsl_matrix *pB, gsl_matrix *pC)
887 {
888  // Zeroise the output matrix
889  gsl_matrix_set_zero(pC);
890 
891  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, pA, pB, 0.0, pC);
892 }
893 
896 void BasicMathPlugin::MatrixVectorMultiply(gsl_matrix *pA, gsl_vector *pB, gsl_vector *pC)
897 {
898  // Zeroise the output vector
899  gsl_vector_set_zero(pC);
900 
901  gsl_blas_dgemv(CblasNoTrans, 1.0, pA, pB, 0.0, pC);
902 }
903 
905  TelescopeDirectionVector &TriangleVertex2,
906  TelescopeDirectionVector &TriangleVertex3)
907 {
908  // Use Möller-Trumbore
909 
910  //Find vectors for two edges sharing V1
911  TelescopeDirectionVector Edge1 = TriangleVertex2 - TriangleVertex1;
912  TelescopeDirectionVector Edge2 = TriangleVertex3 - TriangleVertex1;
913 
914  TelescopeDirectionVector P = Ray * Edge2; // cross product
915  double Determinant = Edge1 ^ P; // dot product
916  double InverseDeterminant = 1.0 / Determinant;
917 
918  // If the determinant is negative the triangle is backfacing
919  // If the determinant is close to 0, the ray misses the triangle
920  if ((Determinant > -std::numeric_limits<double>::epsilon()) &&
921  (Determinant < std::numeric_limits<double>::epsilon()))
922  return false;
923 
924  // I use zero as ray origin so
925  TelescopeDirectionVector T(-TriangleVertex1.x, -TriangleVertex1.y, -TriangleVertex1.z);
926 
927  // Calculate the u parameter
928  double u = (T ^ P) * InverseDeterminant;
929 
930  if (u < 0.0 || u > 1.0)
931  //The intersection lies outside of the triangle
932  return false;
933 
934  //Prepare to test v parameter
935  TelescopeDirectionVector Q = T * Edge1;
936 
937  //Calculate v parameter and test bound
938  double v = (Ray ^ Q) * InverseDeterminant;
939 
940  if (v < 0.0 || u + v > 1.0)
941  //The intersection lies outside of the triangle
942  return false;
943 
944  double t = (Edge2 ^ Q) * InverseDeterminant;
945 
946  if (t > std::numeric_limits<double>::epsilon())
947  {
948  //ray intersection
949  return true;
950  }
951 
952  // No hit, no win
953  return false;
954 }
955 
956 } // namespace AlignmentSubsystem
957 } // namespace INDI
#define ASSDEBUG(msg)
Definition: DriverCommon.h:17
#define ASSDEBUGF(msg,...)
Definition: DriverCommon.h:18
bool MatrixInvert3x3(gsl_matrix *pInput, gsl_matrix *pInversion)
Calculate the inverse of the supplied matrix.
double Matrix3x3Determinant(gsl_matrix *pMatrix)
Caluclate the determinant of the supplied matrix.
void MatrixMatrixMultiply(gsl_matrix *pA, gsl_matrix *pB, gsl_matrix *pC)
Multiply matrix A by matrix B and put the result in C.
void Dump3(const char *Label, gsl_vector *pVector)
Print out a 3 vector to debug.
virtual void CalculateTransformMatrices(const TelescopeDirectionVector &Alpha1, const TelescopeDirectionVector &Alpha2, const TelescopeDirectionVector &Alpha3, const TelescopeDirectionVector &Beta1, const TelescopeDirectionVector &Beta2, const TelescopeDirectionVector &Beta3, gsl_matrix *pAlphaToBeta, gsl_matrix *pBetaToAlpha)=0
Calculate tranformation matrices from the supplied vectors.
std::vector< TelescopeDirectionVector > ActualDirectionCosines
virtual bool TransformTelescopeToCelestial(const TelescopeDirectionVector &ApparentTelescopeDirectionVector, double &RightAscension, double &Declination)
Override for the base class virtual function.
void MatrixVectorMultiply(gsl_matrix *pA, gsl_vector *pB, gsl_vector *pC)
Multiply matrix A by vector B and put the result in vector C.
virtual ~BasicMathPlugin()
Virtual destructor.
bool RayTriangleIntersection(TelescopeDirectionVector &Ray, TelescopeDirectionVector &TriangleVertex1, TelescopeDirectionVector &TriangleVertex2, TelescopeDirectionVector &TriangleVertex3)
Test if a ray intersects a triangle in 3d space.
virtual bool TransformCelestialToTelescope(const double RightAscension, const double Declination, double JulianOffset, TelescopeDirectionVector &ApparentTelescopeDirectionVector)
Override for the base class virtual function.
virtual bool Initialise(InMemoryDatabase *pInMemoryDatabase)
Override for the base class virtual function.
void Dump3x3(const char *Label, gsl_matrix *pMatrix)
Print out a 3x3 matrix to debug.
void EdgeOrderOnFaces()
EdgeOrderOnFaces: puts e0 between v0 and v1, e1 between v1 and v2, e2 between v2 and v0 on each face....
Definition: ConvexHull.cpp:473
void Reset()
Frees the vertices edges and faces lists and resets the debug and check flags.
Definition: ConvexHull.cpp:988
void MakeNewVertex(double x, double y, double z, int VertexId)
Makes a vertex from the supplied information and adds it to the vertices list.
Definition: ConvexHull.cpp:623
void PrintOut(const char *FileName, tVertex v)
Prints vertices, edges and faces to the standard error output.
Definition: ConvexHull.cpp:924
bool DoubleTriangle()
DoubleTriangle builds the initial double triangle. It first finds 3 noncollinear points and makes two...
Definition: ConvexHull.cpp:421
void ConstructHull()
ConstructHull adds the vertices to the hull one at a time. The hull vertices are those in the list ma...
Definition: ConvexHull.cpp:360
void PrintObj(const char *FileName="chull.obj")
Outputs the faces in Lightwave obj format for 3d viewing. The files chull.obj and chull....
Definition: ConvexHull.cpp:847
This class provides the driver side API to the in memory alignment database.
AlignmentDatabaseType & GetAlignmentDatabase()
Get a reference to the in memory database.
std::vector< AlignmentDatabaseEntry > AlignmentDatabaseType
bool GetDatabaseReferencePosition(IGeographicCoordinates &Position)
Get the database reference position.
InMemoryDatabase * pInMemoryDatabase
Definition: MathPlugin.h:83
virtual bool Initialise(InMemoryDatabase *pInMemoryDatabase)
Initialise or re-initialise the math plugin. Re-reading the in memory database as necessary.
Definition: MathPlugin.cpp:15
MountAlignment_t ApproximateMountAlignment
Describe the approximate alignment of the mount. This information is normally used in a one star alig...
Definition: MathPlugin.h:82
const TelescopeDirectionVector TelescopeDirectionVectorFromAltitudeAzimuth(INDI::IHorizontalCoordinates HorizontalCoordinates)
Calculates a normalised direction vector from the supplied altitude and azimuth.
void EquatorialCoordinatesFromTelescopeDirectionVector(const TelescopeDirectionVector TelescopeDirectionVector, INDI::IEquatorialCoordinates &EquatorialCoordinates)
Calculates equatorial coordinates from the supplied telescope direction vector and declination.
const TelescopeDirectionVector TelescopeDirectionVectorFromEquatorialCoordinates(INDI::IEquatorialCoordinates EquatorialCoordinates)
Calculates a telescope direction vector from the supplied equatorial coordinates.
void AltitudeAzimuthFromTelescopeDirectionVector(const TelescopeDirectionVector TelescopeDirectionVector, INDI::IHorizontalCoordinates &HorizontalCoordinates)
Calculates an altitude and azimuth from the supplied normalised direction vector and declination.
Implementations for common driver routines.
Namespace to encapsulate INDI client, drivers, and mediator classes.
void EquatorialToHorizontal(IEquatorialCoordinates *object, IGeographicCoordinates *observer, double JD, IHorizontalCoordinates *position)
EquatorialToHorizontal Calculate horizontal coordinates from equatorial coordinates.
Definition: libastro.cpp:140
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
Definition: libastro.cpp:156
Entry in the in memory alignment database.
Definition: Common.h:152
double RightAscension
Right ascension in decimal hours. N.B. libnova works in decimal degrees so conversion is always neede...
Definition: Common.h:190
TelescopeDirectionVector TelescopeDirection
Normalised vector giving telescope pointing direction. This is referred to elsewhere as the "apparent...
Definition: Common.h:197
double Declination
Declination in decimal degrees.
Definition: Common.h:193
Holds a nomalised direction vector (direction cosines)
Definition: Common.h:69
void Normalise()
Normalise the vector.
Definition: Common.h:131