roncli.com blog
The blog of roncli
roncli.com blog
roncli.com
blog
Profile
roncli
Houston, Texas, United States
Labels
Coding
CTG Music
Editorials
Games
Miscellaneous
Music
Servers
Silliness
Software
Sports
Trax in Space Beta
Weather
Recent Posts
A Tale of Two Communities
The Final Stretch
A Two Tiered, Untiered OTL
Secretly, you wish you could've done what I did
What have I done since roncli.com v2?
It's Done. It's Finally Done.
The Big Picture is Starting to Wear on Me
A Low Bang to Buck Ratio
win-acme
Overload has truth; next it needs balance
Archives
February 2005
March 2005
April 2005
May 2005
June 2005
July 2005
August 2005
September 2005
October 2005
November 2005
December 2005
January 2006
February 2006
March 2006
April 2006
May 2006
June 2006
July 2006
August 2006
September 2006
October 2006
November 2006
December 2006
February 2007
March 2007
April 2007
May 2007
June 2007
July 2007
August 2007
September 2007
October 2007
November 2007
December 2007
January 2008
February 2008
March 2008
April 2008
June 2008
July 2008
September 2008
December 2008
February 2009
July 2009
August 2009
September 2009
October 2009
November 2009
February 2010
March 2010
April 2010
June 2010
July 2010
August 2010
September 2010
October 2010
November 2010
December 2010
March 2011
June 2011
July 2011
August 2011
September 2011
October 2011
December 2011
January 2012
February 2012
April 2012
July 2012
November 2012
July 2013
April 2014
July 2014
August 2014
November 2014
December 2014
March 2015
April 2015
May 2015
June 2015
July 2015
September 2015
January 2016
February 2016
May 2016
July 2016
November 2016
March 2017
January 2018
May 2018
June 2018
January 2019
January 2021
February 2021
March 2021
August 2021
October 2021
December 2021
August 2022
November 2022
October 2023
February 2024
Current Posts
Thursday, March 31, 2005
Updated NWS Code
Posted: 10:17:00 PM 0 comments
Now playing: Atomship - Pencil Fight (3:38)

Mikhail's code was enough to get me started on combining all of the various parameters I wanted (just the relative ones, none of this dewpoint crap) together to come up with one single variable that has all of the forecast possible for one location.

#Region "Structs"

    Private Structure WeatherTable
        Public nodTimeLayout As XmlNode
        Public nodData As XmlNode
    End Structure

    Private Structure WeatherData
        Public wtHighTemp As WeatherTable
        Public wtLowTemp As WeatherTable
        Public wtPointTemp As WeatherTable
        Public wtLiquidPrecip As WeatherTable
        Public wtSnowPrecip As WeatherTable
        Public wtPrecipProb As WeatherTable
        Public wtWindSpeed As WeatherTable
        Public wtWindDirection As WeatherTable
        Public wtCloudCover As WeatherTable
    End Structure

    Private Structure TemperatureData
        Public F As Integer
        Public ReadOnly Property C() As Integer
            Get
                Return Integer.Parse(Math.Round(((Double.Parse(F) - 32) / 9) * 5))
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure PrecipitationData
        Public Inches As Double
        Public ReadOnly Property MM() As Double
            Get
                Return Inches * 25.4
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure PercentData
        Public Pct As Integer
        Public dt As Date
    End Structure

    Private Structure WindData
        Public Knots As Integer
        Public ReadOnly Property MPH() As Integer
            Get
                Return Integer.Parse(Math.Round((Double.Parse(Knots) * 6076.12) / 5280))
            End Get
        End Property
        Public Degrees As Integer
        Public ReadOnly Property Dir() As String
            Get
                Select Case Degrees
                    Case 0 To 11.25, 348.75 To 360
                        Return "N"
                    Case 11.25 To 33.75
                        Return "NNE"
                    Case 33.75 To 56.25
                        Return "NE"
                    Case 56.25 To 78.75
                        Return "ENE"
                    Case 78.75 To 101.25
                        Return "E"
                    Case 101.25 To 123.75
                        Return "ESE"
                    Case 123.75 To 146.25
                        Return "SE"
                    Case 146.25 To 168.75
                        Return "SSE"
                    Case 168.75 To 191.25
                        Return "S"
                    Case 191.25 To 213.75
                        Return "SSW"
                    Case 213.75 To 236.25
                        Return "SW"
                    Case 236.25 To 258.75
                        Return "WSW"
                    Case 258.75 To 281.25
                        Return "W"
                    Case 281.25 To 303.75
                        Return "WNW"
                    Case 303.75 To 326.25
                        Return "NW"
                    Case 326.25 To 348.75
                        Return "NNW"
                End Select
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure FormattedWeatherData
        Public HighTemp() As TemperatureData
        Public LowTemp() As TemperatureData
        Public PointTemp() As TemperatureData
        Public LiquidPrecip() As PrecipitationData
        Public SnowPrecip() As PrecipitationData
        Public PrecipProb() As PercentData
        Public Wind() As WindData
        Public CloudCover() As PercentData
    End Structure

