def getPrimeMeridian(cls, year): referenceRotation = Angle.stringToAngle("100d42.6") yearlyGHADecrement = Angle.stringToAngle("-0d14.32") deltaYear = year - 2001 cumulativeProgression = Angle.multiply(yearlyGHADecrement, deltaYear) dailyRotation = Angle.stringToAngle("0d59.0") leapYears = math.floor((year - 2001) / 4) leapProgression = Angle.multiply(dailyRotation, leapYears) totalProgression = Angle.add(referenceRotation, cumulativeProgression) totalProgression = Angle.add(totalProgression, leapProgression) return totalProgression
def test300_010ShouldReturnSumOfAngles(self): # Arrange # Act angle1 = Angle.stringToAngle("100d4.8") angle2 = Angle.stringToAngle("-1d0.0") # Assert result = Angle.add(angle1, angle2) self.assertEqual(result.str, "99d4.8")
def getGreenwichHourAngle(cls, year, month, day, hour, minute, second): referenceDatetime = str(year) + ",01,01,00,00,00" observationDatetime = str(year) + ',' + str(month) + ',' + str( day) + ',' observationDatetime += str(hour) + ',' + str(minute) + ',' + str( second) observationDatetime = datetime.strptime(observationDatetime, '%Y,%m,%d,%H,%M,%S') referenceDatetime = datetime.strptime(referenceDatetime, '%Y,%m,%d,%H,%M,%S') secondsSinceReference = (observationDatetime - referenceDatetime).total_seconds() relativePrimeMeridian = Aries.getPrimeMeridian(year) earthRotation = Aries.getEarthRotationSinceObservation( secondsSinceReference) return Angle.add(relativePrimeMeridian, earthRotation)
def predict(values=None): # ------ Validation ------ if values is None or not isinstance(values, dict): return {'error': 'values is not provided'} if (not ('body' in values)): return {'error': 'no body provided'} starName = values['body'] if starName not in STARS: return {'error': 'unknown star'} if "date" in values: date = values['date'] (year, month, day) = date.split('-') year = int(year) month = int(month) day = int(day) if year < 2001: return {'error': 'invalid date'} if "time" in values: time = values['time'] (hour, minute, second) = time.split(':') hour = int(hour) minute = int(minute) second = int(second) if hour > 23 or minute > 59 or second > 59: return {'error': 'invalid time'} # ------ Initialization ------ result = values body = values['body'] if 'date' in values: date = values['date'] else: date = '2001-01-01' if 'time' in values: time = values['time'] else: time = "00:00:00" sidereal = STARS[body]['sidereal'] declination = STARS[body]['declination'] # ------ Calculation ------ latitude = Angle.stringToAngle(declination) (year, month, day) = date.split("-") (hour, minute, second) = time.split(":") year = int(year) month = int(month) day = int(day) hour = int(hour) minute = int(minute) second = int(second) gha = Aries.getGreenwichHourAngle(year, month, day, hour, minute, second) sha = Angle.stringToAngle(sidereal) longitude = Angle.add(gha, sha) fullAngle = Angle.stringToAngle("-360d0.0") if longitude.hourDegree > 360: longitude = Angle.add(longitude, fullAngle) if longitude.hourDegree == 360 and longitude.minuteDegree > 0: longitude = Angle.add(longitude, fullAngle) result['lat'] = latitude.str result['long'] = longitude.str return result
def correct(values=None): # ----- Validation ----- if values is None or not isinstance(values, dict): return {'error': 'values is not provided'} if (not ('lat' in values)): return {'error': 'mandatory information missing'} if (not ('long' in values)): return {'error': 'mandatory information missing'} if (not ('altitude' in values)): return {'error': 'mandatory information missing'} if (not ('assumedLat' in values)): return {'error': 'mandatory information missing'} if (not ('assumedLong' in values)): return {'error': 'mandatory information missing'} # validate lat lat = values['lat'] x, y = lat.split("d") if int(x) < -89 or int(x) > 89: return {'error': 'lat is invalid'} y = y.lstrip("0") if float(y) < 0.0 or not float(y) < 60: return {'error': 'lat is invalid'} # validate assumedLat assumedLat = values['assumedLat'] x, y = assumedLat.split("d") if int(x) < -89 or int(x) > 89: return {'error': 'assumedLat is invalid'} y = y.lstrip("0") if float(y) < 0.0 or not float(y) < 60: return {'error': 'assumedLat is invalid'} # validate longitude longitude = values['long'] x, y = longitude.split("d") if int(x) < 0 or int(x) > 359: return {'error': 'long is invalid'} y = y.lstrip("0") if float(y) < 0.0 or not float(y) < 60: return {'error': 'long is invalid'} # validate assumed longitude assumedLong = values['assumedLong'] x, y = assumedLong.split("d") if int(x) < 0 or int(x) > 359: return {'error': 'assumedLong is invalid'} y = y.lstrip("0") if float(y) < 0.0 or not float(y) < 60: return {'error': 'assumedLong is invalid'} # validate altitude altitude = values['altitude'] x, y = altitude.split("d") if int(x) < 0 or int(x) > 89: return {'error': 'altitude is invalid'} y = y.lstrip("0") if float(y) < 0.0 or not float(y) < 60: return {'error': 'altitude is invalid'} if int(x) == 0 and float(y) < 0.1: return {'error': 'altitude is invalid'} # ----- Initialization ----- result = values lat = values['lat'] longitude = values['long'] altitude = values['altitude'] assumedLat = values['assumedLat'] assumedLong = values['assumedLong'] # ----- Calculation ----- lat = Angle.stringToAngle(lat) longitude = Angle.stringToAngle(longitude) assumedLat = Angle.stringToAngle(assumedLat) assumedLong = Angle.stringToAngle(assumedLong) altitude = Angle.stringToAngle(altitude) # calculate the local hour angle of the navigator lha = Angle.add(longitude, assumedLong) # calculate the angle to adjust the observed altitude to match # the star observed from the assumed position sin_lat = math.sin(math.radians(lat.decimal * 360)) cos_lat = math.cos(math.radians(lat.decimal * 360)) sin_assumedLat = math.sin(math.radians(assumedLat.decimal * 360)) cos_assumedLat = math.cos(math.radians(assumedLat.decimal * 360)) cos_lha = math.cos(math.radians(lha.decimal * 360)) intermediateDistance = sin_lat * sin_assumedLat + cos_lat * cos_assumedLat * cos_lha correctedAltitude = math.asin(intermediateDistance) / math.pi * 180 / 360 correctedAltitude = Angle.decimalToAngle(-correctedAltitude) # Calculate the distance the navigator needs to move to make the # observed and calculated star positions match correctedDistance = Angle.add(altitude, correctedAltitude) correctedDistance = int(correctedDistance.decimal * 60 * 360) # Determine the compass direction in which to make the distance adjustment compassDirection = math.cos(math.radians(correctedAltitude.decimal * 360)) numerator = (sin_lat - (sin_assumedLat * intermediateDistance)) denomonator = cos_assumedLat * compassDirection correctedAz = math.acos(numerator / denomonator) correctedAzDegree = math.degrees(correctedAz) correctedAzimuth = Angle.decimalToAngle(correctedAzDegree / 360) # If the correctedDistance < 0, then normalize by 1) obtaining the absolute value of the # correctedDistance and 2) adjusting the correctedAzimuth by 180 degrees if (correctedDistance < 0): correctedDistance = abs(correctedDistance) + 1 correctedAzimuth.str = str(correctedAzimuth.hourDegree + 180) + "d" + str( correctedAzimuth.minuteDegree) result['correctedDistance'] = correctedDistance result['correctedAzimuth'] = correctedAzimuth.str return result