{ "info": { "author": "Daniel Kraft", "author_email": "dk@d9t.de", "bugtrack_url": null, "classifiers": [ "Framework :: Zope3", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "==============================\nD9T GIS / Area Search Solution\n==============================\n\n------------\nIntroduction\n------------\n\nThis package aims to bring you close to a ready-usable area search\nfor existing \"addresses\" within a given distance from a starting point.\n\nThis was developed for germany, where any place has a zip-code. We wanted\nto have a search functionality to find objects that are \"close\" (i.e. within\na defined distance) to a given location.\n\nYou could also use any other key which points to coordinates with little\neffort. The only requirement is that the key is unique.\n\nFor this, zip codes are the best available solution for us. We have a free list\nof zip codes and corresponding gis information for germany (see data directory).\nThis list is from the opengeodb project and licensed as public domain:\nhttp://sourceforge.net/projects/opengeodb/\n\n\n-----------\nBoilerplate\n-----------\n\nFirst, let's load the required zcml as this is a unit test.\n >>> from Products.Five.zcml import load_config, load_string\n >>> import d9t.gis\n >>> import Products.Five\n >>> import five.localsitemanager\n >>> load_config('configure.zcml', package=Products.Five)\n >>> load_config('configure.zcml', package=five.localsitemanager)\n >>> load_config('configure.zcml', package=d9t.gis)\n\n-----\nUsage\n-----\n\nMeasurable Objects\n==================\n\nA measurable object has to provide ICoordinate, which also may be\nprovided by an adapter.\n\nLet's define a generic address class (minimalistic and incomplete, i know).\n\n >>> from zope.interface import implements, Interface\n >>> from zope.component import queryUtility, adapts\n >>> from d9t.gis.interfaces import ICoordinate, ICoordinateProvider\n\n >>> class Address(object):\n ... implements(ICoordinate)\n ...\n ... def __init__(self, country, zip):\n ... zip_coordinate_provider = queryUtility(ICoordinateProvider)\n ... coordinate = zip_coordinate_provider.coordinate(country, zip)\n ... self.latitude = coordinate.latitude\n ... self.longitude = coordinate.longitude\n\nNow let's generate a few addresses.\n\n >>> a1 = Address(\"DE\", \"89073\")\n >>> a2 = Address(\"DE\", \"88299\")\n\nYou can also create simple Coordinates. A demo Coordinate class is included:\n\n >>> from d9t.gis.coordinate import Coordinate\n >>> c1 = Coordinate(9.99968113200213, 48.4052825255534) # DE 89073\n >>> c2 = Coordinate(10.0191253966503, 47.8117109627977) # DE 88299\n\nIt should be noted that ZipCoordinateProvider loads the gis data from csv on zope startup.\nThis takes far less then a second and we decided that storing the data in\nzodb wouldn't have any advantage.\n\nCalculating Distance\n====================\n\n >>> from d9t.gis.interfaces import IDistanceCalculation\n >>> distance_util = queryUtility(IDistanceCalculation)\n\nYou can measure distance between anything that provides ICoordinate. So:\nBetween Coordinates\n\n >>> distance_util.distance(c1, c2)\n 65.033485081783098\n\nBetween Addresses\n\n >>> distance_util.distance(a1, a2)\n 65.033485081783098\n\nBetween Coordinates and Addresses\n\n >>> distance_util.distance(a1, c2)\n 65.033485081783098\n >>> distance_util.distance(a1, c1)\n 0.0\n\nCommon usage\n============\n\nProbably you already have some address objects which are unaware of\ngis information. Maybe you want - and this is indeed a good idea -\nto prevent your address - objects to even know about gis information.\n\nYou can have all gis features by providing an ICoordinate Adapter for\nyour objects.\n\nImagine we have a already existing class which is unaware of any gis info:\n\n >>> class IMyAddress(Interface):\n ... \"\"\" \"\"\"\n\n >>> class MyAddress(object):\n ... implements(IMyAddress)\n ... address = \"\"\n ... zip_code = \"\"\n ... city = \"\"\n ... country = \"\"\n ... def __init__(self, address, zip_code, city, country):\n ... self.address, self.zip_code, self.city, self.country = address, zip_code, city, country\n\nYou would then have objects of that type:\n\n >>> my_a1 = MyAddress(\"Ilextwiete 12\", \"22455\", \"Hamburg\", \"DE\")\n >>> my_a2 = MyAddress(\"Gangweg 2\", \"80797\", \"Muenchen\", \"DE\")\n\nFor measuring distance, your objects have to provide ICoordinate. So let's\ncreate an adapter which simply uses a ready-to-use utility to get the coordinates.\n\n >>> class MyAddressCoordinate(object):\n ... implements(ICoordinate)\n ... adapts(IMyAddress)\n ...\n ... def __init__(self, my_address):\n ... self.my_address = my_address\n ... zip_coordinate_provider = queryUtility(ICoordinateProvider)\n ... coordinate = zip_coordinate_provider.coordinate(self.my_address.country, self.my_address.zip_code)\n ... self.latitude = coordinate.latitude\n ... self.longitude = coordinate.longitude\n\nYou would usually provide the adapter in your zcml, but as this is a testcase,\nwe'll do it here:\n\n >>> from zope.app.testing import ztapi\n >>> ztapi.provideAdapter(IMyAddress, ICoordinate, MyAddressCoordinate)\n\nThen you can measure as usual:\n\n >>> distance_util.distance(my_a1, my_a2)\n 624.79554959923701\n\n\nGet nearby places\n=================\n\nIf you want to know which of several addresses are the closest to a given one, just\ngive the utility a list of known ICoordinate and one to look for. You will get back\na list of tuples where [0] is the distance and [1] is the original object.\nBtw: As you will see any adaptable object will be ok and returned as-is.\n\nLet's measure what are the nearest 3 to Muenchen (my_a2) from this list:\n\n >>> nearest = distance_util.nearest(my_a2, (my_a1, my_a2, c1, c2, a1, a2))\n >>> [\"%s (%s)\" % (n[0], n[1].__class__) for n in nearest]\n [\"0.0 ()\", \"175.137634687 ()\", \"175.137634687 ()\", \"175.24792832 ()\", \"175.24792832 ()\", \"624.795549599 ()\"]\n\nYou can also limit the search to e.g. 3 results (sorted of course):\n\n >>> nearest = distance_util.nearest(my_a2, (my_a1, my_a2, c1, c2, a1, a2), 3)\n >>> [\"%s (%s)\" % (n[0], n[1].__class__) for n in nearest]\n [\"0.0 ()\", \"175.137634687 ()\", \"175.137634687 ()\"]\n\n\nGet nearby ZIPs\n===============\n\nIn case you need all zips within a given distance around a given coordinate, you might\nfind the INearbyZips utility useful.\n\n >>> from zope.component import getUtility\n >>> from d9t.gis.interfaces import INearbyZips, IDistanceCalculation\n >>> nbz = getUtility(INearbyZips)\n >>> distance_util = getUtility(IDistanceCalculation, name=\"km\")\n >>> nbz.nearbyZips(c1, distance_util.toRadiant(10))\n set([('DE', '89077'), ('DE', '89231'), ('DE', '89075'), ('DE', '89073')])\n\nThis was for 10km. \nAttention! This only works away from radiant bounderies. Stay away from +-180 degrees!\nThis is due to speed optimizations. Sorry ;)\n\n\n--------\nAdvanced\n--------\n\nNearby places with portal_catalog\n=================================\n\nWhen using portal_catalog, you only get brains back which have no usable\ninterface to adapt to. Then, please don't getObject() anything. It's a\nwaste.\n\nInstead, create a decorator for the brains like that:\n\n >>> class MyAddressBrainCoordinateDecorator(object):\n ... implements(ICoordinate)\n ... def __init__(self, brain):\n ... self.brain = brain\n ... zip_coordinate_provider = queryUtility(ICoordinationProvider)\n ... coordinate = zip_coordinate_provider.coordinate(brain.getCountry, brain.getZip)\n ... self.latitude = coordinate.latitude\n ... self.longitude = coordinate.longitude\n\nThen decorate your brains before using them for nearest search and get them back\nafter the search:\n\n >>> brains = []\n >>> decorated_brains = [MyAddressBrainCoordinateDecorator(brain) for brain in brains]\n >>> nearest = distance_util.nearest(my_a2, decorated_brains, 5)\n >>> brains = [decorated_brain.brain for decorated_brain in decorated_brains]\n\nToo bad, that way the laziness of the portal_catalog search is gone. But with\na result set of less than 100 that shouldn't really matter. If your set is\nbig enough for performance impacts, any ideas are welcome.\n\n\nHave fun ;)\n\n\nChangelog\n=========\n\nd9t.gis - 0.4 [20120525]\n\n - Fixed a bug where a rounding error (caused by float) crashed\n with ValueError: math domain error when the lookup-coordinate\n were identical to one in the list, i.e. when the distance\n should have been 0.\n\nd9t.gis - 0.3 [20081217]\n\n - Added nearby Zips utility (FAST, no. DAMN FAST!) [Daniel Kraft, Oliver Roch]\n - Added named distance utility for miles and km [Daniel Kraft, Oliver Roch]\n - Made zip database pluggable. You may now code your sql implementation. [Daniel Kraft, Oliver Roch]\n\nd9t.gis - 0.2\n\n - Fully functional and complete doctest available.\n [Daniel Kraft]\n\n\nd9t.gis - 0.1 Unreleased\n\n - Initial package structure.\n [zopeskel]", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://d9t.de/", "keywords": "", "license": "GPLv3", "maintainer": null, "maintainer_email": null, "name": "d9t.gis", "package_url": "https://pypi.org/project/d9t.gis/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/d9t.gis/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://d9t.de/" }, "release_url": "https://pypi.org/project/d9t.gis/0.4/", "requires_dist": null, "requires_python": null, "summary": "GIS Tools", "version": "0.4" }, "last_serial": 788743, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "e8d17104edb6c662c428d72c26caeb65", "sha256": "2db74548aa4b3831601fc6b26eb09113d195e77a1c584d671c940e32c3cb8159" }, "downloads": -1, "filename": "d9t.gis-0.2.tar.gz", "has_sig": false, "md5_digest": "e8d17104edb6c662c428d72c26caeb65", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 416812, "upload_time": "2008-04-15T11:13:06", "url": "https://files.pythonhosted.org/packages/46/8b/35187ba7df22f919f72f1d3ed6bb45e64abea2663013d4c113cb89b303ae/d9t.gis-0.2.tar.gz" } ], "0.2dev": [ { "comment_text": "", "digests": { "md5": "a2c4f3edeb48f4eaed515d1342e48b75", "sha256": "833cf9c86192716eac040d6d1feec65c57b1aecedf296dcd06a8646df629835b" }, "downloads": -1, "filename": "d9t.gis-0.2dev.tar.gz", "has_sig": false, "md5_digest": "a2c4f3edeb48f4eaed515d1342e48b75", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 416846, "upload_time": "2008-04-15T10:07:51", "url": "https://files.pythonhosted.org/packages/18/b2/23074d5e56dc7f182326b219451b6138d431a20181d81a6fca9bc936ee96/d9t.gis-0.2dev.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "fa3e768e9218f08879dddb6f54fbb95b", "sha256": "196e0e4f0b17447f9dbf16c7fab11f14bd0ff52ca5d733870f5d4ed0cd286c7a" }, "downloads": -1, "filename": "d9t.gis-0.3.tar.gz", "has_sig": false, "md5_digest": "fa3e768e9218f08879dddb6f54fbb95b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 418128, "upload_time": "2008-12-17T13:45:55", "url": "https://files.pythonhosted.org/packages/01/ee/7f353983425ffa3cd8e84f765191849d4224c651dbb00414d3c36911bb23/d9t.gis-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "38faaa31d37f72ac7c2459ba2689ca44", "sha256": "1e3f4e794c004efcf991331c2f2ae237dac2f1f68bb2105d6581e90a5645f1a7" }, "downloads": -1, "filename": "d9t.gis-0.4.tar.gz", "has_sig": false, "md5_digest": "38faaa31d37f72ac7c2459ba2689ca44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 418378, "upload_time": "2012-05-25T14:51:30", "url": "https://files.pythonhosted.org/packages/a4/aa/85523c25e11491969f9d0b00269a707cec026940ba7e7012ece439f63cc4/d9t.gis-0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "38faaa31d37f72ac7c2459ba2689ca44", "sha256": "1e3f4e794c004efcf991331c2f2ae237dac2f1f68bb2105d6581e90a5645f1a7" }, "downloads": -1, "filename": "d9t.gis-0.4.tar.gz", "has_sig": false, "md5_digest": "38faaa31d37f72ac7c2459ba2689ca44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 418378, "upload_time": "2012-05-25T14:51:30", "url": "https://files.pythonhosted.org/packages/a4/aa/85523c25e11491969f9d0b00269a707cec026940ba7e7012ece439f63cc4/d9t.gis-0.4.tar.gz" } ] }