#End Region

#Region "NWS XML Reader http://www.nws.noaa.gov/forecasts/xml"

    Private Function FindLayoutTable(ByVal xmlDoc As XmlDocument, ByVal nodData As XmlNode)
        Dim nlTimeLayouts As XmlNodeList = xmlDoc.SelectNodes("/dwml/data/time-layout")
        Dim strTimeLayout As String = nodData.Attributes("time-layout").Value

        Dim node As XmlNode
        For Each node In nlTimeLayouts
            If strTimeLayout = node.SelectSingleNode("layout-key").InnerText Then
                Return node
            End If
        Next

        Return Nothing
    End Function

    Private Function ParseDateTime(ByVal str As String) As Date
        Return Date.Parse(str.Replace("T", " ").Substring(0, str.LastIndexOf("-")))
    End Function

    Private Sub FillTemperatureData(ByVal wt As WeatherTable, ByRef temp() As TemperatureData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(temp) - 1
            temp(intCount) = New TemperatureData()
            temp(intCount).F = Integer.Parse(nlData(intCount).InnerText)
            temp(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
        Next
    End Sub

    Private Sub FillPrecipitationData(ByVal wt As WeatherTable, ByRef precip() As PrecipitationData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(precip) - 1
            precip(intCount) = New PrecipitationData()
            If Len(nlData(intCount).InnerText) = 0 Then
                precip(intCount).Inches = 0
            Else
                precip(intCount).Inches = Double.Parse(nlData(intCount).InnerText)
            End If
            precip(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
        Next
    End Sub

    Private Sub FillPercentData(ByVal wt As WeatherTable, ByRef pct() As PercentData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(pct) - 1
            pct(intCount) = New PercentData()
            pct(intCount).Pct = Integer.Parse(nlData(intCount).InnerText)
            pct(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
        Next
    End Sub

    Private Sub FillWindData(ByVal wtSpeed As WeatherTable, ByVal wtDir As WeatherTable, ByRef wind() As WindData)
        Dim intCount As Integer

        Dim nlSpeed As XmlNodeList = wtSpeed.nodData.SelectNodes("value")
        Dim nlDir As XmlNodeList = wtDir.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wtSpeed.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(wind) - 1
            wind(intCount) = New WindData()
            wind(intCount).Knots = Integer.Parse(nlSpeed(intCount).InnerText)
            wind(intCount).Degrees = Integer.Parse(nlDir(intCount).InnerText)
            wind(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
        Next
    End Sub

    Private Function ParseForecastXML(ByVal strXMLWeather) As FormattedWeatherData
        Try
            'Setup variables
            Dim xmlDoc As New XmlDocument()
            Dim wdData As New WeatherData()
            Dim fwdData As New FormattedWeatherData()
            wdData.wtHighTemp = New WeatherTable()
            wdData.wtLowTemp = New WeatherTable()
            wdData.wtPointTemp = New WeatherTable()
            wdData.wtLiquidPrecip = New WeatherTable()
            wdData.wtSnowPrecip = New WeatherTable()
            wdData.wtPrecipProb = New WeatherTable()
            wdData.wtWindSpeed = New WeatherTable()
            wdData.wtWindDirection = New WeatherTable()
            wdData.wtCloudCover = New WeatherTable()

            'Load XML data
            xmlDoc.LoadXml(strXMLWeather)

            'Load data and their corresponding time nodes
            wdData.wtHighTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='maximum']")
            wdData.wtLowTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='minimum']")
            wdData.wtPointTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='hourly']")
            wdData.wtLiquidPrecip.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/precipitation[@type='liquid']")
            wdData.wtSnowPrecip.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/precipitation[@type='snow']")
            wdData.wtPrecipProb.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/probability-of-precipitation[@type='12 hour']")
            wdData.wtWindSpeed.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/wind-speed[@type='sustained']")
            wdData.wtWindDirection.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/direction[@type='wind']")
            wdData.wtCloudCover.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/cloud-amount[@type='total']")

            wdData.wtHighTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtHighTemp.nodData)
            wdData.wtLowTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtLowTemp.nodData)
            wdData.wtPointTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtPointTemp.nodData)
            wdData.wtLiquidPrecip.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtLiquidPrecip.nodData)
            wdData.wtSnowPrecip.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtSnowPrecip.nodData)
            wdData.wtPrecipProb.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtPrecipProb.nodData)
            wdData.wtWindSpeed.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtWindSpeed.nodData)
            wdData.wtWindDirection.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtWindDirection.nodData)
            wdData.wtCloudCover.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtCloudCover.nodData)

            'Setup formatted data variables
            ReDim fwdData.HighTemp(wdData.wtHighTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.LowTemp(wdData.wtLowTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.PointTemp(wdData.wtPointTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.LiquidPrecip(wdData.wtLiquidPrecip.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.SnowPrecip(wdData.wtSnowPrecip.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.PrecipProb(wdData.wtPrecipProb.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.Wind(wdData.wtWindSpeed.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.CloudCover(wdData.wtCloudCover.nodTimeLayout.SelectNodes("start-valid-time").Count)

            'Fill in data
            FillTemperatureData(wdData.wtHighTemp, fwdData.HighTemp)
            FillTemperatureData(wdData.wtLowTemp, fwdData.LowTemp)
            FillTemperatureData(wdData.wtPointTemp, fwdData.PointTemp)
            FillPrecipitationData(wdData.wtLiquidPrecip, fwdData.LiquidPrecip)
            FillPrecipitationData(wdData.wtSnowPrecip, fwdData.SnowPrecip)
            FillPercentData(wdData.wtPrecipProb, fwdData.PrecipProb)
            FillWindData(wdData.wtWindSpeed, wdData.wtWindDirection, fwdData.Wind)
            FillPercentData(wdData.wtCloudCover, fwdData.CloudCover)

            Return fwdData

        Catch ex As Exception
            Return Nothing
        End Try
    End Function

#End Region


A little more complicated in some ways, a bit simpler in others, but the data is complete. To call the web service and retrieve the data:

        Dim weather As New gov.weather.ndfdXML()
        Dim params As New gov.weather.weatherParametersType()
        params.maxt = True
        params.mint = True
        params.temp = True
        params.qpf = True
        params.snow = True
        params.pop12 = True
        params.wspd = True
        params.wdir = True
        params.sky = True
        Dim fwdWeather as FormattedWeatherData = ParseForecastXML(weather.NDFDgen(sngLatitude, sngLongitude, "time-series", Now, Now.AddDays(30), params))
        weather = Nothing
        params = Nothing


fwdWeather now has all the forecasting data you need. It also has easy functions to convert F to C, Knots to MPH, and Inches to Millimeters.

Not bad for a day of research and coding! Now if only they'd make web services for current conditions and severe weather statements, I'd be all set.

Labels: , ,

Damn Hackers
Posted: 5:51:00 PM 0 comments
Now playing: Atomship - Pencil Fight (3:38)

I've been using w.bloggar as my method to post since I started this thing... It's very useful and puts a little "b" in the systray, which I leave visible all the time as a reminder for me to not ignore my blog. It's worked rather well so far, until I've had to edit a post.

Apparantly, w.bloggar is getting some sort of "invalid property value" whenever I try to load up an old post. It loads the text fine, but when I go to update the post, it actually creates a NEW post.

No problem, I figure, I'll just go to the website, wbloggar.com, check for a new version, or report a bug. Well, I guess they have an invalid property value thing going on too, no site comes up. A quick run at the source reveals the reason.

<!--r00t by Team g0dmode, greets to BasS-Z & Para Sh4rk!-->

PWNED!!!!!1111one11!!1onetwo11six11shiftone!!!111½½¼¼¼ Bastard hackers.

Labels: , ,

NWS XML web service for VB.Net
Posted: 5:35:00 PM 3 comments
Now playing: Atomship - Pencil Fight (3:38)

In my quest for consuming the NWS XML Web Service, I came across this blog post by Mikhail Arkhipov over at Microsoft. He has available for download a bit of code that allows you to consume said web service. Problem is, it's in C#.Net.

After reading the code and finally understanding NWS's NDFD format, I went ahead and converted the C#.Net code to VB.Net. Now, this isn't the first time I've done something with C# code, so it was fairly easy to go through the code and come up with a VB.Net equivalent. In fact, it was dead easy.

Anyway, I figured I'd post my conversion. The code is practically identical, except I chagned the variable names to suit the standards I'm used to.

First, create a new project and add a web reference to http://weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php?wsdl. This will hook you into NWS's free service.

Second, add this bit of code to your project.

#Region "Structs"

    Private Structure DayWeatherData
        Public dtDate As Date
        Public strLowTempF As String
        Public strHighTempF As String
        Public strLowTempC As String
        Public strHighTempC As String
        Public strCloudIconURL As String
    End Structure

    Private Structure WeatherTable
        Public nodTimeLayout As XmlNode
        Public nodData As XmlNode
    End Structure

#End Region

#Region "NWS XML Reader http://www.nws.noaa.gov/forecasts/xml"
    'Converted to VB.Net by Ronald M. Clifford
    'Original C#.Net by Mikhail Arkhipov

    Private Function FindLayoutTable(ByVal xmlDoc As XmlDocument, ByVal nodData As XmlNode)
        Dim nlTimeLayouts As XmlNodeList = xmlDoc.SelectNodes("/dwml/data/time-layout")
        Dim strTimeLayout As String = nodData.Attributes("time-layout").Value

        Dim node As XmlNode
        For Each node In nlTimeLayouts
            If strTimeLayout = node.SelectSingleNode("layout-key").InnerText Then
                Return node
            End If
        Next

        Return Nothing
    End Function

    Private Sub FillLowTemperatures(ByVal nodXML As XmlNode, ByRef dwdData() As DayWeatherData)
        Dim nlNodes As XmlNodeList = nodXML.SelectNodes("value")

        Dim intCount As Integer
        For intCount = 0 To UBound(dwdData) - 1
            dwdData(intCount).strLowTempF = nlNodes(intCount).InnerText
            dwdData(intCount).strLowTempC = Math.Round(5 * (Double.Parse(dwdData(intCount).strLowTempF) - 32) / 9).ToString
        Next
    End Sub

    Private Sub FillHighTemperatures(ByVal nodXML As XmlNode, ByRef dwdData() As DayWeatherData)
        Dim nlNodes As XmlNodeList = nodXML.SelectNodes("value")

        Dim intCount As Integer
        For intCount = 0 To UBound(dwdData) - 1
            dwdData(intCount).strHighTempF = nlNodes(intCount).InnerText
            dwdData(intCount).strHighTempC = Math.Round(5 * (Double.Parse(dwdData(intCount).strHighTempF) - 32) / 9).ToString
        Next
    End Sub

    Private Function ParseDateTime(ByVal str As String) As Date
        Return Date.Parse(str.Replace("T", " ").Substring(0, str.LastIndexOf("-")))
    End Function

    Private Sub FillDayNameAndTime(ByVal nodLows As XmlNodeList, ByVal nodHighs As XmlNodeList, ByRef dwdData() As DayWeatherData)
        ' Choose first elemnt from low or high list depending on what is close to the current time.
        ' Typically weather report is about 'today' or 'tonight' on the current day or about
        ' day temperatures for the coming days. Therefoce remaining elements always come from
        ' the high temperatures list.

        Dim dtFirstLow As Date = ParseDateTime(nodLows(0).InnerText)
        Dim dtFirstHigh As Date = ParseDateTime(nodHighs(0).InnerText)
        Dim dtNow As Date = Now
        Dim nlNodes As XmlNodeList

        If dtFirstLow.Day = dtNow.Day And dtFirstHigh.Day = dtNow.Day Then
            ' choose nearest
            Dim intDiffFromLow = Math.Abs(dtFirstLow.Hour - dtNow.Hour)
            Dim intDiffFromHigh = Math.Abs(dtFirstHigh.Hour - dtNow.Hour)

            If intDiffFromHigh < intDiffFromLow Then
                nlNodes = nodHighs
            Else
                nlNodes = nodLows
            End If
        ElseIf dtFirstHigh.Day = dtNow.Day Then
            ' choose highs
            nlNodes = nodHighs
        Else
            ' choose lows
            nlNodes = nodLows
        End If

        Dim intCount As Integer

        For intCount = 0 To UBound(dwdData) - 1
            Dim dt As Date = ParseDateTime(nlNodes(intCount).InnerText)

            If intCount = 0 Then
                dwdData(intCount).dtDate = dt
            Else
                dwdData(intCount).dtDate = New Date(dt.Year, dt.Month, dt.Day, 12, 0, 0)
            End If
        Next
    End Sub

    Private Sub FillCloudData(ByVal wt As WeatherTable, ByRef dwdData() As DayWeatherData)
        ' Cloud data is typically much longer than day high/low data
        ' We need to find times that match ones in high and low temp tables.
        Dim nlTimes As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        Dim nlIcons As XmlNodeList = wt.nodData.SelectNodes("icon-link")

        Dim intWeatherData As Integer = 0
        Dim intNodes As Integer = 0
        Dim intHourDiff As Integer = Integer.MaxValue

        Dim nodXML As XmlNode
        For Each nodXML In nlTimes
            Dim dt As Date = ParseDateTime(nodXML.InnerText)

            If dt.Date > dwdData(intWeatherData).dtDate.Date Then
                intWeatherData += 1

                If intWeatherData > UBound(dwdData) Then Exit For

                intHourDiff = Integer.MaxValue
            End If

            If dt.Date = dwdData(intWeatherData).dtDate.Date Then
                Dim intDiff As Integer = Math.Abs(dt.Hour - dwdData(intWeatherData).dtDate.Hour)

                If intDiff < intHourDiff Then
                    intHourDiff = intDiff
                    dwdData(intWeatherData).strCloudIconURL = nlIcons(intNodes).InnerText
                End If
            End If

            intNodes += 1
        Next
    End Sub

    Private Function ParseWeatherXML(ByVal strXMLWeather) As DayWeatherData()
        Try
            Dim dwd() As DayWeatherData
            Dim xmlDoc As New XmlDocument()

            ' load XML data into a tree
            xmlDoc.LoadXml(strXMLWeather)

            ' locate dwml/data/time-layout nodes. There should be three of them: 
            '      - next week nighttime temperatures (lows)
            '      - next week daytime temperatures (highs)
            '      - next week cloud data

            ' Find roots nodes for temperature and cloud data
            Dim wtLowTemp As New WeatherTable()
            Dim wtHighTemp As New WeatherTable()
            Dim wtClouds As New WeatherTable()

            wtLowTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='minimum']")
            wtHighTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='maximum']")
            wtClouds.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/conditions-icon")

            ' Find out corresponding time layout table for each top data node
            wtLowTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wtLowTemp.nodData)
            wtHighTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wtHighTemp.nodData)
            wtClouds.nodTimeLayout = FindLayoutTable(xmlDoc, wtClouds.nodData)

            ' Number of day data is min of low and high temperatures
            Dim nlLowTimes As XmlNodeList = wtLowTemp.nodTimeLayout.SelectNodes("start-valid-time")
            Dim nlHighTimes As XmlNodeList = wtHighTemp.nodTimeLayout.SelectNodes("start-valid-time")

            Dim intTimes As Integer = Math.Min(nlLowTimes.Count, nlHighTimes.Count)

            Dim dwdData(intTimes) As DayWeatherData

            Dim intCount As Integer
            For intCount = 0 To intTimes - 1
                dwdData(intCount) = New DayWeatherData()
            Next

            ' Fill highs and lows
            FillLowTemperatures(wtLowTemp.nodData, dwdData)
            FillHighTemperatures(wtHighTemp.nodData, dwdData)

            FillDayNameAndTime(nlLowTimes, nlHighTimes, dwdData)

            FillCloudData(wtClouds, dwdData)

            Return dwdData

        Catch ex As Exception
            Return Nothing
        End Try
    End Function

#End Region


Finally, simply make a call to their web service.

        Dim weather As New gov.weather.ndfdXML()
        Dim params As New gov.weather.weatherParametersType()
        params.maxt = True
        params.mint = True
        params.icons = True
        Dim strWeatherXML As String = weather.NDFDgen(39, -77, "time-series", Now, Now.AddDays(5), params)
        weather = Nothing
        params = Nothing
        Dim dwdWeather() As DayWeatherData = ParseWeatherXML(strWeatherXML)


You now have a DayWeatherData object, dwdWeather, that contains the highs and lows for the day, along with a URL to an icon that displays the type of weather to expect for the day. This is ultra basic. If you check out the NWS site, you'll find there are many other options you can add in, including cloud cover, percipitation chance and amount, and a couple other things. You'll have to code the XML reader to parse these things, but it's pretty easily done. And best of all, it's free!

The only down side to this is that you need to come up with the latitude and longitude (negative for the western hemisphere) for the location you want to use, which means you'll need to grab a Zip Code to latitude & longitude database.

Labels: , ,

Web Junkie
Posted: 5:16:00 PM 0 comments
Now playing: Atomship - Pencil Fight (3:38)

Here it is about 5:15 in the afternoon. I've been up since about 8 in the morning, mostly trying to figure out the NWS XML web service. I eventually got it (more on that in my next post) thanks to a website that had downloadable code available that consumes the service.

So, I wanted to make a post here in my blog about it. I open up Crazy Browser, got to the history, and click on "today". How many freaking websites did I visit today?! The list is absolutely ENORMOUS, showing over 100 sites.

Am I a junkie or what?

Labels: , , ,

Monday, March 28, 2005
Lose That Buger Belly!
Posted: 7:21:00 PM 0 comments
Found this inside our regular Chic-Fil-A in Meyerland.

Labels: , ,

Sleep is Needed?
Posted: 3:43:00 PM 0 comments
Now playing: dfast - rauhaisa (3:05)

I can code VB in my sleep. C++ is a different story.

After pulling a 30 hour marathon Saturday/Sunday for no reason other than I wasn't tired, I woke up this morning (I think it was around 1:30 AM) and did stuff throughout the day. About 12 hours into being awake, I started playing with the textboxes again. I fixed some annoying bugs I was having with them, and then decided that I would start adding features. One of which is the ability to use the tab key to go between textboxes.

Well, it wasn't working, and I couldn't for the life of me figure out what was wrong. I went into the debugger to see what the key code was. It was coming back as a "9" as expected. Alright, that meant that it was likely the "9" didn't equal CSKEY_TAB. Right? I go and look, and CSKEY_TAB is defined to '\t'.

This is where the lack of sleep comes in. I thought, "Oh wait, \t is 20! It should be \i instead!!"

So I spent an hour trying to figure out 1) Why CSKEY_TAB wasn't '\i', and 2) Why tab worked in OTHER Crystal Space applications. After looking around for some documentation on keyboard events in Crystal Space and finding nothing, I decided to work up the nerve to ask on #crystalspace on IRC. The conversation went something like this.

roncli: Hmm. CSKEY_TAB is defined as '\t' (20), but when I hit tab, it's coming back with '\i' (9)... Is that normal?
res2k: roncli: \t should be 9
res2k: looks to me like you believe '\X' would resolve to the index of X in the alphabet, which is totally wrong

That's when the error in what I was doing sunk in, and when I decided to crawl into a little hole for a while I went back and studied what I apparantly didn't learn reading my C++ materials.

Labels: , , ,

Sunday, March 27, 2005
More on Textboxes
Posted: 11:25:00 AM 0 comments
I went ahead and played some more with Textboxes, and they really weren't too hard to figure out. About the toughest time I had is what to do with Backspace & Delete. But it handles most things right now, with the rest of the required features soon on its way. Once I get through making textboxes working right, the rest of the settings page is going to seem like a breeze.

Labels: , , ,

Saturday, March 26, 2005
Making Textboxes Ain't Easy
Posted: 7:52:00 PM 0 comments
Now playing: Peter Enroth - Tarmdansen (3:00)

In Cent there is going to be several places where you can type in text. Naturally, I want to have a decent GUI and give the user a textbox within which they may place their text. In VB, or anything else that's got a form designer for that matter, this is a snap. Just drag and drop a textbox onto your form and you've got yourself a nice textbox.

However, I'm not using a form designer. Instead, I'm coding every aspect of the display, which means I can't just drag and drop things. For images, buttons, and text this isn't too bad. However, the fun began when I wanted a textbox a user can edit.

Now, Crystal Space has some sort of Windowing System. I didn't look too much into it, but from what I gather it's quite complicated. So I figured I'd do my own controls. How hard can it be anyway?

Textboxes hurt. Think of all the things you take for granted. When you click inside a textbox, what actually happens? You've gotta figure out where in the textbox the user clicked. But that's not enough! You have to calculate what character is at the point the user clicked, find out if it's closer that character's left side or right side, and move the cursor there. To do this, you must know how wide each character is and exactly where on the screen it is positioned.

And what if the text is too wide for the field? AARGH!!! As you can see, this gets really ugly really quick. Thank goodness for reusable code.

In any case, so far I've got my text box properly clickable so that the cursor appears in the right place. I just have to add in the eye candy (I-beam mouse when you're over the textbox, and a flashing cursor), and the ability to actually... you know... type characters into the box.

Moving? Yes. Slowly? Definitely.

Labels: , , ,

Liquid War
Posted: 4:02:00 PM 0 comments
Perhaps the craziest and most addictive game I've played in a long time, check out Liquid Wars. It has many different maps along with skill settings you can tweak. And it's visually mesmerizing, too.

Labels: ,

Wednesday, March 23, 2005
#modarchive Story 2
Posted: 2:41:00 AM 0 comments
New #mas2 time to beat is 14'56"!

Labels: , ,

Sunday, March 20, 2005
Poker
Posted: 4:59:00 AM 0 comments
Texas Hold'em, all in, with a pair of 5's in the hole, and a 5 and two 8's showing... losing to a straight flush... ugh! It's tough losing with a full house, but still a heck of a lot of fun. I'll definitely have to go poker playing again in the near future.

Labels: ,

Friday, March 18, 2005
Slow Going
Posted: 2:16:00 AM 0 comments
Now playing: troupe - rfc1459 (3:19)

I've been working on the routines to load, save, and manipulate the pilot and controller profiles in preparation of getting the settings section of Cent fully functional. So far it's been like most programming tasks - long, drawn out, and quite repetative.

So needless to say, it's been slow going, but the good news is that it's at least been going. It's still going to be a while before I have a nice 3D shot up here, but my mantra of "functionality before beauty" and the knowledge that I'm doing things the right way the first time (hopefully!) keeps me motivated.

I've actually thought about taking a break to start designing some maps for the game, but my mild unfamiliarity with Blender combined with the fact that there is no good Crystal Space exporter from within Blender (at least not using the latest buggy Python version anyway, that's another story in and of itself) kinda makes me wanna pass for now and focus on the programming aspect.

