From e1ba34f47f41cc14a579ffd7b3c01f967a9a7c78 Mon Sep 17 00:00:00 2001 From: Michael Pulsifer Date: Wed, 25 May 2016 13:04:35 -0400 Subject: [PATCH] Fixed heat index calculations that were giving values different from NOAA's by 1 degree F in certain circumstances. Also fixed Swift-related crashes introduced since the latest release. Removed duplicate display of the state abbreviation. --- .../UserInterfaceState.xcuserstate | Bin 24802 -> 27769 bytes Heat Tool/Base.lproj/Main.storyboard | 49 ++---- Heat Tool/HeatIndexController.swift | 143 +++++++++++++----- Heat Tool/Info.plist | 4 +- 4 files changed, 117 insertions(+), 79 deletions(-) diff --git a/Heat Tool.xcodeproj/project.xcworkspace/xcuserdata/pulsifer-michael.xcuserdatad/UserInterfaceState.xcuserstate b/Heat Tool.xcodeproj/project.xcworkspace/xcuserdata/pulsifer-michael.xcuserdatad/UserInterfaceState.xcuserstate index afad0ba2b294441a4ab95f3b6749425ecf8ed4ac..5c08fd8e6d3c3fb562dfe2cd7021874fc2be039d 100644 GIT binary patch literal 27769 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 - + - + + @@ -12,11 +13,9 @@ - - @@ -38,15 +37,13 @@ - - @@ -235,7 +221,6 @@ - @@ -310,13 +295,11 @@ - + - - @@ -341,7 +324,6 @@ - @@ -350,9 +332,7 @@ - - @@ -387,13 +367,11 @@ - + - - @@ -417,7 +395,6 @@ - diff --git a/Heat Tool/HeatIndexController.swift b/Heat Tool/HeatIndexController.swift index 2f6a9b1..ffeb96e 100755 --- a/Heat Tool/HeatIndexController.swift +++ b/Heat Tool/HeatIndexController.swift @@ -51,6 +51,9 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, var inHourlyTemp = false var inHourlyHumidity = false + // Create global for troubleshooting XML parsing + var trashData = NSMutableArray() + // Create a global to keep track of risk state/background color var riskLevel = 0; @@ -121,7 +124,7 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, doneToolbar.barStyle = UIBarStyle.Default let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil) - let done: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Calculate", comment: "Calculate Button"), style: UIBarButtonItemStyle.Done, target: self, action: Selector("doneButtonAction")) + let done: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Calculate", comment: "Calculate Button"), style: UIBarButtonItemStyle.Done, target: self, action: #selector(HeatIndexController.doneButtonAction)) doneToolbar.items = NSArray(objects: flexSpace, done) as? [UIBarButtonItem] doneToolbar.sizeToFit() @@ -133,7 +136,7 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, let locationToolbar: UIToolbar = UIToolbar() locationToolbar.barStyle = UIBarStyle.Default - let useMyLocation: UIBarButtonItem = UIBarButtonItem(title: "Use My Location", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("beginGeolocation")) + let useMyLocation: UIBarButtonItem = UIBarButtonItem(title: "Use My Location", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(HeatIndexController.beginGeolocation)) locationToolbar.items = NSArray(objects: useMyLocation) as? [UIBarButtonItem] locationToolbar.sizeToFit() @@ -189,7 +192,6 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, // Use current coordinates to input and parse the NOAA API parser = NSXMLParser(contentsOfURL: (NSURL(string: "http://forecast.weather.gov/MapClick.php?lat=\(locations[locations.count-1].coordinate.latitude)&lon=\(locations[locations.count-1].coordinate.longitude)&FcstType=digitalDWML"))!)! - // South Texas, for some nice testing // parser = NSXMLParser(contentsOfURL: (NSURL(string: "http://forecast.weather.gov/MapClick.php?lat=25.902470&lon=-97.418151&FcstType=digitalDWML")))! @@ -257,24 +259,43 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, } */ func parser(parser: NSXMLParser, foundCharacters string: String) { - buffer.appendString(string) + //buffer.appendString(string) + buffer.setString(string) } func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { + + /*if elementName == "creation-date" || elementName == "production-center" { + // trashData.addObject(buffer) + // print ("trashData = " + (buffer as String)) + print("junk = " + (buffer as String)) + }*/ + if elementName == "description" || elementName == "area-description" { - self.locationTextField.text = buffer as String + var locationDescription = buffer as String + let locationDescriptionComma = locationDescription.endIndex.advancedBy(-4) + if locationDescription[locationDescriptionComma] == "," { + locationDescription = locationDescription.substringToIndex(locationDescription.endIndex.advancedBy(-4)) + } + self.locationTextField.text = locationDescription + //self.locationTextField.text = buffer as String + + print(self.locationTextField.text) } - if elementName == "start-valid-time" { - times.addObject(buffer) + if elementName == "start-valid-time" { + times.addObject((buffer as String)) + //print ("Added time to the buffer") + //print((buffer as String)) } if elementName == "value" && inHourlyTemp { - temperatures.addObject(buffer) + temperatures.addObject((buffer as String)) } if elementName == "value" && inHourlyHumidity { - humidities.addObject(buffer) + humidities.addObject((buffer as String)) + //print ("Added humidty to the buffer") } if elementName == "temperature" && inHourlyTemp { @@ -308,12 +329,18 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, } // A function to calculate the heat index from a temperature/humidity combination - func calculateHeatIndex(tempInF: Double, humidity: Double) -> Double { - // Heat index calculation applies only to temps >= 80° - if tempInF < 80.0 { + func calculateHeatIndex(tempInF: Double, humidity: Double) -> Int { + // See http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml for the methodology used below + + let simpleCalculation = 0.5 * (tempInF + 61.0 + ((tempInF - 68.0) * 1.2) + (humidity * 0.094)) + let simpleCalculationAverage = (simpleCalculation + tempInF) / 2 + + /*if tempInF < 80.0 { return tempInF - } else { - var calculatedHeatIndexF = 0.0 + } else { */ + + var calculatedHeatIndexF = simpleCalculationAverage + if simpleCalculationAverage > 80.0 { // Broke the formula up in pieces since its orginal incarnation was causing problems with Xcode calculatedHeatIndexF = -42.379 + (2.04901523 * tempInF) @@ -325,8 +352,19 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, calculatedHeatIndexF += 8.5282 * pow(10,-4) * tempInF * pow(humidity,2) calculatedHeatIndexF -= 1.99 * pow(10,-6) * pow(tempInF, 2) * pow(humidity, 2) - return round(calculatedHeatIndexF) } + + // If the RH is less than 13% and the temperature is between 80 and 112 degrees F, then the following adjustment is subtracted from HI: + if humidity < 13.0 && (tempInF >= 80.0 && tempInF <= 112.0) { + calculatedHeatIndexF -= ((13 - humidity) / 4) * sqrt((17 - abs(tempInF - 95.0)) / 17) + } + + // On the other hand, if the RH is greater than 85% and the temperature is between 80 and 87 degrees F, then the following adjustment is added to HI: + if humidity > 85.0 && (tempInF >= 80.0 && tempInF <= 87) { + calculatedHeatIndexF += ((humidity - 85) / 10) * ((87 - tempInF) / 5) + } + + return Int(round(calculatedHeatIndexF)) } // Update the "today's max" risk @@ -334,39 +372,53 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, // Look for the maximum for the rest of the day var maxIndex = -1 var maxTime:String = "" - var maxHeatIndex = -1000.0 + var maxHeatIndex = -1000 + + //print ("times = " + times) // For the next 24 hours, stopping at midnight for index in 0...23 { // Get a date object for this hour's time let newTime = (times[index] as! NSString).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) - print(" raw time= " + newTime) + //print(" raw time= " + newTime) // Get a clean 12-hour readout of this hour's time let newDateFormatter = NSDateFormatter() newDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ" let newDate = newDateFormatter.dateFromString(newTime) - // print("new date = " + newDate) - newDateFormatter.dateFormat = "h:mm a" - let newHour = newDateFormatter.stringFromDate(newDate!) - - // Stop the loop when we hit midnight - if newHour == "12:00 AM" { - break - } - - // Calculate the heat index for this hour - let newTempDouble = (temperatures[index] as! NSString).doubleValue - let newHumidityDouble = (humidities[index] as! NSString).doubleValue - let newHeatIndex = calculateHeatIndex(newTempDouble, humidity: newHumidityDouble) - - // Print out this hour's data -// println("Hour \(index): Time: \(newHour) Temp: \(temperatures[index]), Humidity: \(humidities[index])") - // If the heat index exists and is higher than previous ones, mark it as the new high - if newTempDouble > 80.0 && newHeatIndex > maxHeatIndex { - maxIndex = index - maxHeatIndex = newHeatIndex - maxTime = newTime + /*print("raw time = " + (times[index] as! String)) + print("newDateFormatter.dateFormat = " + newDateFormatter.dateFormat) + print("new date = " + newTime)*/ + + newDateFormatter.dateFormat = "HH:mm a" + // **ERROR** Code below indicates either newDateDate or newDateFormatter is nil + // Added not nil condition + if ((newDate) != nil) { + //print ("new date! Time = " + newTime) + let newHour = newDateFormatter.stringFromDate(newDate!) + //print (" new hour=" + newHour) + // Stop the loop when we hit midnight + //if newHour == "12:00 AM" { + if newHour == "00:00" { + break + } + + // Calculate the heat index for this hour + let newTempDouble = (temperatures[index] as! NSString).doubleValue + let newHumidityDouble = (humidities[index] as! NSString).doubleValue + let newHeatIndex = calculateHeatIndex(newTempDouble, humidity: newHumidityDouble) + + // Print out this hour's data + print("Hour \(index): Time: \(newHour) Temp: \(temperatures[index]), Humidity: \(humidities[index])") + + // If the heat index exists and is higher than previous ones, mark it as the new high + if newTempDouble > 80 && newHeatIndex > maxHeatIndex { + maxIndex = index + maxHeatIndex = newHeatIndex + maxTime = newTime + } + } else { + print ("NewDate is nil") } } @@ -451,8 +503,16 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, // Update the risk state/background color of the app func updateRiskLevel() { - let tempInF = Double(Int(temperatureTextField.text!)!) - let humidity = Double(Int(humidityTextField.text!)!) + + // The below two lines were giving us the "fatal error: unexpectedly found nil while unwrapping an Optional value" error. Using safer, even if more verbose code. +// let tempInF : Double? = Double(Int(temperatureTextField.text!)!) + // let humidity : Double? = Double(Int(humidityTextField.text!)!) + let tempInFString = temperatureTextField.text ?? "79" + let tempInFInt = Int(tempInFString) ?? 79 + let tempInF = Double(tempInFInt) + let humidityString = humidityTextField.text ?? "0" + let humidityInt = Int(humidityString) ?? 0 + let humidity = Double(humidityInt) let perceivedTemperature = calculateHeatIndex(tempInF, humidity: humidity) var riskTitleString = "" @@ -622,7 +682,8 @@ class HeatIndexController: GAITrackedViewController, CLLocationManagerDelegate, self.times = [] self.temperatures = [] self.humidities = [] - + //print ("URL called = " + "http://forecast.weather.gov/MapClick.php?lat=\(placemark.location!.coordinate.latitude)&lon=\(placemark.location!.coordinate.longitude)&FcstType=digitalDWML") + // Use current coordinates to input and parse the NOAA API self.parser = NSXMLParser(contentsOfURL: (NSURL(string: "http://forecast.weather.gov/MapClick.php?lat=\(placemark.location!.coordinate.latitude)&lon=\(placemark.location!.coordinate.longitude)&FcstType=digitalDWML"))!)! diff --git a/Heat Tool/Info.plist b/Heat Tool/Info.plist index f7db4b8..192d256 100755 --- a/Heat Tool/Info.plist +++ b/Heat Tool/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0 + 2.0.1 CFBundleSignature ???? CFBundleVersion - 22 + 23 LSRequiresIPhoneOS NSAppTransportSecurity