Instrument Neutral Distributed Interface INDI 2.2.5
scopesim_helper.cpp
Go to the documentation of this file.
1/*
2 * scopesim_helper.cpp
3 *
4 * Copyright 2020 Chris Rowland <[email protected]>
5 *
6 * implementation of telescope simulator helper classes Angle, Axis and Alignment
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23
24#include "scopesim_helper.h"
25
26#include "indilogger.h"
27
28char device_str[64] = "Telescope Simulator";
29
31
32// Angle implementation
33
35{
36 switch(type)
37 {
38 case DEGREES:
39 angle = range(value);
40 break;
41 case HOURS:
42 angle = range(value * 15.0);
43 break;
44 case RADIANS:
45 angle = range(value * 180.0 / M_PI);
46 break;
47 }
48}
49
51{
52 return this->angle * M_PI / 180.0;
53}
54
56{
57 return std::abs(difference(a)) < 10E-6;
58}
59
61{
62 return std::abs(difference(a)) >= 10E-6;
63}
64
66
67// Axis Implementation
68
69void Axis::setDegrees(double degrees)
70{
71 this->position = degrees;
72 this->target = degrees;
73}
74
75void Axis::setHours(double hours)
76{
77 this->position = hours * 15.0;
78 this->target = hours * 15.0;
79}
80
82{
83 LOGF_DEBUG("%s StartSlew to %f", axisName, angle.Degrees());
84 target = angle;
85 isSlewing = true;
86}
87
88void Axis::Tracking(bool enabled)
89{
90 tracking = enabled;
91 LOGF_EXTRA1("%s Tracking enabled %s", axisName, enabled ? "true" : "false");
92}
93
95{
96 trackingRate = rate;
97 switch (trackingRate)
98 {
101 break;
103 TrackingRateDegSec = siderealRate;
104 break;
106 TrackingRateDegSec = solarRate;
107 break;
109 TrackingRateDegSec = lunarRate;
110 break;
111 }
112 LOGF_EXTRA1("%s: TrackRate %i, trackingRateDegSec %f arcsec", axisName, trackingRate, TrackingRateDegSec.Degrees() * 3600);
113}
114
116{
117 return trackingRate;
118}
119
124
125void Axis::StartGuide(double rate, uint32_t durationMs)
126{
127 // rate is fraction of sidereal, signed to give the direction
128
129 guideRateDegSec = (360.0 / 86400) * rate;
130 guideDuration = durationMs / 1000.0;
131 LOGF_DEBUG("%s StartGuide rate %f=>%f, dur %d =>%f", axisName, rate, guideRateDegSec.Degrees(), durationMs, guideDuration);
132}
133
134void Axis::update() // called about once a second to update the position and mode
135{
136 struct timeval currentTime
137 {
138 0, 0
139 };
140
141 /* update elapsed time since last poll, don't presume exactly POLLMS */
142 gettimeofday(&currentTime, nullptr);
143
144 if (lastTime.tv_sec == 0 && lastTime.tv_usec == 0)
145 lastTime = currentTime;
146
147 // Time diff in seconds
148 double interval = currentTime.tv_sec - lastTime.tv_sec + (currentTime.tv_usec - lastTime.tv_usec) / 1e6;
149 lastTime = currentTime;
150 double change = 0;
151
152 //LOGF_DEBUG("%s: position %f, target %f, interval %f", axisName, position.Degrees(), target.Degrees(), interval);
153
154 // tracking
155 if (isTracking())
156 {
157 position += TrackingRateDegSec * interval;
158 target += TrackingRateDegSec * interval;
159 LOGF_EXTRA1("%s: tracking, rate %f, position %f, target %f", axisName, TrackingRateDegSec.Degrees(), position.Degrees(), target.Degrees());
160 }
161
162 // handle the slew
163 if (isSlewing)
164 {
165 // get positions relative to the rotate centre
166 Angle trc = target - rotateCentre;
167 Angle prc = position - rotateCentre;
168 // get the change, don't use Angle so the change goes through the rotate centre
169 double delta = trc.Degrees() - prc.Degrees();
170 double fastChange = mcRates[4].Degrees() * interval;
171 double slowChange = fastChange / 5;
172 //LOGF_DEBUG("slew: trc %f prc %f, delta %f", trc.Degrees(), prc.Degrees(), delta);
173 // apply the change to the relative position
174 if (delta < -fastChange)
175 {
176 change = -fastChange;
177 }
178 else if (delta < -slowChange)
179 {
180 change = -slowChange;
181 }
182 else if (delta > fastChange)
183 {
184 change = fastChange;
185 }
186 else if (delta > slowChange)
187 {
188 change = slowChange;
189 }
190 else
191 {
192 position = target;
193 isSlewing = false;
194 //OnMoveFinished();
195 }
196 position += change;
197 //LOGF_DEBUG("move %s: change %f, position %f", b, change, position.Degrees());
198 }
199
200 int rate = std::max(-4,std::min(4,mcRate));
201 if(rate != mcRate) {
202 LOGF_ERROR("Invalid mcRate Detected = %d",mcRate);
203 }
204
205 // handle the motion control
206 if (rate < 0)
207 {
208 change = -mcRates[-rate].Degrees() * interval;
209 //LOGF_DEBUG("mcRate %d, rate %f, change %f", mcRate, mcRates[-mcRate].Degrees(), change);
210 position += change;
211 }
212 else if (rate > 0)
213 {
214 change = mcRates[rate].Degrees() * interval;
215 //LOGF_DEBUG("mcRate %d, rate %f, change %f", mcRate, mcRates[mcRate].Degrees(), change);
216 position += change;
217 }
218
219 // handle guiding
220 if (guideDuration > 0)
221 {
222 change = guideRateDegSec.Degrees() * (guideDuration > interval ? interval : guideDuration);
223 guideDuration -= interval;
224 LOGF_DEBUG("guide rate %f, remaining duration %f, change %f", guideRateDegSec.Degrees(), guideDuration, change);
225 position += change;
226 }
227}
228
230
231// Alignment methods
232
237
238void Alignment::mountToApparentHaDec(Angle primary, Angle secondary, Angle * apparentHa, Angle* apparentDec)
239{
240
241 Angle prio, seco;
242 // get instrument place
243 switch (mountType)
244 {
246 // Primary instrument axis: Negative PA-system looking down from Zenith:Nadir, origin "HA-like"!!!
247 // Secondary instrument axis: Positive PA-system looking at E, origin "DEC-like"
249 // Primary instrument axis: ??
250 // Secondary instrument axis: ??
251 seco = (latitude >= 0) ? secondary : -secondary;
252 prio = primary;
253 break;
255 seco = (latitude >= 0) ? secondary : -secondary; // northern : southern hemisphere
256 prio = primary;
257 if (seco > 90 || seco < -90) // pierside west/looking east (cf. apparentHaDecToMount())
258 {
259 // Primary instrument axis: Negative PA-system looking down from NCP:SCP, origin opposite HA-like
260 // Secondary instrument axis: Negative PA-system looking at E, origin opposite DEC-like
261 prio = primary + Angle(180.0); // Primary to Ha transformation to get negative PA-system with origin HA-like
262 seco = Angle(180.0) - seco; // Secondary to Dec transformation to get positive PA-system origin DEC-like
263 }
264 break;
265 }
266 // instrument to observed, ignore apparent
267 instrumentToObserved(prio, seco, apparentHa, apparentDec);
268 // finally rotate an AltAzm mount to the Ha/Dec coordinates
270 {
271 Angle rot = latitude - Angle(90);
272 // apparentHa and apparentDec hold corrected INDI Az and Altitude.
273 // Vector uses scopesim Az (0=South); subtract 180 deg to convert from INDI Az.
274 Vector trueAzAlt(*apparentHa - Angle(180.0), *apparentDec);
275 Vector haDec = trueAzAlt.rotateY(rot);
276 // Primary instrument axis: Negative PA-system looking down from Zenith:Nadir, origin "HA-like" ...
277 *apparentHa = haDec.primary(); // ... so there is no transformation needed!
278 // Secondary instrument axis: Positive PA-system looking east, origin "DEC-like" ...
279 *apparentDec = haDec.secondary(); // ... so there is no transformation needed!
280 LOGF_EXTRA1("ALTAZ to apparent HaDec: pri %f, sec %f to ha %f, dec %f rot %f", prio.Degrees(), seco.Degrees(), apparentHa->Degrees(),
281 apparentDec->Degrees(), rot.Degrees());
282 }
283 else
284 LOGF_EXTRA1("EQ to apparent HaDec: pri %f, sec %f to ha %f, dec %f", prio.Degrees(), seco.Degrees(), apparentHa->Degrees(),
285 apparentDec->Degrees());
286}
287
288void Alignment::mountToApparentRaDec(Angle primary, Angle secondary, Angle * apparentRa, Angle* apparentDec)
289{
290 Angle ha;
291 mountToApparentHaDec(primary, secondary, &ha, apparentDec);
292 *apparentRa = lst() - ha;
293 LOGF_EXTRA1("mount to apparent RaDec: pri %f, sec %f to ha %f, ra %f, dec %f", primary.Degrees(), secondary.Degrees(), ha.Degrees(),
294 apparentRa->Degrees(), apparentDec->Degrees());
295}
296
297void Alignment::mountToInstrumentHaDec(Angle primary, Angle secondary, Angle *instrumentHa, Angle *instrumentDec)
298{
299 // Convert axis positions to equatorial HA/Dec without any Wallace pointing-model correction.
300 // For EQ mounts the axes are already in HA/Dec space; for ALTAZ we must apply the inverse
301 // spherical rotation (Az/Alt → HA/Dec) to match what apparentHaDecToMount does, but skip
302 // the instrumentToObserved step (which applies IH/ID/CH/NP).
303 switch (mountType)
304 {
306 {
307 // primary = INDI Az (0=North), secondary = Alt.
308 // Vector uses scopesim Az (0=South); subtract 180 deg before rotating to HA/Dec.
309 Angle rot = latitude - Angle(90); // inverse of rotateY(90 - lat)
310 Vector haDec = Vector(primary - Angle(180.0), secondary).rotateY(rot);
311 *instrumentHa = haDec.primary();
312 *instrumentDec = haDec.secondary();
313 break;
314 }
316 *instrumentDec = (latitude >= 0) ? secondary : -secondary;
317 *instrumentHa = primary;
318 break;
320 {
321 Angle seco = (latitude >= 0) ? secondary : -secondary;
322 if (seco.Degrees() > 90 || seco.Degrees() < -90)
323 {
324 *instrumentHa = primary + Angle(180.0);
325 *instrumentDec = Angle(180.0) - seco;
326 }
327 else
328 {
329 *instrumentHa = primary;
330 *instrumentDec = seco;
331 }
332 break;
333 }
334 }
335}
336
337void Alignment::instrumentHaDecToMount(Angle instrumentHa, Angle instrumentDec, Angle *primary, Angle *secondary)
338{
339 switch (mountType)
340 {
342 {
343 // Convert equatorial HA/Dec to Az/Alt via spherical rotation (no Wallace errors),
344 // mirroring apparentHaDecToMount but skipping the observedToInstrument step.
345 // Vector.primary() returns scopesim Az (0=South); add 180 deg to yield INDI Az (0=North).
346 Vector altAzm = Vector(instrumentHa, instrumentDec).rotateY(Angle(90) - latitude);
347 *primary = altAzm.primary() + Angle(180.0); // INDI Az (0=North)
348 *secondary = altAzm.secondary();
349 break;
350 }
352 // Primary instrument axis: HA (negative PA-system looking down to NCP:SCP)
353 // Secondary instrument axis: Dec (positive PA-system looking E)
354 *primary = instrumentHa;
355 *secondary = (latitude >= 0) ? instrumentDec : -instrumentDec;
356 break;
358 if (instrumentHa < flipHourAngle) // pierside west (looking east)
359 {
360 // Ha axis: Negative PA-system looking down from NCP:SCP, origin HA-like
361 // Dec axis: Positive PA-system looking at E, origin DEC-like
362 *primary = instrumentHa + Angle(180); // Ha to Primary: negative PA-system with origin opposite HA-like
363 *secondary = Angle(180) - instrumentDec; // Dec to Secondary: positive PA-system with origin DEC-like
364 }
365 else
366 {
367 *primary = instrumentHa; // Ha already rotated by 180
368 *secondary = instrumentDec; // Dec already rotated by 180
369 }
370 if (latitude < 0) // southern hemisphere
371 *secondary = -*secondary;
372 break;
373 }
374}
375
376void Alignment::apparentHaDecToMount(Angle apparentHa, Angle apparentDec, Angle* primary, Angle* secondary)
377{
378 // convert to Alt Azm first
380 {
381 // rotate the apparent HaDec vector to the vertical
382 // TODO sort out Southern Hemisphere
383 Vector altAzm = Vector(apparentHa, apparentDec).rotateY(Angle(90) - latitude);
384 // azimuth in scopesim convention is 0 deg = South, increasing clockwise West->North->East
385 // INDI's IHorizontalCoordinates uses 0 deg = North.
386 Angle apparentAz = altAzm.primary() + Angle(180.0);
387 Angle apparentAlt = altAzm.secondary();
388
389 Angle instrumentAz, instrumentAlt;
390 observedToInstrument(apparentAz, apparentAlt, &instrumentAz, &instrumentAlt);
391
392 *primary = instrumentAz;
393 *secondary = instrumentAlt;
394 LOGF_EXTRA1("apparent HaDec to ALTAZ: ha %f, dec %f to pri %f, sec %f", apparentHa.Degrees(), apparentDec.Degrees(), primary->Degrees(),
395 secondary->Degrees() );
396 return; // Prevent fallthrough to equatorial override
397 }
398 // EQ: apply Wallace pointing-model correction in HA/Dec space, then delegate axis mapping.
399 // (For ALTAZ the correction is applied in Az/Alt space above, before the early return.)
400 Angle instrumentHa, instrumentDec;
401 observedToInstrument(apparentHa, apparentDec, &instrumentHa, &instrumentDec);
402 instrumentHaDecToMount(instrumentHa, instrumentDec, primary, secondary);
403 LOGF_EXTRA1("apparent HaDec to EQ: ha %f, dec %f to pri %f, sec %f", apparentHa.Degrees(), apparentDec.Degrees(), primary->Degrees(),
404 secondary->Degrees() );
405}
406
407void Alignment::apparentRaDecToMount(Angle apparentRa, Angle apparentDec, Angle* primary, Angle* secondary)
408{
409 Angle ha = lst() - apparentRa;
410 apparentHaDecToMount(ha, apparentDec, primary, secondary);
411 LOGF_EXTRA1("apparent RaDec to mount: ra %f, ha %f, dec %f to pri %f, sec %f", apparentRa.Degrees(), ha.Degrees(), apparentDec.Degrees(),
412 primary->Degrees(), secondary->Degrees());
413}
414
415#define NEW
416
417void Alignment::instrumentToObserved(Angle instrumentHa, Angle instrumentDec, Angle * observedHa, Angle* observedDec)
418{
419 static Angle maxDec = Angle(89);
420
421 // do the corrections consecutively
422 // apply Ha and Dec zero offsets
423 *observedHa = instrumentHa + IH;
424 *observedDec = instrumentDec + ID;
425
426 // apply collimation (cone) error, limited to CH * 10
427 double cosDec = *observedDec < maxDec ? std::cos(observedDec->radians()) : std::cos(maxDec.radians());
428 double tanDec = *observedDec < maxDec ? std::tan(observedDec->radians()) : std::tan(maxDec.radians());
429
430 *observedHa += (CH / cosDec);
431 // apply Ha and Dec axis non perpendiculary, limited to NP * 10
432 *observedHa += (NP * tanDec);
433
434 // Use rotations so the corrections work at the pole
435 // apply polar axis Azimuth error using rotation in the East, West, Pole plane (X)
436 Vector vMa = Vector(*observedHa, *observedDec).rotateX(MA);
437
438 // apply polar axis elevation error using rotation in the North, South, Pole plane (Y)
439 Vector vMe = vMa.rotateY(Angle(ME));
440
441 *observedHa = vMe.primary();
442 *observedDec = vMe.secondary();
443}
444
445void Alignment::observedToInstrument(Angle observedHa, Angle observedDec, Angle * instrumentHa, Angle *instrumentDec)
446{
447#ifdef NEW
448
449 // avoid errors near dec 90 by limiting sec and tan dec to 57
450 static Angle maxDec = Angle(89);
451
452 // do the corrections consecutively
453 // use vector rotations for MA and ME so they work close to the pole
454 // rotate about the EW axis (Y)
455 Vector vMe = Vector(observedHa, observedDec).rotateY(Angle(-ME));
456
457 // apply polar axis Azimuth error
458 Vector vMa = vMe.rotateX(-MA);
459
460 *instrumentHa = vMa.primary();
461 *instrumentDec = vMa.secondary();
462
463 // apply Ha and Dec axis non perpendiculary, limited to maxDec
464 double tanDec = *instrumentDec < maxDec ? std::tan(instrumentDec->radians()) : std::tan(maxDec.radians());
465 *instrumentHa -= (NP * tanDec);
466 // apply collimation (cone) error, limited to maxDec
467 double cosDec = *instrumentDec < maxDec ? std::cos(instrumentDec->radians()) : std::cos(maxDec.radians());
468 *instrumentHa -= (CH / cosDec);
469
470 // apply Ha and Dec zero offsets
471 *instrumentHa -= IH;
472 *instrumentDec -= ID;
473
474#else
475
476
477 Angle correctionHa, correctionDec;
478 correction(observedHa, observedDec, &correctionHa, &correctionDec);
479 // subtract the correction to get a first pass at the instrument
480 *instrumentHa = observedHa - correctionHa;
481 *instrumentDec = observedDec - correctionDec;
482
483 static const Angle minDelta(1.0 / 3600.0); // 1.0 arc seconds
484 Angle dHa(180);
485 Angle dDec(180);
486 int num = 0;
487 while ( num < 10)
488 {
489 // use the previously calculated instrument to get a new position
490 Angle newHa, newDec;
491 correction(*instrumentHa, *instrumentDec, &correctionHa, &correctionDec);
492 newHa = *instrumentHa + correctionHa;
493 newDec = *instrumentDec + correctionDec;
494 // get the deltas
495 dHa = observedHa - newHa;
496 dDec = observedDec - newDec;
497 // LOGF_DEBUG("observedToInstrument %i: observed %f, %f, new %f, %f, delta %f, %f", num,
498 // observedHa.Degrees(), observedDec.Degrees(),
499 // newHa.Degrees(), newDec.Degrees(), dHa.Degrees(), dDec.Degrees());
500 if (Angle(fabs(dHa.Degrees())) < minDelta && Angle(fabs(dDec.Degrees())) < minDelta)
501 {
502 return;
503 }
504 // apply the delta
505 *instrumentHa += dHa;
506 *instrumentDec += dDec;
507 num++;
508 }
509 LOGF_DEBUG("mountToObserved iterations %i, delta %f, %f", num, dHa.Degrees(), dDec.Degrees());
510#endif
511}
512
513// corrections based on the instrument position, add to instrument to get observed
514// see Patrick Wallace's white paper for details
515void Alignment::correction(Angle instrumentHa, Angle instrumentDec, Angle * correctionHa, Angle * correctionDec)
516{
517 // apply Ha and Dec zero offsets
518 *correctionHa = IH;
519 *correctionDec = ID;
520
521 // avoid errors near dec 90 by limiting sec and tan dec to 100
522 static const double minCos = 0.01;
523 static const double maxTan = 100.0;
524
525 double cosDec = std::cos(instrumentDec.radians());
526 if (cosDec >= 0 && cosDec < minCos) cosDec = minCos;
527 else if (cosDec <= 0 && cosDec > -minCos) cosDec = -minCos;
528
529 double tanDec = std::tan(instrumentDec.radians());
530 if (tanDec > maxTan) tanDec = maxTan;
531 if (tanDec < -maxTan) tanDec = -maxTan;
532
533 double cosHa = std::cos(instrumentHa.radians());
534 double sinHa = std::sin(instrumentHa.radians());
535
536 // apply collimation (cone) error, limited to CH * 10
537 *correctionHa += (CH / cosDec);
538 // apply Ha and Dec axis non perpendiculary, limited to NP * 10
539 *correctionHa += (NP * tanDec);
540
541 // apply polar axis Azimuth error
542 *correctionHa += (-MA * cosHa * tanDec);
543 *correctionDec += (MA * sinHa);
544
545 // apply polar axis elevation error
546 *correctionHa += (ME * sinHa * tanDec);
547 *correctionDec += (ME * cosHa);
548
549 LOGF_EXTRA1("correction %f, %f", correctionHa->Degrees(), correctionDec->Degrees());
550}
551
552#ifdef FALSE
554{
555 // rotate by IH and ID
556 Vector vIh = HaDec.rotateZ(Angle(IH));
557 Vector vId = vIh.rotateX(Angle(ID));
558}
559#endif
560
561void Alignment::setCorrections(double ih, double id, double ch, double np, double ma, double me)
562{
563 IH = ih;
564 ID = id;
565 CH = ch;
566 NP = np;
567 MA = ma;
568 ME = me;
569 LOGF_DEBUG("setCorrections IH %f, ID %f, CH %f, NP %f, MA %f, ME %f", IH, ID, CH, NP, MA, ME);
570}
571
573
574// Vector methods
575
576Vector::Vector(double x, double y, double z)
577{
578 double len = std::sqrt(x * x + y * y + z * z);
579 L = x / len;
580 M = y / len;
581 N = z / len;
582}
583
584Vector::Vector(Angle primary, Angle secondary)
585{
586 double sp = std::sin(primary.radians());
587 double cp = std::cos(primary.radians());
588 double ss = std::sin(secondary.radians());
589 double cs = std::cos(secondary.radians());
590
591 L = cs * cp;
592 M = cs * sp;
593 N = ss;
594}
595
597{
598 double len = length();
599 L /= len;
600 M /= len;
601 N /= len;
602}
603
605{
606 Angle a = Angle(atan2(M, L), Angle::RADIANS);
607 //IDLog("primary %f", a.Degrees());
608 return a;
609}
610
612{
613 Angle a = Angle(std::asin(N), Angle::RADIANS);
614 //IDLog("secondary %f", a.Degrees());
615 return a;
616}
617
619{
620 double ca = std::cos(angle.radians());
621 double sa = std::sin(angle.radians());
622 return Vector(L, M * ca + N * sa, N * ca - M * sa);
623}
624
626{
627 double ca = std::cos(angle.radians());
628 double sa = std::sin(angle.radians());
629 return Vector(L * ca - N * sa, M, L * sa + N * ca);
630}
631
633{
634 double ca = std::cos(angle.radians());
635 double sa = std::sin(angle.radians());
636 return Vector(L * ca + M * sa, M * ca - L * sa, N);
637}
void setCorrections(double ih, double id, double ch, double np, double ma, double me)
setCorrections set the values of the six corrections
void instrumentHaDecToMount(Angle instrumentHa, Angle instrumentDec, Angle *primary, Angle *secondary)
void apparentRaDecToMount(Angle apparentRa, Angle apparentDec, Angle *primary, Angle *secondary)
void mountToApparentHaDec(Angle primary, Angle secondary, Angle *apparentHa, Angle *apparentDec)
mountToApparentHaDec: convert mount position to apparent Ha, Dec
void apparentHaDecToMount(Angle apparentHa, Angle apparentDec, Angle *primary, Angle *secondary)
apparentHaDecToMount
void observedToInstrument(Angle observedHa, Angle observedDec, Angle *instrumentHa, Angle *instrumentDec)
void mountToApparentRaDec(Angle primary, Angle secondary, Angle *apparentRa, Angle *apparentDec)
mountToApparentRaDec: convert mount position to apparent Ra, Dec
void instrumentToObserved(Angle instrumentHa, Angle instrumentDec, Angle *observedHa, Angle *observedDec)
MOUNT_TYPE mountType
void mountToInstrumentHaDec(Angle primary, Angle secondary, Angle *instrumentHa, Angle *instrumentDec)
mountToInstrumentHaDec: convert mount axis positions to instrument (encoder) HA/Dec without applying ...
The Angle class This class implements an angle type. This holds an angle that is always in the range ...
double Degrees360()
Degrees360.
double difference(Angle a)
double radians()
radians
bool operator==(const Angle &a)
bool operator!=(const Angle &a)
double Degrees()
Degrees.
Angle TrackingRateDegSec
TrackingRateDegSec.
bool isSlewing
const char * axisName
void setDegrees(double degrees)
void StartGuide(double rate, uint32_t durationMs)
StartGuide start guiding.
void Tracking(bool enabled)
AXIS_TRACK_RATE TrackRate()
TrackRate returns the AXIS_TRACK_RATE property.
void StartSlew(Angle angle)
void update()
Angle position
double getTrackingRateDegSec()
bool isTracking()
AXIS_TRACK_RATE
The AXIS_TRACK_RATE enum defines the common track rates.
void setHours(double hours)
The Vector class This implements the Directional Cosine used by Taki in his Matrix method....
Vector rotateY(Angle angle)
rotateY rotates this vector through angle about the Y axis
Vector rotateX(Angle angle)
rotateX rotates this vector through angle about the X axis
double length()
Vector()
Vector creates an empty vector.
Vector rotateZ(Angle angle)
rotateZ rotates this vector through angle about the Z axis
void normalise()
Angle secondary()
secondary returns the secondary angle (dec, altitude) from this vector
Angle primary()
primary returns the primary angle (Ra, Ha, Azimuth) from this vector
#define M_PI
Definition dsp.h:52
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sidereal time given longitude and system clock.
char * me
Definition indidriver.c:50
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOGF_EXTRA1(fmt,...)
Definition indilogger.h:84
uint16_t type
Definition pwc-ioctl.h:0
char device_str[64]
The transformations are based on the paper "Matrix Method for Coordinates Transformation" written by ...