Plus there's still OSMusic stuff to work on, which I haven't touched in quite some time. So many projects, so little time. Who's bright idea was it to only put 24 hours in a day anyway? It needs at least 40.

Labels: , , , , ,

Tuesday, March 15, 2005
Troupe
Posted: 8:14:00 PM 0 comments
Now playing: roncli, The Nightstalker - Cent Credits (2:40)

Met up with Troupe today, who's in town with his family. Didn't do much more than talk shop about Reason/ModPlug/Renoise/Outpost/CTG/TiS, but it was still fun. I'm hoping we can get together and whip out some totally kickass tune at some point before he leaves, he's a very talented musician, worth checking out!

Labels: ,

Music Clean Up
Posted: 8:11:00 PM 0 comments
Now playing: roncli, The Nightstalker - Cent Main Theme (2:28)

I cleaned up the Cent Music a bit. centMain.ogg is of higher quality, and has a new guitar solo to boot. I am still not entirely pleased with it yet, especially the fake-sounding guitar, but it's getting there. centCredits.ogg is also new, I replaced the piano with a better sounding one. Horray for Reason 3.0!

Labels: , ,

Sunday, March 13, 2005
Cent Settings Screenshot
Posted: 11:47:00 PM 0 comments
Now playing: AmBeam - Heartland (9:34)

