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 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 test400_010ShouldReturnProductOfAngles(self): # Arrange # Act angle = Angle.stringToAngle("0d59.0") result = Angle.multiply(angle, 3) # Assert self.assertEqual(result.str, "2d56.9")
def test100_010ShouldReturnStringConvertedToAngle(self): # Arrange # Act angle = Angle.stringToAngle("164d54.5") # Assert self.assertEqual(angle.hourDegree, 164) self.assertEqual(angle.minuteDegree, 54.5) self.assertAlmostEqual(angle.decimal, 0.458, places=3)
def locate(values=None): # ----- Validation ----- if values is None or not isinstance(values, dict): return {'error': 'values is not provided'} if (not ('assumedLat' in values)): return {'error': 'mandatory information missing'} if (not ('assumedLong' in values)): return {'error': 'mandatory information missing'} if (not ('corrections' in values)): return {'error': 'mandatory information missing'} # 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 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 corrections corrections = values['corrections'] corrections = corrections.split(', ') for correction in corrections: correctedDistance, correctedAzmuth = correction.split(",") # remove brackets correctedAzmuth = correctedAzmuth.replace(']', "") correctedAzmuth = correctedAzmuth.replace(']', "") correctedDistance = correctedDistance.replace('[', "") correctedDistance = correctedDistance.replace('[', "") # validate corrected distance correctedDistance = float(correctedDistance) if correctedDistance < 0: return {'error': 'correctedDistance is invalid'} # ----- Initialization ------ result = values assumedLat = values['assumedLat'] assumedLong = values['assumedLong'] corrections = values['corrections'] # ----- Calculation ----- # add corrections to dict corrections = corrections.split(', ') # Calculate the present position as the vector sum of the corrections for each sighting: nsCorrection = 0 ewCorrection = 0 n = len(corrections) for correction in corrections: correctedDistance, correctedAzmuth = correction.split(",") # remove brackets correctedAzmuth = correctedAzmuth.replace(']', "") correctedAzmuth = correctedAzmuth.replace(']', "") correctedDistance = correctedDistance.replace('[', "") correctedDistance = correctedDistance.replace('[', "") correctedAzmuth = Angle.stringToAngle(correctedAzmuth) correctedAzmuth.decimal = correctedAzmuth.hourDegree + ( correctedAzmuth.minuteDegree / 60) correctedDistance = float(correctedDistance) nsCorrection += correctedDistance * math.cos( math.radians(correctedAzmuth.decimal)) ewCorrection += correctedDistance * math.sin( math.radians(correctedAzmuth.decimal)) nsCorrection = nsCorrection / n ewCorrection = ewCorrection / n assumedLat = Angle.stringToAngle(assumedLat) assumedLat.decimal = assumedLat.hourDegree + (assumedLat.minuteDegree / 60) assumedLat.decimal = assumedLat.decimal + (nsCorrection / 60) left, right = str(assumedLat.decimal).split(".") right = "0." + right right = float(right) right = right * 60 right = round(right, 1) result['presentLat'] = str(int(left)) + "d" + str(right) assumedLong = Angle.stringToAngle(assumedLong) assumedLong.decimal = assumedLong.hourDegree + (assumedLong.minuteDegree / 60) assumedLong.decimal = assumedLong.decimal + (ewCorrection / 60) left, right = str(assumedLong.decimal).split(".") right = "0." + right right = float(right) right = right * 60 right = round(right, 1) result['presentLong'] = str(int(left)) + "d" + str(right) # Estimate the precision of the present position by measuring the uniformity of the input corrected distance/corrected azimuth pairs: precision = 0 for correction in corrections: correctedDistance, correctedAzmuth = correction.split(",") # remove brackets correctedAzmuth = correctedAzmuth.replace(']', "") correctedAzmuth = correctedAzmuth.replace(']', "") correctedDistance = correctedDistance.replace('[', "") correctedDistance = correctedDistance.replace('[', "") correctedAzmuth = Angle.stringToAngle(correctedAzmuth) correctedAzmuth.decimal = correctedAzmuth.hourDegree + ( correctedAzmuth.minuteDegree / 60) correctedDistance = float(correctedDistance) a = math.pow( ((correctedDistance * math.cos(math.radians(correctedAzmuth.decimal))) - nsCorrection), 2) b = math.pow( ((correctedDistance * math.sin(math.radians(correctedAzmuth.decimal))) - ewCorrection), 2) precision += math.sqrt(a + b) precision = (1.0 / n) * precision left, right = str(precision).split(".") result['precision'] = left result['accuracy'] = 'NA' return result
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