65.9K
CodeProject 正在变化。 阅读更多。
Home

从数据库映射邮政编码

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.45/5 (18投票s)

2004年7月26日

4分钟阅读

viewsIcon

140850

downloadIcon

1785

使用经度、纬度和邮政编码来绘制美国地图,然后在地图上标记出数据库中匹配到的邮政编码。

Sample Image - zipcodemapping.gif

引言

这个应用程序是为了帮助我了解我的地址列表的人口统计信息而设计的。我很好奇,不同的人分布在美国大陆的哪些地方。过了一段时间,我找到了一些有趣的资料,为我指明了方向,但没有一个能让我直接使用,我还是得自己写解决方案……所以,这就是我的解决方案……邮政编码映射解决方案(免费)。请耐心对待这篇文章,这是我发布的第一篇文章……

工作原理

数据库

这个应用程序包含一些相当简单的源代码……但核心内容和亮点来自数据库。在演示数据库中,您会找到两个表和三个查询。

  • 表 1:PUBLISHERS

    (这是微软提供的样本数据表,通常情况下,这会是您的客户群……或者您想映射的任何人。)

  • 表 2:ZIPCODES

    (这个表是我通过美国人口普查局和我在网上找到的免费邮政编码数据库整理出来的。

  • 查询 1:ALLZIPS

    (这个查询只是从ZIPCODES表中过滤出所有不在美国大陆的邮政编码。)

  • 查询 2:ZIPCODEADDRESS

    (这个查询也过滤掉不在美国大陆的邮政编码,同时移除“PUBLISHERS”表中的 `null` 邮政编码、非数字邮政编码(例如,外国邮政编码)以及空格。)

  • 查询 3:ZIPLOCATIONS

    (这个查询计算每个邮政编码的人数,获取经纬度,并通过匹配 `ZIPCODEADDRESS` 和 `ZIPCODES` 表来列出邮政编码。)

数学原理

为了实现这个功能,我必须确定一些数学公式。基本上,应用程序需要做的是将邮政编码缩放到一个网格中,基于经纬度坐标转换为图像上的像素。以下是所需的数据(这些在演示项目中都有解释)。

  • +48.987386 是美国大陆的最高纬度
  • +18.005611 是一个低于最南纬度的纬度(用于缓冲)
  • -124.626080 是美国大陆最西端的经度
  • -62.361014 是一个比最东端经度更靠东的经度(用于缓冲)

要计算比例尺,我只是计算了纬度的差值,然后除以我的图像高度……然后计算了经度的差值,再除以我的图像宽度。例如:

我选择了一个 701w x 565h 像素的图像。为了计算比例尺,我做了如下计算:

Latitude:  (48.987386-18.005611)/565h  = .054835 latitude  unit/pixel
Longitude: (124.656080-67.040767)/701w = .088866 longitude unit/pixel

为了将这些转换为代码,我创建了两个函数:

Function getLat(byVal y1)
    Return cInt((48.987386 - (cDbl(y1))) / 0.054835)
End Function
Function getLong(byVal x1)
    Return cInt((124.62608 - (cDbls(x1) * -1)) / 0.088866)
End Function

*请注意,经度乘以了 -1……这是为了使其成为正数,以便进行减法运算。

现在,有了这些函数,我就可以简单地将数据库中的纬度和经度发送给这些函数,以获得我需要绘制地图的正确像素区域。

应用程序

现在我们已经确定了画布的大小和比例尺,我们就可以创建一个画布了。

    'declare variables
    Dim objBitmap As Bitmap = New Bitmap(701, 565) 
    Dim objGraphics As Graphics = Graphics.FromImage(objBitmap)

    'create the colors and the shapes
    Dim objBrush As SolidBrush = _
      New SolidBrush(System.Drawing.Color.LightGray) 'for US Contour
    Dim objWhite As SolidBrush = _
      New SolidBrush(System.Drawing.Color.White) 'for background
    Dim objNewBrush As SolidBrush
    Dim myRect As Rectangle

在这里,我创建了 `Bitmap` 和 `Graphics` 对象来进行绘制。我还创建了一些画笔来绘制一些东西。

下一步是访问数据库中的所有数据。我用 Oracle 9i 和 MS Access 都测试过……只要您更改数据来源,一切都会正常工作。因此,我将跳过数据库连接的部分,因为您应该能够自己解决……如果不行,演示程序中仍然包含这部分内容。

我采取的第一步(也许有更简单的方法)是绘制一个白色的矩形作为我的位图背景。

    myRect = New Rectange(0,0,701,565)
    objGraphics.FillRectangle(objWhite, myRect)

下一步是选择“ALLZIPS”表中的**所有**记录,并在每条记录的位置绘制一个点。(这在我的电脑上其实很快,但结果可能有所不同。)

    rs.Open("SELECT * FROM ALLZIPS", DB, 3, 3)
    
    'LOOP THROUGH
    WHILE NOT RS.EOF
        myRect = New Rectangle(getLong(rs("LONGITUDE").value)+50, _
                                getLat(rs("LATITUDE").value)+50,2,2)
        objGraphics.FillEllipse(objBrush, myRect)
        rs.MoveNext()
    Wend

正如您所注意到的,它正在创建(2x2)的椭圆,颜色为 `LightGray`,位于由“getLong({DB-LONGITUDE})”和“getLat({DB-LATITUDE})”指定的坐标处,我添加了 50 像素作为图像的周围边距。

现在,我再次执行此操作,但使用我想要用不同颜色标记的记录。

    rs.close 'close previous recordset
    rs.open("SELECT * FROM ZIPLOCATIONS"), DB, 3, 3)
    'LOOP THROUGH
    WHILE NOT RS.EOF
        myRect = New Rectangle(getLong(rs("LONGITUDE").value)+50, _
                                getLat(rs("LATITUDE").value)+50,4,4)
        'now determine the color based on number of matches
        Select Case (rs("ZIPCOUNT").Value)
        Case 1
            objNewBrush = New SolidBrush(System.Drawing.Color.RoyalBlue)
        Case 2
            objNewBrush = New SolidBrush(System.Drawing.Color.MediumSeaGreen)
        Case 3
            objNewBrush = New SolidBrush(System.Drawing.Color.LawnGreen)
        Case 4
            objNewBrush = New SolidBrush(System.Drawing.Color.OliveDrab)
        Case 5
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkKhaki)
        Case 6
            objNewBrush = New SolidBrush(System.Drawing.Color.Goldenrod)
        Case 7
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkOrange)
        Case 8
            objNewBrush = New SolidBrush(System.Drawing.Color.Coral)
        Case 9
            objNewBrush = New SolidBrush(System.Drawing.Color.Red)
        Case 10
            objNewBrush = New SolidBrush(System.Drawing.Color.Firebrick)
        Case Else
            objNewBrush = New SolidBrush(System.Drawing.Color.DarkRed)
        End Select
        'fill the ellipse with the selected color
        objGraphics.FillEllipse(objNewBrush, myRect)
        rs.MoveNext()
    Wend

此时,图像已经绘制并存储在变量中……所以我们只需要完成图像的导出,并将其设置为 `Image` 对象。

    'finish up
    objBitmap.Save(Server.MapPath(Request.ApplicationPath) _
            & "\newGlobe.gif", Imaging.ImageFormat.Gif)
    objGraphics.Dispose()
    objBitmap.Dispose()
    rs.Close()

    'set source
    imageButton.ImageUrl = "newGlobe.gif"

就这么简单……您需要的一切都已完成。

附加评论

演示程序中还有一个过程可以帮助您“缩放”,该过程基于 Harish Palaniappan 的文章(也曾在 CodeProject 上找到)。我希望这篇文章对您有所帮助,我非常想听听谁将此应用程序用于他们的网站。请在下方留下评论。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.