Just posting a screenshot of the settings page for Cent.

Labels: , , ,

Saturday, March 12, 2005
Comparing Cherries to Pears
Posted: 5:35:00 PM 0 comments
Now playing: roncli, The Nightstalker - Cent Credits (2:37)

Read a blog post today about the product CherryOS, which is essentially a Mac OS X emulator for Windows. It turns out that CherryOS stole most of their code from PearPC, and are categorically denying it.

How stupid do you have to be to rip off someone else's software? I mean really, in this day and age when people will sue at the drop of the hat for ridiculously stupid things, this company's really gotta have its head in the ground if they believe that just because it's open source means that they're not going to get sued. Sure, the people running PearPC may not have the time or resources to start a lawsuit, but it's just a matter of time before someone does on their behalf.

Incredible the idiocy of some people.

Labels: , ,

Friday, March 11, 2005
Cent files moved
Posted: 6:05:00 PM 0 comments
Now playing: roncli, The Nightstalker - roncli Productions Intro (0:13)

I moved the cent stuff out of the music directory. You can now see it all at http://www.roncli.com/music/cent, and peruse the directory yourself.

Labels: , , ,

Thursday, March 10, 2005
Cent Main Theme
Posted: 10:48:00 PM 0 comments
More Cent music, this time the Main Theme.

