地理信息系统工具
d9t.gis的Python项目详细描述
简介
这个包的目的是让你接近一个现成的可用区域搜索 对于现有的“地址”在一个给定的距离从起点。
这是为德国开发的,任何地方都有邮政编码。我们想要 具有搜索功能以查找“接近”的对象(即 一段规定的距离)。
你也可以使用任何其他的关键点来协调 努力。唯一的要求是密钥是唯一的。
为此,邮政编码是我们最好的解决方案。我们有免费的名单 德国邮政编码和相应的地理信息系统信息(见数据目录)。 此列表来自opengeodb项目,并被授权为公共域: http://sourceforge.net/projects/opengeodb/
样板
- 首先,我们加载所需的zcml,因为这是一个单元测试。
>>> from Products.Five.zcml import load_config, load_string >>> import d9t.gis >>> import Products.Five >>> import five.localsitemanager >>> load_config('configure.zcml', package=Products.Five) >>> load_config('configure.zcml', package=five.localsitemanager) >>> load_config('configure.zcml', package=d9t.gis)
用法
可测量对象
一个可测量的物体必须提供像坐标,也可以是 由适配器提供。
让我们定义一个通用地址类(我知道,它是极简的和不完整的)。
>>> from zope.interface import implements, Interface >>> from zope.component import queryUtility, adapts >>> from d9t.gis.interfaces import ICoordinate, ICoordinateProvider>>> class Address(object): ... implements(ICoordinate) ... ... def __init__(self, country, zip): ... zip_coordinate_provider = queryUtility(ICoordinateProvider) ... coordinate = zip_coordinate_provider.coordinate(country, zip) ... self.latitude = coordinate.latitude ... self.longitude = coordinate.longitude
现在让我们生成几个地址。
>>> a1 = Address("DE", "89073") >>> a2 = Address("DE", "88299")
也可以创建简单的坐标。包括演示坐标类:
>>> from d9t.gis.coordinate import Coordinate >>> c1 = Coordinate(9.99968113200213, 48.4052825255534) # DE 89073 >>> c2 = Coordinate(10.0191253966503, 47.8117109627977) # DE 88299
需要注意的是,zipcoordinateprovider在zope启动时从csv加载gis数据。 这需要的时间远远少于一秒钟,我们决定将数据存储在 佐德不会有任何优势。
计算距离
>>> from d9t.gis.interfaces import IDistanceCalculation >>> distance_util = queryUtility(IDistanceCalculation)
您可以测量任何提供图标坐标的对象之间的距离。所以: 坐标之间
>>> distance_util.distance(c1, c2) 65.033485081783098
地址之间
>>> distance_util.distance(a1, a2) 65.033485081783098
在坐标和地址之间
>>> distance_util.distance(a1, c2) 65.033485081783098 >>> distance_util.distance(a1, c1) 0.0
常见用法
可能你已经有了一些地址对象 地理信息系统信息。也许你想-这确实是个好主意- 防止你的地址对象知道地理信息系统的信息。
您可以通过为 你的物品。
假设我们有一个已经不存在任何GIS信息的类:>>> class IMyAddress(Interface): ... """ """>>> class MyAddress(object): ... implements(IMyAddress) ... address = "" ... zip_code = "" ... city = "" ... country = "" ... def __init__(self, address, zip_code, city, country): ... self.address, self.zip_code, self.city, self.country = address, zip_code, city, country
然后您将拥有该类型的对象:
>>> my_a1 = MyAddress("Ilextwiete 12", "22455", "Hamburg", "DE") >>> my_a2 = MyAddress("Gangweg 2", "80797", "Muenchen", "DE")
为了测量距离,你的物体必须提供坐标。所以让我们 创建一个适配器,它只需使用一个随时可用的实用程序来获取坐标。
>>> class MyAddressCoordinate(object): ... implements(ICoordinate) ... adapts(IMyAddress) ... ... def __init__(self, my_address): ... self.my_address = my_address ... zip_coordinate_provider = queryUtility(ICoordinateProvider) ... coordinate = zip_coordinate_provider.coordinate(self.my_address.country, self.my_address.zip_code) ... self.latitude = coordinate.latitude ... self.longitude = coordinate.longitude
您通常会在zcml中提供适配器,但由于这是一个测试用例, 我们在这里做:
>>> from zope.app.testing import ztapi >>> ztapi.provideAdapter(IMyAddress, ICoordinate, MyAddressCoordinate)
然后您可以像往常一样测量:
>>> distance_util.distance(my_a1, my_a2) 624.79554959923701
就近到达
如果你想知道几个地址中哪一个最接近给定的地址,只需 为实用程序提供一个已知图标坐标的列表和一个要查找的列表。你会回来的 元组列表,其中[0]是距离,[1]是原始对象。 顺便说一句:正如你所看到的,任何可适应的对象都是可以的,并按原样返回。
让我们从这个列表中测量离muenchen(my_a2)最近的3是什么:
>>> nearest = distance_util.nearest(my_a2, (my_a1, my_a2, c1, c2, a1, a2)) >>> ["%s (%s)" % (n[0], n[1].__class__) for n in nearest] ["0.0 (<class 'MyAddress'>)", "175.137634687 (<class 'Address'>)", "175.137634687 (<class 'd9t.gis.coordinate.Coordinate'>)", "175.24792832 (<class 'Address'>)", "175.24792832 (<class 'd9t.gis.coordinate.Coordinate'>)", "624.795549599 (<class 'MyAddress'>)"]
您还可以将搜索限制为3个结果(当然是排序的):
>>> nearest = distance_util.nearest(my_a2, (my_a1, my_a2, c1, c2, a1, a2), 3) >>> ["%s (%s)" % (n[0], n[1].__class__) for n in nearest] ["0.0 (<class 'MyAddress'>)", "175.137634687 (<class 'Address'>)", "175.137634687 (<class 'd9t.gis.coordinate.Coordinate'>)"]
靠近拉链
如果你需要在给定的坐标周围一定距离内的所有拉链,你可以 找到有用的inearbysips实用程序。
>>> from zope.component import getUtility >>> from d9t.gis.interfaces import INearbyZips, IDistanceCalculation >>> nbz = getUtility(INearbyZips) >>> distance_util = getUtility(IDistanceCalculation, name="km") >>> nbz.nearbyZips(c1, distance_util.toRadiant(10)) set([('DE', '89077'), ('DE', '89231'), ('DE', '89075'), ('DE', '89073')])
这是10公里。 注意!这只适用于远离辐射的边界。远离+180度! 这是由于速度优化。抱歉;)
高级
附近有门户网站目录
使用portal_catalog时,只会得到无法使用的大脑 要适应的接口。那么,请不要获取object()任何内容。是一个 浪费。
相反,为大脑创建一个这样的装饰器:
>>> class MyAddressBrainCoordinateDecorator(object): ... implements(ICoordinate) ... def __init__(self, brain): ... self.brain = brain ... zip_coordinate_provider = queryUtility(ICoordinationProvider) ... coordinate = zip_coordinate_provider.coordinate(brain.getCountry, brain.getZip) ... self.latitude = coordinate.latitude ... self.longitude = coordinate.longitude
然后在用它们进行最近的搜索之前装饰你的大脑并把它们找回来 搜索后:
>>> brains = [] >>> decorated_brains = [MyAddressBrainCoordinateDecorator(brain) for brain in brains] >>> nearest = distance_util.nearest(my_a2, decorated_brains, 5) >>> brains = [decorated_brain.brain for decorated_brain in decorated_brains]
也一样糟糕的是,这样一来门户目录搜索的惰性就消失了。但是 一个小于100的结果集并不重要。如果你的套装是 足够大的性能影响,任何想法都是受欢迎的。
玩得开心;)
变更日志
d9t.gis-0.4[20120525]
- Fixed a bug where a rounding error (caused by float) crashed with ValueError: math domain error when the lookup-coordinate were identical to one in the list, i.e. when the distance should have been 0.
d9t.gis-0.3[20081217]
- Added nearby Zips utility (FAST, no. DAMN FAST!) [Daniel Kraft, Oliver Roch]
- Added named distance utility for miles and km [Daniel Kraft, Oliver Roch]
- Made zip database pluggable. You may now code your sql implementation. [Daniel Kraft, Oliver Roch]
d9t.gis-0.2
- Fully functional and complete doctest available. [Daniel Kraft]
d9t.gis-0.1未发布
- Initial package structure. [zopeskel]