Cent's just about all I've been working on in my spare time, hence the lack of updates. When I get some more exciting screenshots, I'll start posting. In the meantime, enjoy the soundtrack.

Labels: ,

Tuesday, March 08, 2005
Cent Credits
Posted: 7:47:00 PM 0 comments
Now playing: roncli, The Nightstalker - Cent Credits (2:37)

I finished up the credits tune today, had a bit of fun on my keyboard making it too. It took me back about 12 years when I used to write tunes solely for the piano all the time. Anyway, check out Cent Credits. If you've listened to the intro tune I posted earlier, the beginning and end of this one follow the same theme.

Labels: ,

New Music
Posted: 11:09:00 AM 0 comments
Now playing: roncli, The Nightstalker - roncli Productions Intro (0:13)

Just a note that I have a new piece up, roncli Productions Intro. It's a 13s OGG file that will serve as the intro for Cent.

I'm working on the credits version, which is basically just a piano version of this combined with the main theme. The upside is that I will be recording it all into reason with my MIDI keyboard, so it should sound pretty sweet.

Labels: ,

Monday, March 07, 2005
Google Desktop Search
Posted: 1:04:00 PM 0 comments
Now playing: Karmann - Number 27 (5:30)

Google continues to impress me with the quality of the products that they put out. Today I downloaded the Google Desktop Search. Easy install, and great integration with your desktop. Get this, it'll even put search results from your desktop into your google.com search results, all without sending anything to Google. It's absolutely brilliant, and makes all my other file finding utilities I've downloaded over the years irrelevant.

Google rocks.

Labels: ,

Saturday, March 05, 2005
Crystal Space
Posted: 10:47:00 AM 0 comments
What have I been working on?



This is my pet project lately, working with Crystal Space to make an application. What sort of application? Well, it's not very far along yet, so giving out any details would be unfair.

But the interesting thing about this is that I understand the engine, and even with my limited knowledge of C++, I can do some pretty neat things. How far will this go? Only time will tell.

Labels: , , , ,

Thursday, March 03, 2005
Crystal Space
Posted: 8:44:00 PM 0 comments
Now playing: Karmann - Number 27 (5:30)

I've spent the last couple of days - in between tweaking video settings - playing with the Crystal Space engine. For the first time, I am beginning to really understand C++ classes, and the result is the language getting easier for me to learn. I still get occasional oddities that I'm not immediately sure how to resolve, but they are becoming more and more trivial.

That said, the Crystal Space engine is really nice. Not only does it have a full 3D renderer, but it takes care of a lot of common problems associated with coding a 3D app. If this takes off, I'll be able to do some seriously cool things with it.

Labels: ,

Pushing the Limits
Posted: 6:48:00 AM 0 comments
Now playing: RedHeat Sonic Soundscapes - Outer Circle (Vocal, Dance) (4:50)

A followup on the screen resolution.

I did end up finding a good application called PowerStrip that allows you to totally tweak out your monitor and customize it's resolutions.

Not only can I experience the computing bliss of 2048 by 1536 at a eye-pleasing 64 Hz, I can also play Descent 3 at a screen resolution of 800 by 600 at a mind-blowing 158 Hz! The game is so fluid at that refresh rate, very enjoyable experience.

The only thing that bothers me about my ungodly large resolution is patches of bright white. I've actually tweaked the contrast down about a bit, and may go more should I get bothered by it. But for now, I'm content stretching my monitor's capabilities to the limit!

Labels: , ,

Wednesday, March 02, 2005
Side Effects
Posted: 1:01:00 PM 0 comments
Now playing: Sagal - National Geographic Mix (11:37)

I don't know where or why, but at some point I lost Open GL capability on my Raedon 8500. I ended up going to ati.com for the latest drivers just to be safe.

It didn't fix my OpenGL problem, but the next time I showed up in the Display Properties, I had a surprise waiting for me - more video options! For the past several years I've been running at a 1600 by 1200 resolution, largely because my 19" Mag Innovision monitor supposedly can't do more.

Well, these new drivers certainly put this monitor in it's place. It can go as high as 1920 by 1440! Unfortunately for me, that is only available in a 60 Hz refresh rate which kills my eyes, I have found through testing I need at least 66 Hz.

However, I was able to squeeze another 384,000 pixels out of my desktop, expanding the right edge of my screen by a full 320 pixels to a new resolution of 1920 by 1200, running at 75 Hz! It's going to take a while to get used to the horizontal compression I'm sure, but hey, I'll take all the pixels I can get. The more, the merrier.

I've heard of some programs that allow you to tweak the refresh rate of your video. I may try that later and see if I can't fake out my monitor to run the 1920 by 1440 at 66 Hz or more, which is approximately the lower limit of comfort for my eyes. But for now, viva la desktop real estate!

Oh yeah, if you know how to fix my OpenGL, let me know...

Labels: ,

Attention BitTorrent Client Writers
Posted: 10:53:00 AM 0 comments
Have you ever heard of MULTITHREADING for Pete's sake?!

I've now downloaded four different BitTorrent clients, all of which choke on the MAME complete ROM set, because there's thousands of files to download and whoever coded these lame BitTorrent clients didn't realize that it would be used for that purpose. Come on, people, have a little decency and be nice to your users, make your GUI not lock up when it's got a lot to do...

Labels: , ,

Tuesday, March 01, 2005
Clearing Up Space
Posted: 10:17:00 AM 0 comments
Well, after about a week or so of struggling with my quickly evaporating hard drive space, I decided to do something about it. I went through all my Program Files and uninstalled everything I didn't use anymore, and deleted all of the shell folders that were left behind from previous installations. Everything went crisp and clean, and to my knowledge I didn't delete anything I needed.

The problem started when I compared the output from Disk Size Manager to my actual free space. Approximately 76,000 MB of hard drive space, approximately 6,000 MB free. DSM reported I had used 62,700 MB of disk space.

76,000 - 6,000 > 62,700. Where were the other 7 or so GB?

My first instinct was permissions. I quickly logged out and logged on as Administrator. Of course, my user account has Administrator access, so the 62,700 persisted.

Now, 6 GB is a lot of space to be honest. The problem is with NASCAR SimRacing wanting 4 GB for some ridiculous reason, and I still have about 5 GB left of CHDs to download for my full MAME collection. So I probably wouldn't have even dealt with it if I didn't have a need for the space.

Anyway, I did some searching around on Google and found a couple of possibilities. The one that worked for me was the System Restore option. Sure enough, I go in, and there it is taking up 10% - A full seven and a half gigs - of disk space. I move that down to 1%, reboot, and for the first time in months, I have double digit free space!

What annoys me the most about is is that, although Windows is reporting free space correctly, it's not reporting used space correctly. Where does Windows put the System Restore data if not on the C: drive? It's stupid.

Oh well, that's one problem licked. That's what matters.

Labels: , , , ,

Phone Features Poll
Posted: 6:49:00 AM 0 comments
Now playing: Sagal - The Tragidy of Love (7:02)

Found a poll on neowin.net that asked what features would you use most on a phone. Answers ranged from MP3 Player, to Radio, to Internet, even Chat and Text Messaging.

The number one response, of course, was "Phoning!", proving that not all hope is lost in the realm of common sense.

Labels: ,