pax_global_header00006660000000000000000000000064122605712010014506gustar00rootroot0000000000000052 comment=c39bfc815fb62dc1213a4e8f25795b0587345f3e Shapely-1.3.0/000077500000000000000000000000001226057120100131145ustar00rootroot00000000000000Shapely-1.3.0/.gitignore000066400000000000000000000002201226057120100150760ustar00rootroot00000000000000*.pyc VERSION.txt Shapely.egg-info/ build/ dist/ docs/_build/ shapely/speedups/_speedups.* docs/shapely.*.txt docs/shapely.txt docs/modules.txt Shapely-1.3.0/.travis.yml000066400000000000000000000006431226057120100152300ustar00rootroot00000000000000language: python python: - "2.6" - "2.7" - "3.2" - "3.3" before_install: - sudo add-apt-repository -y ppa:ubuntugis/ppa - sudo apt-get update -qq - sudo apt-get install -qq libgeos-dev - if [[ $TRAVIS_PYTHON_VERSION == "2.6" ]]; then pip install unittest2; fi - pip install -r requirements-dev.txt install: - python setup.py build script: "python setup.py test" notifications: email: false Shapely-1.3.0/CHANGES.txt000066400000000000000000000200141226057120100147220ustar00rootroot00000000000000Changes ======= 1.3.0 (2013-12-31) ------------------ - Include support for Python 3.2 and 3.3 (#56), minimum version is now 2.6. - Switch to GEOS WKT/WKB Reader/Writer API, with defaults changed to enable 3D output dimensions, and to 'trim' WKT output for GEOS >=3.3.0. - Use GEOS version instead of GEOS C API version to determine library capabilities (#65). 1.2.19 (2013-12-30) ------------------- - Add buffering style options (#55). 1.2.18 (2013-07-23) -------------------- - Add shapely.ops.transform. - Permit empty sequences in collection constructors (#49, #50). - Individual polygons in MultiPolygon.__geo_interface__ are changed to tuples to match Polygon.__geo_interface__ (#51). - Add shapely.ops.polygonize_full (#57). 1.2.17 (2013-01-27) ------------------- - Avoid circular import between wkt/wkb and geometry.base by moving calls to GEOS serializers to the latter module. - Set _ndim when unpickling (issue #6). - Don't install DLLs to Python's DLL directory (#37). - Add affinity module of affine transformation (#31). - Fix NameError that blocked installation with PyPy (#40, #41). 1.2.16 (2012-09-18) ------------------- - Add ops.unary_union function. - Alias ops.cascaded_union to ops.unary_union when GEOS CAPI >= (1,7,0). - Add geos_version_string attribute to shapely.geos. - Ensure parent is set when child geometry is accessed. - Generate _speedups.c using Cython when building from repo when missing, stale, or the build target is "sdist". - The is_simple predicate of invalid, self-intersecting linear rings now returns ``False``. - Remove VERSION.txt from repo, it's now written by the distutils setup script with value of shapely.__version__. 1.2.15 (2012-06-27) ------------------- - Eliminate numerical sensitivity in a method chaining test (Debian bug #663210). - Account for cascaded union of random buffered test points being a polygon or multipolygon (Debian bug #666655). - Use Cython to build speedups if it is installed. - Avoid stumbling over SVN revision numbers in GEOS C API version strings. 1.2.14 (2012-01-23) ------------------- - A geometry's coords property is now sliceable, yielding a list of coordinate values. - Homogeneous collections are now sliceable, yielding a new collection of the same type. 1.2.13 (2011-09-16) ------------------- - Fixed errors in speedups on 32bit systems when GEOS references memory above 2GB. - Add shapely.__version__ attribute. - Update the manual. 1.2.12 (2011-08-15) ------------------- - Build Windows distributions with VC7 or VC9 as appropriate. - More verbose report on failure to speed up. - Fix for prepared geometries broken in 1.2.11. - DO NOT INSTALL 1.2.11 1.2.11 (2011-08-04) ------------------- - Ignore AttributeError during exit. - PyPy 1.5 support. - Prevent operation on prepared geometry crasher (#12). - Optional Cython speedups for Windows. - Linux 3 platform support. 1.2.10 (2011-05-09) ------------------- - Add optional Cython speedups. - Add is_cww predicate to LinearRing. - Add function that forces orientation of Polygons. - Disable build of speedups on Windows pending packaging work. 1.2.9 (2011-03-31) ------------------ - Remove extra glob import. - Move examples to shapely.examples. - Add box() constructor for rectangular polygons. - Fix extraneous imports. 1.2.8 (2011-12-03) ------------------ - New parallel_offset method (#6). - Support for Python 2.4. 1.2.7 (2010-11-05) ------------------ - Support for Windows eggs. 1.2.6 (2010-10-21) ------------------ - The geoms property of an empty collection yields [] instead of a ValueError (#3). - The coords and geometry type sproperties have the same behavior as above. - Ensure that z values carry through into products of operations (#4). 1.2.5 (2010-09-19) ------------------ - Stop distributing docs/_build. - Include library fallbacks in test_dlls.py for linux platform. 1.2.4 (2010-09-09) ------------------ - Raise AttributeError when there's no backend support for a method. - Raise OSError if libgeos_c.so (or variants) can't be found and loaded. - Add geos_c DLL loading support for linux platforms where find_library doesn't work. 1.2.3 (2010-08-17) ------------------ - Add mapping function. - Fix problem with GEOSisValidReason symbol for GEOS < 3.1. 1.2.2 (2010-07-23) ------------------ - Add representative_point method. 1.2.1 (2010-06-23) ------------------ - Fixed bounds of singular polygons. - Added shapely.validation.explain_validity function (#226). 1.2 (2010-05-27) ---------------- - Final release. 1.2rc2 (2010-05-26) ------------------- - Add examples and tests to MANIFEST.in. - Release candidate 2. 1.2rc1 (2010-05-25) ------------------- - Release candidate. 1.2b7 (2010-04-22) ------------------ - Memory leak associated with new empty geometry state fixed. 1.2b6 (2010-04-13) ------------------ - Broken GeometryCollection fixed. 1.2b5 (2010-04-09) ------------------ - Objects can be constructed from others of the same type, thereby making copies. Collections can be constructed from sequences of objects, also making copies. - Collections are now iterators over their component objects. - New code for manual figures, using the descartes package. 1.2b4 (2010-03-19) ------------------ - Adds support for the "sunos5" platform. 1.2b3 (2010-02-28) ------------------ - Only provide simplification implementations for GEOS C API >= 1.5. 1.2b2 (2010-02-19) ------------------ - Fix cascaded_union bug introduced in 1.2b1 (#212). 1.2b1 (2010-02-18) ------------------ - Update the README. Remove cruft from setup.py. Add some version 1.2 metadata regarding required Python version (>=2.5,<3) and external dependency (libgeos_c >= 3.1). 1.2a6 (2010-02-09) ------------------ - Add accessor for separate arrays of X and Y values (#210). TODO: fill gap here 1.2a1 (2010-01-20) ------------------ - Proper prototyping of WKB writer, and avoidance of errors on 64-bit systems (#191). - Prototype libgeos_c functions in a way that lets py2exe apps import shapely (#189). 1.2 Branched (2009-09-19) 1.0.12 (2009-04-09) ------------------- - Fix for references held by topology and predicate descriptors. 1.0.11 (2008-11-20) ------------------- - Work around bug in GEOS 2.2.3, GEOSCoordSeq_getOrdinate not exported properly (#178). 1.0.10 (2008-11-17) ------------------- - Fixed compatibility with GEOS 2.2.3 that was broken in 1.0.8 release (#176). 1.0.9 (2008-11-16) ------------------ - Find and load MacPorts libgeos. 1.0.8 (2008-11-01) ------------------ - Fill out GEOS function result and argument types to prevent faults on a 64-bit arch. 1.0.7 (2008-08-22) ------------------ - Polygon rings now have the same dimensions as parent (#168). - Eliminated reference cycles in polygons (#169). 1.0.6 (2008-07-10) ------------------ - Fixed adaptation of multi polygon data. - Raise exceptions earlier from binary predicates. - Beginning distributing new windows DLLs (#166). 1.0.5 (2008-05-20) ------------------ - Added access to GEOS polygonizer function. - Raise exception when insufficient coordinate tuples are passed to LinearRing constructor (#164). 1.0.4 (2008-05-01) ------------------ - Disentangle Python and topological equality (#163). - Add shape(), a factory that copies coordinates from a geo interface provider. To be used instead of asShape() unless you really need to store coordinates outside shapely for efficient use in other code. - Cache GEOS geometries in adapters (#163). 1.0.3 (2008-04-09) ------------------ - Do not release GIL when calling GEOS functions (#158). - Prevent faults when chaining multiple GEOS operators (#159). 1.0.2 (2008-02-26) ------------------ - Fix loss of dimensionality in polygon rings (#155). 1.0.1 (2008-02-08) ------------------ - Allow chaining expressions involving coordinate sequences and geometry parts (#151). - Protect against abnormal use of coordinate accessors (#152). - Coordinate sequences now implement the numpy array protocol (#153). 1.0 (2008-01-18) ---------------- - Final release. 1.0 RC2 (2008-01-16) -------------------- - Added temporary solution for #149. 1.0 RC1 (2008-01-14) -------------------- - First release candidate Shapely-1.3.0/CREDITS.txt000066400000000000000000000027241226057120100147570ustar00rootroot00000000000000Credits ======= Shapely is written by: * Sean Gillies * Aron Bierbaum * Kai Lautaportti * Oliver Tonnhofer Patches contributed by: * Allan Adair (https://github.com/allanadair) * Howard Butler * Gabi Davar (https://github.com/mindw) * Phil Elson (https://github.com/pelson) * Johan Euphrosine (https://github.com/proppy) * Bertrand Gervais (https://github.com/BertrandGervais) * Marc Jansen (https://github.com/marcjansen) * Kelsey Jordahl (https://github.com/kjordahl) * Fr |eaigue| d |eaigue| ric Junod * Thomas Kluyver (https://github.com/takluyver) * Eric Lemoine * Naveen Michaud-Agrawal (https://github.com/nmichaud) * psagers https://github.com/psagers * Jeethu Rao (https://github.com/jeethu) * Benjamin Root (https://github.com/WeatherGod) * Jason Sanford (https://github.com/JasonSanford) * Johannes Schönberger (https://github.com/ahojnnes) * Jonathan Tartley * Kristian Thy * Mike Toews (https://github.com/mwtoews) * Maarten Vermeyen (https://github.com/maarten-vermeyen) See also: https://github.com/Toblerity/Shapely/graphs/contributors. Additional help from: * Justin Bronn (GeoDjango) for ctypes inspiration * Martin Davis (JTS) * Jaakko Salli for the Windows distributions * Sandro Santilli, Mateusz Loskot, Paul Ramsey, et al (GEOS Project) Major portions of this work were supported by a grant (for Pleiades_) from the U.S. National Endowment for the Humanities (http://www.neh.gov). .. |eaigue| unicode:: U+00E9 :trim: .. _Pleiades: http://pleiades.stoa.org Shapely-1.3.0/DLLs_AMD64_VC9/000077500000000000000000000000001226057120100152265ustar00rootroot00000000000000Shapely-1.3.0/DLLs_AMD64_VC9/README.txt000066400000000000000000000000131226057120100167160ustar00rootroot00000000000000AMD64 DLLs Shapely-1.3.0/DLLs_x86_VC7/000077500000000000000000000000001226057120100150765ustar00rootroot00000000000000Shapely-1.3.0/DLLs_x86_VC7/README.txt000066400000000000000000000000111226057120100165640ustar00rootroot00000000000000x86 DLLs Shapely-1.3.0/DLLs_x86_VC9/000077500000000000000000000000001226057120100151005ustar00rootroot00000000000000Shapely-1.3.0/DLLs_x86_VC9/README.txt000066400000000000000000000000111226057120100165660ustar00rootroot00000000000000x86 DLLs Shapely-1.3.0/GEOS-C-API.txt000066400000000000000000000060071226057120100152040ustar00rootroot00000000000000Ctypes declarations for functions present in GEOS C API 1.4, but not present in 1.3, are listed below: lgeos.GEOS_getWKBOutputDims.restype = ctypes.c_int lgeos.GEOS_getWKBByteOrder.restype = ctypes.c_int lgeos.GEOS_setWKBByteOrder.restype = ctypes.c_int lgeos.GEOS_setWKBByteOrder.argtypes = [ctypes.c_int] lgeos.GEOSGeomFromHEX_buf.restype = ctypes.c_void_p lgeos.GEOSGeomFromHEX_buf.argtypes = [ctypes.c_void_p, ctypes.c_size_t] lgeos.GEOSSimplify.restype = ctypes.c_void_p lgeos.GEOSSimplify.argtypes = [ctypes.c_void_p, ctypes.c_double] lgeos.GEOSTopologyPreserveSimplify.restype = ctypes.c_void_p lgeos.GEOSTopologyPreserveSimplify.argtypes = [ctypes.c_void_p, ctypes.c_double] lgeos.GEOSEqualsExact.restype = ctypes.c_int lgeos.GEOSEqualsExact.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_double] lgeos.GEOSNormalize.restype = ctypes.c_int lgeos.GEOSNormalize.argtypes = [ctypes.c_void_p] lgeos.GEOSWKTReader_create.restype = ctypes.c_void_p lgeos.GEOSWKTReader_destroy.restype = None lgeos.GEOSWKTReader_destroy.argtypes = [ctypes.c_void_p] lgeos.GEOSWKTReader_read.restype = ctypes.c_void_p lgeos.GEOSWKTReader_read.argtypes = [ctypes.c_void_p, ctypes.c_char_p] lgeos.GEOSWKTWriter_create.restype = ctypes.c_void_p lgeos.GEOSWKTWriter_destroy.restype = None lgeos.GEOSWKTWriter_destroy.argtypes = [ctypes.c_void_p] lgeos.GEOSWKTWriter_write.restype = ctypes.c_char_p lgeos.GEOSWKTWriter_write.argtypes = [ctypes.c_void_p, ctypes.c_void_p] lgeos.GEOSWKBReader_create.restype = ctypes.c_void_p lgeos.GEOSWKBReader_destroy.restype = None lgeos.GEOSWKBReader_destroy.argtypes = [ctypes.c_void_p] lgeos.GEOSWKBReader_read.restype = ctypes.c_void_p lgeos.GEOSWKBReader_read.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t] lgeos.GEOSWKBReader_readHEX.restype = ctypes.c_void_p lgeos.GEOSWKBReader_readHEX.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t] lgeos.GEOSWKBWriter_create.restype = ctypes.c_void_p lgeos.GEOSWKBWriter_destroy.restype = None lgeos.GEOSWKBWriter_destroy.argtypes = [ctypes.c_void_p] lgeos.GEOSWKBWriter_getOutputDimension.restype = ctypes.c_int lgeos.GEOSWKBWriter_getOutputDimension.argtypes = [ctypes.c_void_p] lgeos.GEOSWKBWriter_setOutputDimension.restype = None lgeos.GEOSWKBWriter_setOutputDimension.argtypes = [ctypes.c_void_p, ctypes.c_int] lgeos.GEOSWKBWriter_getByteOrder.restype = ctypes.c_int lgeos.GEOSWKBWriter_getByteOrder.argtypes = [ctypes.c_void_p] lgeos.GEOSWKBWriter_setByteOrder.restype = None lgeos.GEOSWKBWriter_setByteOrder.argtypes = [ctypes.c_void_p, ctypes.c_int] lgeos.GEOSWKBWriter_getIncludeSRID.restype = ctypes.c_char lgeos.GEOSWKBWriter_getIncludeSRID.argtypes = [ctypes.c_void_p] lgeos.GEOSWKBWriter_setIncludeSRID.restype = None lgeos.GEOSWKBWriter_setIncludeSRID.argtypes = [ctypes.c_void_p, ctypes.c_char] Furthermore, the following unneeded declarations are removed to avoid problems with Debian's 2.2.3 package: lgeos.GEOSCoordSeq_getOrdinate.restype = ctypes.c_int lgeos.GEOSCoordSeq_getOrdinate.argtypes = [ctypes.c_void_p, ctypes.c_uint, ctypes.c_uint, ctypes.c_void_p] Shapely-1.3.0/LICENSE.txt000066400000000000000000000027571226057120100147520ustar00rootroot00000000000000 Copyright (c) 2007, Sean C. Gillies All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Sean C. Gillies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Shapely-1.3.0/MANIFEST.in000066400000000000000000000006041226057120100146520ustar00rootroot00000000000000exclude *.txt recursive-exclude manual * recursive-exclude debian * recursive-exclude docs * recursive-exclude DLLs_AMD64 * recursive-exclude DLLs_x86 * include CHANGES.txt CREDITS.txt LICENSE.txt README.rst VERSION.txt recursive-include shapely/tests *.py *.txt recursive-include shapely/examples *.py recursive-exclude shapely/speedups *.pyx include docs/manual.txt exclude MANIFEST.in Shapely-1.3.0/README.rst000066400000000000000000000112341226057120100146040ustar00rootroot00000000000000======= Shapely ======= Manipulation and analysis of geometric objects in the Cartesian plane. .. image:: http://farm3.staticflickr.com/2738/4511827859_b5822043b7_o_d.png :width: 800 :height: 400 Shapely is a BSD-licensed Python package for manipulation and analysis of planar geometric objects. It is based on the widely deployed GEOS_ (the engine of PostGIS_) and JTS_ (from which GEOS is ported) libraries. Shapely is not concerned with data formats or coordinate systems, but can be readily integrated with packages that are. For more details, see: * Shapely manual_ * Shapely `example apps`_ Requirements ============ Shapely 1.3 requires * Python >=2.6 (including Python 3.x) * libgeos_c >=3.1 (3.0 and below have not been tested, YMMV) Installation ============ Windows users should use the executable installer, which contains the required GEOS DLL. Other users should acquire libgeos_c by any means, make sure that it is on the system library path, and install from the Python package index:: $ pip install Shapely or from a source distribution with the setup script:: $ python setup.py install .. warning:: Windows users: do not under any circumstances use pip (or easy_install) to uninstall Shapely versions < 1.2.17. Due to the way Shapely used to install its GEOS DLL and a distribute or setuptools bug, your Python installation may be broken by an uninstall command. Shapely 1.2.17 will uninstall safely. Usage ===== Here is the canonical example of building an approximately circular patch by buffering a point:: >>> from shapely.geometry import Point >>> patch = Point(0.0, 0.0).buffer(10.0) >>> patch >>> patch.area 313.65484905459385 See the manual_ for comprehensive usage snippets and the dissolve.py and intersect.py `example apps`_. Integration =========== Shapely does not read or write data files, but it can serialize and deserialize using several well known formats and protocols. The shapely.wkb and shapely.wkt modules provide dumpers and loaders inspired by Python's pickle module.:: >>> from shapely.wkt import dumps, loads >>> dumps(loads('POINT (0 0)')) 'POINT (0.0000000000000000 0.0000000000000000)' All linear objects, such as the rings of a polygon (like ``patch`` above), provide the Numpy array interface.:: >>> from numpy import asarray >>> ag = asarray(patch.exterior) >>> ag array([[ 1.00000000e+01, 0.00000000e+00], [ 9.95184727e+00, -9.80171403e-01], [ 9.80785280e+00, -1.95090322e+00], ... [ 1.00000000e+01, 0.00000000e+00]]) That yields a Numpy array of [x, y] arrays. This is not always exactly what one wants for plotting shapes with Matplotlib (for example), so Shapely 1.2 adds a `xy` property for obtaining separate arrays of coordinate x and y values.:: >>> x, y = patch.exterior.xy >>> ax = asarray(x) >>> ax array([ 1.00000000e+01, 9.95184727e+00, 9.80785280e+00, ...]) Numpy arrays can also be adapted to Shapely linestrings:: >>> from shapely.geometry import asLineString >>> asLineString(ag).length 62.806623139095073 >>> asLineString(ag).wkt 'LINESTRING (10.0000000000000000 0.0000000000000000, ...)' Shapely can also integrate with other Python GIS packages using data modeled after GeoJSON. .. sourcecode:: pycon >>> import json >>> from shapely.geometry import mapping, shape >>> s = shape(json.loads('{"type": "Point", "coordinates": [0.0, 0.0]}')) >>> s >>> print(json.dumps(mapping(s))) {"type": "Point", "coordinates": [0.0, 0.0]} Development and Testing ======================= Dependecies for developing Shapely are listed in requirements-dev.txt. Cython and Numpy are not required for production installations, only for development. Use of a virtual environment is strongly recommended.:: $ virtualenv . $ source bin/activate (env)$ pip install -r requirements-dev.txt (env)$ python setup.py develop Shapely uses a Zope-stye suite of unittests and doctests, exercised via setup.py.:: (env)$ python setup.py test Nosetests won't run the tests properly; Zope doctest suites are not currently supported well by nose. Support ======= Please discuss Shapely with us at http://lists.gispython.org/mailman/listinfo/community. Bugs may be reported at https://github.com/Toblerity/Shapely. .. include:: ../CREDITS.txt .. _JTS: http://www.vividsolutions.com/jts/jtshome.htm .. _PostGIS: http://postgis.org .. _GEOS: http://trac.osgeo.org/geos/ .. _example apps: https://github.com/sgillies/shapely/tree/master/shapely/examples .. _manual: http://toblerity.github.com/shapely/manual.html .. _Pleiades: http://pleiades.stoa.org Shapely-1.3.0/docs/000077500000000000000000000000001226057120100140445ustar00rootroot00000000000000Shapely-1.3.0/docs/Makefile000066400000000000000000000063331226057120100155110ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* build/plot_directive/* html: apidocs $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: apidocs $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Shapely.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Shapely.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." apidocs: sphinx-apidoc -f -s txt -o . ../shapely @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." Shapely-1.3.0/docs/code/000077500000000000000000000000001226057120100147565ustar00rootroot00000000000000Shapely-1.3.0/docs/code/buffer.py000066400000000000000000000027321226057120100166050ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY def plot_line(ax, ob): x, y = ob.xy ax.plot(x, y, color=GRAY, linewidth=3, solid_capstyle='round', zorder=1) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1 ax = fig.add_subplot(121) plot_line(ax, line) dilated = line.buffer(0.5, cap_style=3) patch1 = PolygonPatch(dilated, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch1) ax.set_title('a) dilation, cap_style=3') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) patch2a = PolygonPatch(dilated, fc=GRAY, ec=GRAY, alpha=0.5, zorder=1) ax.add_patch(patch2a) eroded = dilated.buffer(-0.3) # GeoJSON-like data works as well polygon = eroded.__geo_interface__ # >>> geo['type'] # 'Polygon' # >>> geo['coordinates'][0][:2] # ((0.50502525316941682, 0.78786796564403572), (0.5247963548222736, 0.8096820147509064)) patch2b = PolygonPatch(polygon, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch2b) ax.set_title('b) erosion, join_style=1') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/cascaded_union.py000066400000000000000000000017511226057120100202730ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Point from shapely.ops import cascaded_union from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY polygons = [Point(i, 0).buffer(0.7) for i in range(5)] fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1 ax = fig.add_subplot(121) for ob in polygons: p = PolygonPatch(ob, fc=GRAY, ec=GRAY, alpha=0.5, zorder=1) ax.add_patch(p) ax.set_title('a) polygons') xrange = [-2, 6] yrange = [-2, 2] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) u = cascaded_union(polygons) patch2b = PolygonPatch(u, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch2b) ax.set_title('b) union') xrange = [-2, 6] yrange = [-2, 2] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/convex_hull.py000066400000000000000000000022471226057120100176630ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import MultiPoint from descartes.patch import PolygonPatch from figures import SIZE fig = pyplot.figure(1, figsize=SIZE, dpi=90) fig.set_frameon(True) # 1 ax = fig.add_subplot(121) points2 = MultiPoint([(0, 0), (2, 2)]) for p in points2: ax.plot(p.x, p.y, 'o', color='#999999') hull2 = points2.convex_hull x, y = hull2.xy ax.plot(x, y, color='#6699cc', linewidth=3, alpha=0.5, zorder=2) ax.set_title('a) N = 2') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) points1 = MultiPoint([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) for p in points1: ax.plot(p.x, p.y, 'o', color='#999999') hull1 = points1.convex_hull patch1 = PolygonPatch(hull1, facecolor='#6699cc', edgecolor='#6699cc', alpha=0.5, zorder=2) ax.add_patch(patch1) ax.set_title('b) N > 2') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/difference.py000066400000000000000000000024301226057120100174210ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Point from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY fig = pyplot.figure(1, figsize=SIZE, dpi=90) a = Point(1, 1).buffer(1.5) b = Point(2, 1).buffer(1.5) # 1 ax = fig.add_subplot(121) patch1 = PolygonPatch(a, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch1) patch2 = PolygonPatch(b, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch2) c = a.difference(b) patchc = PolygonPatch(c, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchc) ax.set_title('a.difference(b)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) patch1 = PolygonPatch(a, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch1) patch2 = PolygonPatch(b, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch2) c = b.difference(a) patchc = PolygonPatch(c, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchc) ax.set_title('b.difference(a)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/figures.py000066400000000000000000000001601226057120100167710ustar00rootroot00000000000000from math import sqrt GM = (sqrt(5)-1.0)/2.0 W = 8.0 H = W*GM SIZE = (W, H) BLUE = '#6699cc' GRAY = '#999999' Shapely-1.3.0/docs/code/geometrycollection.py000066400000000000000000000031461226057120100212430ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from figures import SIZE BLUE = '#6699cc' YELLOW = '#ffcc33' GREEN = '#339933' GRAY = '#999999' def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color=GRAY, zorder=1) fig = pyplot.figure(1, figsize=SIZE, dpi=90) #1, figsize=(10, 4), dpi=180) a = LineString([(0, 0), (1, 1), (1,2), (2,2)]) b = LineString([(0, 0), (1, 1), (2,1), (2,2)]) # 1: disconnected multilinestring ax = fig.add_subplot(121) plot_coords(ax, a) plot_coords(ax, b) x, y = a.xy ax.plot(x, y, color=YELLOW, alpha=0.5, linewidth=3, solid_capstyle='round', zorder=2) x, y = b.xy ax.plot(x, y, color=GREEN, alpha=0.5, linewidth=3, solid_capstyle='round', zorder=2) ax.set_title('a) lines') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2: invalid self-touching ring ax = fig.add_subplot(122) x, y = a.xy ax.plot(x, y, color=GRAY, alpha=0.7, linewidth=1, solid_capstyle='round', zorder=1) x, y = b.xy ax.plot(x, y, color=GRAY, alpha=0.7, linewidth=1, solid_capstyle='round', zorder=1) for ob in a.intersection(b): x, y = ob.xy if len(x) == 1: ax.plot(x, y, 'o', color=BLUE, zorder=2) else: ax.plot(x, y, color=BLUE, alpha=0.7, linewidth=3, solid_capstyle='round', zorder=2) ax.set_title('b) collection') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/intersection-sym-difference.py000066400000000000000000000027571226057120100227470ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Point from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY fig = pyplot.figure(1, figsize=SIZE, dpi=90) a = Point(1, 1).buffer(1.5) b = Point(2, 1).buffer(1.5) # 1 ax = fig.add_subplot(121) patch1 = PolygonPatch(a, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch1) patch2 = PolygonPatch(b, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch2) c = a.intersection(b) patchc = PolygonPatch(c, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchc) ax.set_title('a.intersection(b)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) patch1 = PolygonPatch(a, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch1) patch2 = PolygonPatch(b, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch2) c = a.symmetric_difference(b) if c.geom_type == 'Polygon': patchc = PolygonPatch(c, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchc) elif c.geom_type == 'MultiPolygon': for p in c: patchp = PolygonPatch(p, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchp) ax.set_title('a.symmetric_difference(b)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/linearring.py000066400000000000000000000023651226057120100174700ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry.polygon import LinearRing from figures import SIZE COLOR = { True: '#6699cc', False: '#ff3333' } def v_color(ob): return COLOR[ob.is_valid] def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color='#999999', zorder=1) def plot_line(ax, ob): x, y = ob.xy ax.plot(x, y, color=v_color(ob), alpha=0.7, linewidth=3, solid_capstyle='round', zorder=2) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1: valid ring ax = fig.add_subplot(121) ring = LinearRing([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 0.8), (0, 0)]) plot_coords(ax, ring) plot_line(ax, ring) ax.set_title('a) valid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2: invalid self-touching ring ax = fig.add_subplot(122) ring2 = LinearRing([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)]) plot_coords(ax, ring2) plot_line(ax, ring2) ax.set_title('b) invalid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/linestring.py000066400000000000000000000024631226057120100175130ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from figures import SIZE COLOR = { True: '#6699cc', False: '#ffcc33' } def v_color(ob): return COLOR[ob.is_simple] def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color='#999999', zorder=1) def plot_bounds(ax, ob): x, y = zip(*list((p.x, p.y) for p in ob.boundary)) ax.plot(x, y, 'o', color='#000000', zorder=1) def plot_line(ax, ob): x, y = ob.xy ax.plot(x, y, color=v_color(ob), alpha=0.7, linewidth=3, solid_capstyle='round', zorder=2) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1: simple line ax = fig.add_subplot(121) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) plot_coords(ax, line) plot_bounds(ax, line) plot_line(ax, line) ax.set_title('a) simple') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_ylim(*yrange) ax.set_yticks(list(range(*yrange)) + [yrange[-1]]) ax.set_aspect(1) #2: complex line ax = fig.add_subplot(122) line2 = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (-1, 1), (1, 0)]) plot_coords(ax, line2) plot_bounds(ax, line2) plot_line(ax, line2) ax.set_title('b) complex') xrange = [-2, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_ylim(*yrange) ax.set_yticks(list(range(*yrange)) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/multilinestring.py000066400000000000000000000030261226057120100205620ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import MultiLineString from figures import SIZE COLOR = { True: '#6699cc', False: '#ffcc33' } def v_color(ob): return COLOR[ob.is_simple] def plot_coords(ax, ob): for line in ob: x, y = line.xy ax.plot(x, y, 'o', color='#999999', zorder=1) def plot_bounds(ax, ob): x, y = zip(*list((p.x, p.y) for p in ob.boundary)) ax.plot(x, y, 'o', color='#000000', zorder=1) def plot_lines(ax, ob): for line in ob: x, y = line.xy ax.plot(x, y, color=v_color(ob), alpha=0.7, linewidth=3, solid_capstyle='round', zorder=2) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1: disconnected multilinestring ax = fig.add_subplot(121) mline1 = MultiLineString([((0, 0), (1, 1)), ((0, 2), (1, 1.5), (1.5, 1), (2, 0))]) plot_coords(ax, mline1) plot_bounds(ax, mline1) plot_lines(ax, mline1) ax.set_title('a) simple') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2: invalid self-touching ring ax = fig.add_subplot(122) mline2 = MultiLineString([((0, 0), (1, 1), (1.5, 1)), ((0, 2), (1, 1.5), (1.5, 1), (2, 0))]) plot_coords(ax, mline2) plot_bounds(ax, mline2) plot_lines(ax, mline2) ax.set_title('b) complex') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/multipolygon.py000066400000000000000000000031061226057120100200720ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import MultiPolygon from descartes.patch import PolygonPatch from figures import SIZE COLOR = { True: '#6699cc', False: '#ff3333' } def v_color(ob): return COLOR[ob.is_valid] def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color='#999999', zorder=1) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1: valid multi-polygon ax = fig.add_subplot(121) a = [(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)] b = [(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)] multi1 = MultiPolygon([[a, []], [b, []]]) for polygon in multi1: plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(multi1), edgecolor=v_color(multi1), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('a) valid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2: invalid self-touching ring ax = fig.add_subplot(122) c = [(0, 0), (0, 1.5), (1, 1.5), (1, 0), (0, 0)] d = [(1, 0.5), (1, 2), (2, 2), (2, 0.5), (1, 0.5)] multi2 = MultiPolygon([[c, []], [d, []]]) for polygon in multi2: plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(multi2), edgecolor=v_color(multi2), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('b) invalid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/parallel_offset.py000066400000000000000000000037511226057120100205000ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY def plot_coords(ax, x, y, color='#999999', zorder=1): ax.plot(x, y, 'o', color=color, zorder=zorder) def plot_line(ax, ob, color=GRAY): parts = hasattr(ob, 'geoms') and ob or [ob] for part in parts: x, y = part.xy ax.plot(x, y, color=color, linewidth=3, solid_capstyle='round', zorder=1) def set_limits(ax, x_range, y_range): ax.set_xlim(*x_range) ax.set_xticks(range(*x_range) + [x_range[-1]]) ax.set_ylim(*y_range) ax.set_yticks(range(*y_range) + [y_range[-1]]) ax.set_aspect(1) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) line_bounds = line.bounds ax_range = [int(line_bounds[0] - 1.0), int(line_bounds[2] + 1.0)] ay_range = [int(line_bounds[1] - 1.0), int(line_bounds[3] + 1.0)] fig = pyplot.figure(1, figsize=(SIZE[0], 2 * SIZE[1]), dpi=90) # 1 ax = fig.add_subplot(221) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=1) plot_line(ax, offset, color=BLUE) ax.set_title('a) left, round') set_limits(ax, ax_range, ay_range) #2 ax = fig.add_subplot(222) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2) plot_line(ax, offset, color=BLUE) ax.set_title('b) left, mitred') set_limits(ax, ax_range, ay_range) #3 ax = fig.add_subplot(223) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=3) plot_line(ax, offset, color=BLUE) ax.set_title('c) left, beveled') set_limits(ax, ax_range, ay_range) #4 ax = fig.add_subplot(224) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'right', join_style=1) plot_line(ax, offset, color=BLUE) ax.set_title('d) right, round') set_limits(ax, ax_range, ay_range) pyplot.show() Shapely-1.3.0/docs/code/parallel_offset_mitre.py000066400000000000000000000041001226057120100216650ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY def plot_coords(ax, x, y, color='#999999', zorder=1): ax.plot(x, y, 'o', color=color, zorder=zorder) def plot_line(ax, ob, color=GRAY): parts = hasattr(ob, 'geoms') and ob or [ob] for part in parts: x, y = part.xy ax.plot(x, y, color=color, linewidth=3, solid_capstyle='round', zorder=1) def set_limits(ax, x_range, y_range): ax.set_xlim(*x_range) ax.set_xticks(range(*x_range) + [x_range[-1]]) ax.set_ylim(*y_range) ax.set_yticks(range(*y_range) + [y_range[-1]]) ax.set_aspect(1) line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) line_bounds = line.bounds ax_range = [int(line_bounds[0] - 1.0), int(line_bounds[2] + 1.0)] ay_range = [int(line_bounds[1] - 1.0), int(line_bounds[3] + 1.0)] fig = pyplot.figure(1, figsize=(SIZE[0], 2 * SIZE[1]), dpi=90) # 1 ax = fig.add_subplot(221) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2, mitre_limit=0.1) plot_line(ax, offset, color=BLUE) ax.set_title('a) left, limit=0.1') set_limits(ax, ax_range, ay_range) #2 ax = fig.add_subplot(222) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'left', join_style=2, mitre_limit=10.0) plot_line(ax, offset, color=BLUE) ax.set_title('b) left, limit=10.0') set_limits(ax, ax_range, ay_range) #3 ax = fig.add_subplot(223) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'right', join_style=2, mitre_limit=0.1) plot_line(ax, offset, color=BLUE) ax.set_title('c) right, limit=0.1') set_limits(ax, ax_range, ay_range) #4 ax = fig.add_subplot(224) plot_line(ax, line) x, y = list(line.coords)[0] plot_coords(ax, x, y) offset = line.parallel_offset(0.5, 'right', join_style=2, mitre_limit=10.0) plot_line(ax, offset, color=BLUE) ax.set_title('d) right, limit=10.0') set_limits(ax, ax_range, ay_range) pyplot.show() Shapely-1.3.0/docs/code/polygon.py000066400000000000000000000031061226057120100170170ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Polygon from descartes.patch import PolygonPatch from figures import SIZE COLOR = { True: '#6699cc', False: '#ff3333' } def v_color(ob): return COLOR[ob.is_valid] def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color='#999999', zorder=1) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 1: valid polygon ax = fig.add_subplot(121) ext = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)] int = [(1, 0), (0.5, 0.5), (1, 1), (1.5, 0.5), (1, 0)][::-1] polygon = Polygon(ext, [int]) plot_coords(ax, polygon.interiors[0]) plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(polygon), edgecolor=v_color(polygon), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('a) valid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2: invalid self-touching ring ax = fig.add_subplot(122) ext = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)] int = [(1, 0), (0, 1), (0.5, 1.5), (1.5, 0.5), (1, 0)][::-1] polygon = Polygon(ext, [int]) plot_coords(ax, polygon.interiors[0]) plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(polygon), edgecolor=v_color(polygon), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('b) invalid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/polygon2.py000066400000000000000000000034061226057120100171040ustar00rootroot00000000000000from matplotlib import pyplot from matplotlib.patches import Circle from shapely.geometry import Polygon from descartes.patch import PolygonPatch from figures import SIZE COLOR = { True: '#6699cc', False: '#ff3333' } def v_color(ob): return COLOR[ob.is_valid] def plot_coords(ax, ob): x, y = ob.xy ax.plot(x, y, 'o', color='#999999', zorder=1) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # 3: invalid polygon, ring touch along a line ax = fig.add_subplot(121) ext = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)] int = [(0.5, 0), (1.5, 0), (1.5, 1), (0.5, 1), (0.5, 0)] polygon = Polygon(ext, [int]) plot_coords(ax, polygon.interiors[0]) plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(polygon), edgecolor=v_color(polygon), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('c) invalid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #4: invalid self-touching ring ax = fig.add_subplot(122) ext = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)] int_1 = [(0.5, 0.25), (1.5, 0.25), (1.5, 1.25), (0.5, 1.25), (0.5, 0.25)] int_2 = [(0.5, 1.25), (1, 1.25), (1, 1.75), (0.5, 1.75)] # int_2 = [ polygon = Polygon(ext, [int_1, int_2]) plot_coords(ax, polygon.interiors[0]) plot_coords(ax, polygon.interiors[1]) plot_coords(ax, polygon.exterior) patch = PolygonPatch(polygon, facecolor=v_color(polygon), edgecolor=v_color(polygon), alpha=0.5, zorder=2) ax.add_patch(patch) ax.set_title('d) invalid') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/rotate.py000066400000000000000000000025461226057120100166350ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import LineString from shapely import affinity from figures import SIZE, BLUE, GRAY def add_origin(ax, geom, origin): x, y = xy = affinity.interpret_origin(geom, origin, 2) ax.plot(x, y, 'o', color=GRAY, zorder=1) ax.annotate(str(xy), xy=xy, ha='center', textcoords='offset points', xytext=(0, 8)) def plot_line(ax, ob, color): x, y = ob.xy ax.plot(x, y, color=color, alpha=0.7, linewidth=3, solid_capstyle='round', zorder=2) fig = pyplot.figure(1, figsize=SIZE, dpi=90) line = LineString([(1, 3), (1, 1), (4, 1)]) xrange = [0, 5] yrange = [0, 4] # 1 ax = fig.add_subplot(121) plot_line(ax, line, GRAY) plot_line(ax, affinity.rotate(line, 90, 'center'), BLUE) add_origin(ax, line, 'center') ax.set_title(u"90\N{DEGREE SIGN}, default origin (center)") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) # 2 ax = fig.add_subplot(122) plot_line(ax, line, GRAY) plot_line(ax, affinity.rotate(line, 90, 'centroid'), BLUE) add_origin(ax, line, 'centroid') ax.set_title(u"90\N{DEGREE SIGN}, origin='centroid'") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/scale.py000066400000000000000000000032611226057120100164210ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Polygon from shapely import affinity from descartes.patch import PolygonPatch from figures import SIZE, BLUE, GRAY def add_origin(ax, geom, origin): x, y = xy = affinity.interpret_origin(geom, origin, 2) ax.plot(x, y, 'o', color=GRAY, zorder=1) ax.annotate(str(xy), xy=xy, ha='center', textcoords='offset points', xytext=(0, 8)) fig = pyplot.figure(1, figsize=SIZE, dpi=90) triangle = Polygon([(1, 1), (2, 3), (3, 1)]) xrange = [0, 5] yrange = [0, 4] # 1 ax = fig.add_subplot(121) patch = PolygonPatch(triangle, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) triangle_a = affinity.scale(triangle, xfact=1.5, yfact=-1) patch_a = PolygonPatch(triangle_a, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch) ax.add_patch(patch_a) add_origin(ax, triangle, 'center') ax.set_title("a) xfact=1.5, yfact=-1") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) # 2 ax = fig.add_subplot(122) patch = PolygonPatch(triangle, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) triangle_b = affinity.scale(triangle, xfact=2, origin=(1, 1)) patch_b = PolygonPatch(triangle_b, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch) ax.add_patch(patch_b) add_origin(ax, triangle, (1, 1)) ax.set_title("b) xfact=2, origin=(1, 1)") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/simplify.py000066400000000000000000000023051226057120100171640ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import MultiPoint, Point from descartes.patch import PolygonPatch from figures import SIZE, BLUE, GRAY fig = pyplot.figure(1, figsize=SIZE, dpi=90) #1, figsize=SIZE, dpi=90) p = Point(1, 1).buffer(1.5) # 1 ax = fig.add_subplot(121) q = p.simplify(0.2) patch1a = PolygonPatch(p, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) ax.add_patch(patch1a) patch1b = PolygonPatch(q, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch1b) ax.set_title('a) tolerance 0.2') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) #2 ax = fig.add_subplot(122) r = p.simplify(0.5) patch2a = PolygonPatch(p, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) ax.add_patch(patch2a) patch2b = PolygonPatch(r, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch2b) ax.set_title('b) tolerance 0.5') xrange = [-1, 3] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/skew.py000066400000000000000000000047211226057120100163050ustar00rootroot00000000000000from matplotlib import pyplot from shapely.wkt import loads as load_wkt from shapely import affinity from descartes.patch import PolygonPatch from figures import SIZE, BLUE, GRAY def add_origin(ax, geom, origin): x, y = xy = affinity.interpret_origin(geom, origin, 2) ax.plot(x, y, 'o', color=GRAY, zorder=1) ax.annotate(str(xy), xy=xy, ha='center', textcoords='offset points', xytext=(0, 8)) fig = pyplot.figure(1, figsize=SIZE, dpi=90) # Geometry from JTS TestBuilder with fixed precision model of 100.0 # Using CreateShape > FontGlyphSanSerif and A = triangle.wkt from scale.py R = load_wkt('''\ POLYGON((2.218 2.204, 2.273 2.18, 2.328 2.144, 2.435 2.042, 2.541 1.895, 2.647 1.702, 3 1, 2.626 1, 2.298 1.659, 2.235 1.777, 2.173 1.873, 2.112 1.948, 2.051 2.001, 1.986 2.038, 1.91 2.064, 1.823 2.08, 1.726 2.085, 1.347 2.085, 1.347 1, 1 1, 1 3.567, 1.784 3.567, 1.99 3.556, 2.168 3.521, 2.319 3.464, 2.441 3.383, 2.492 3.334, 2.536 3.279, 2.604 3.152, 2.644 3.002, 2.658 2.828, 2.651 2.712, 2.63 2.606, 2.594 2.51, 2.545 2.425, 2.482 2.352, 2.407 2.29, 2.319 2.241, 2.218 2.204), (1.347 3.282, 1.347 2.371, 1.784 2.371, 1.902 2.378, 2.004 2.4, 2.091 2.436, 2.163 2.487, 2.219 2.552, 2.259 2.63, 2.283 2.722, 2.291 2.828, 2.283 2.933, 2.259 3.025, 2.219 3.103, 2.163 3.167, 2.091 3.217, 2.004 3.253, 1.902 3.275, 1.784 3.282, 1.347 3.282))''') xrange = [0, 5] yrange = [0, 4] # 1 ax = fig.add_subplot(121) patch1a = PolygonPatch(R, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) skewR = affinity.skew(R, xs=20, origin=(1, 1)) patch1b = PolygonPatch(skewR, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch1a) ax.add_patch(patch1b) add_origin(ax, R, (1, 1)) ax.set_title("a) xs=20, origin(1, 1)") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) # 2 ax = fig.add_subplot(122) patch2a = PolygonPatch(R, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1) skewR = affinity.skew(R, ys=30) patch2b = PolygonPatch(skewR, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2) ax.add_patch(patch2a) ax.add_patch(patch2b) add_origin(ax, R, 'center') ax.set_title("b) ys=30") ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/code/union.py000066400000000000000000000026211226057120100164610ustar00rootroot00000000000000from matplotlib import pyplot from shapely.geometry import Point from descartes import PolygonPatch from figures import SIZE, BLUE, GRAY fig = pyplot.figure(1, figsize=SIZE, dpi=90) a = Point(1, 1).buffer(1.5) b = Point(2, 1).buffer(1.5) # 1 ax = fig.add_subplot(121) patch1 = PolygonPatch(a, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch1) patch2 = PolygonPatch(b, fc=GRAY, ec=GRAY, alpha=0.2, zorder=1) ax.add_patch(patch2) c = a.union(b) patchc = PolygonPatch(c, fc=BLUE, ec=BLUE, alpha=0.5, zorder=2) ax.add_patch(patchc) ax.set_title('a.union(b)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) def plot_line(ax, ob, color=GRAY): x, y = ob.xy ax.plot(x, y, color, linewidth=3, solid_capstyle='round', zorder=1) #2 ax = fig.add_subplot(122) plot_line(ax, a.exterior) plot_line(ax, b.exterior) u = a.exterior.union(b.exterior) if u.geom_type in ['LineString', 'LinearRing', 'Point']: plot_line(ax, u, color=BLUE) elif u.geom_type is 'MultiLineString': for p in u: plot_line(ax, p, color=BLUE) ax.set_title('a.boundary.union(b.boundary)') xrange = [-1, 4] yrange = [-1, 3] ax.set_xlim(*xrange) ax.set_xticks(range(*xrange) + [xrange[-1]]) ax.set_ylim(*yrange) ax.set_yticks(range(*yrange) + [yrange[-1]]) ax.set_aspect(1) pyplot.show() Shapely-1.3.0/docs/conf.py000066400000000000000000000154131226057120100153470ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Shapely documentation build configuration file, created by # sphinx-quickstart on Mon Apr 12 11:07:08 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append(os.path.abspath('sphinxext')) # Load latest source tree sys.path.insert(0, os.path.abspath('..')) import shapely # For pyplots in code/, load functions here first, so they are visible from shapely import geometry, affinity, wkt, wkb from shapely.ops import cascaded_union # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'matplotlib.sphinxext.only_directives', 'matplotlib.sphinxext.plot_directive', 'sphinx.ext.autodoc', 'sphinx.ext.pngmath', # <----- pick one, not both #'sphinx.ext.mathjax', # <--/ ] # Add any paths that contain templates here, relative to this directory. #templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.txt' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Shapely' copyright = '2011-2013, Sean Gillies, Aron Bierbaum, Kai Lautaportti ' \ 'and others' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = shapely.__version__ # The full version, including alpha/beta/rc tags. release = shapely.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme = 'haiku' html_theme = 'sphinxdoc' # html_theme = 'shapely' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "Shapely 1.2 and 1.3 documentation" # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". #html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Shapelydoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Shapely.tex', 'Shapely Documentation', 'Sean Gillies', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True Shapely-1.3.0/docs/design.txt000066400000000000000000000026031226057120100160570ustar00rootroot00000000000000============ Design Notes ============ Shapely provides classes that implement, more or less, the interfaces in the OGC's simple feature acess specification [1]_. The classes are defined in similarly named modules under ``shapely.geometry``: ``Point`` is in ``shapely.geometry.point``, ``MultiPolygon`` is in ``shapely.geometry.multipolygon``. These classes derive from ``shapely.geometry.base.BaseGeometry``. The simple features methods of ``BaseGeometry`` call functions registered in a class variable ``impl``. For example, ``BaseGeometry.area`` calls ``BaseGeometry.impl['area']``. The default registry is in the ``shapely.impl`` module. Its items are classes that operate on single geometric objects or pairs of geometric objects. Pluggability is a goal of this design, but we're not there yet. Some work needs to be done before anybody can use CGAL as a Shapely backend. In sum, Shapely's stack is 4 layers: * Python geometry classes in ``shapely.geometry`` * An implementation registry: an abstraction that permits alternate geometry engines, even a mix of geometry engines. The default is in ``shapely.impl``. * The GEOS implementations of methods for the registry in ``shapely.geos``. * libgeos: algorithms written in C++. .. [1] John R. Herring, Ed., “OpenGIS Implementation Specification for Geographic information - Simple feature access - Part 1: Common architecture,” Oct. 2006. Shapely-1.3.0/docs/images/000077500000000000000000000000001226057120100153115ustar00rootroot00000000000000Shapely-1.3.0/docs/images/4511827859_b5822043b7_o.png000066400000000000000000002116611226057120100207470ustar00rootroot00000000000000‰PNG  IHDR V%4sBIT|d pHYsaa¨?§i IDATxśěÝy|SUÚđß˝ŮÓ¦űľď”YZ@\@aE}qEDĆEd„Q|}UÜQ@‘e°€ZhY¤PşďkÚ&]Ň%MÎűÇťFB·¤MÓíů~>ýh’»ś{νĎ=ç<‡cŚ1B!„Bđ˝]B!„BČŕA!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇ„B!„b7€B!„Bě†B!„BÝPB!„B± @!„B!vC!„B!Än(!„B!„Ř  „B!„»ˇÄ çϟǔ)S©T Ś=üq«e“““1yňd¨T*¸şşâŢ{ďEvvv/”šBúŞG !„Pb­V‹ĽóÎ;8věľűî; >O<ńÖ¬YcZ.55·ß~;š››ńÍ7ßŕ_˙úŇŇŇ0~üx¨Őę^<Bé]TŹBác¬· ŃßÝvŰmČÉÉAnn.`îÜą8~ü8233áččČËËCdd$žţy¬[·®7‹K!}ŐŁ„2xP ¸şşšţżąąű÷ďÇ˝÷Ţkşh@PP&Nś={öôF !¤OŁz”B @ş€1†ććfh4|ňÉ'řńÇńâ‹/233ŃĐĐ€áÇ·Zď†n@FFšššě]dBéS¨%„ÁKÜŰ菞zę)|ôŃG‘H„µk×âé§źTTTÜÜÜZ­çććĆŞŞŞŕííÝęsµZŤC‡!$$ …˘Ź€2XŐ××#''S§N…‡‡GŻ•ęQBHŐWęŃţŚ.xőŐWń—żüZ­ß˙=^yĺÔŐŐáő×_ďÖv:„|Đ6…$„|öŮg?~ŻíźęQBH×ŰőhFH"000qâDđ<Ź7ß|O<ńÜÝÝ•••­Ö«¬¬Çqf}ťŻ @řA:´‡Jßsž{î9lܸ±·‹Ń%TöŢAe·ż+W®ŕÁ4Ő7˝…ęѶő×ß@eď-Tvűë+őhF ÄÇÇĂh4"//ńńńP(¸xńb«ĺ~˙ýwDFFB*•¶ąą\:t(âââz´Ě=ÁĹĹĄ_– ˛÷*{ďi©oú ŞGýůwEeďTöŢÓ×ęŃţ„ˇŰŔ‰' ‰±XŚ»ďľ»wďFmm­i™ĽĽ<$$$`Îś9˝XRB雨%„ÁZ@¬°dɸ¸¸`ܸqpssCEEvďŢŤ;v`ٲe¦n«WŻĆ1cp×]waůň娯ŻÇĘ•+áĺĺ…ĄK—öňQBHďˇz”Bµ€X!>>ÇŽĂĂ?ŚŰn» .D^^>űě3łI±† ‚cÇŽA"‘ŕľűîĂ#Ź<‚¨¨(ś8qÂtq%„ÁęQB!Ôb…E‹aѢE-‡#GŽôp‰ú–yóćővşŚĘŢ;¨ěŐŁëĎż+*{ď ˛“ţcڱŢ.$''#>>IIIýzP!¤ďčőĚ@?>BHďŁz¦ű¨ !„B!Än(!„BěäرcŕyŐŐŐ˝]»zőŐWńŘcŹYµÎرc±k×®*‘í,\¸łgĎn÷óíŰ··;oMo Á¦M›z»dŁ„Xl°^8mÎ!}ĎÂ… ÁóonnĆ /Ľ€ŘŘXČd2¸»»ăţűďGaaˇŮr•••?>śťťáęęŠÇ{ uuu¦Ď±páB >‰¤Ă'‹×Złf nľůf(•ĘvżŁĽĽ<Ě1đööƲeËčÂ6q‡éӧ٤¤yyyxýő×ńÎ;ď`őęŐ˝]´7lŘ0|ôŃGČČČŔ™3g0tčPLť:ĹĹĹfË:tááá Æ đÖ[oá˝÷ŢCVVÖ®]‹gžyű÷ďďp_[·nŨQŁnzoŐŞUřâ‹/°uëVddd`ăƍزe Ţ}÷]Ó2wÝuJJJpřđaŰĽŤ1Ć0‡Ó.[¶ ţţţí~®×ë1oŢŔ?ţńÄÄÄę‡~Z­€ĐŞąhŃ"hµZÓĂ ż˙ýď„ zٲe ‚T*Ehh(>ţřcł}ź={ŁGʆ\.G\\\«'Ç{÷îE\\ |}}ńňË/›0ŤFĽôŇKđőő…D"ŹŹ–,YbŐ±ß˙ý¸í¶Ű€lܸőőőHII1[îűďżÇĚ™3ź~ú)/^ŚYłfÁßßsćĚÁSO=…őë×w¸Żť;wbÖ¬Yfď]ĽxsćĚÁôéÓ„9sć`Ú´ifçA*•bÚ´iřúëŻ->®… âĉŘ´i“é{ÉËË?~cÇŽ…\.‡źź^yĺÓöÖ3Ťx衇hj©yóÍ7-.O{:ú~€çy|ňÉ'={6„ŻľúĘlß˙="##ˇP(0iŇ$l۶ÍÔŇŢŃďZ¶-Z'''x{{căĆŤ]:Žü˙ůĎđÎ;ď´»ĚkŻ˝†Ěť;·Ó@íË/żÄرcńŇK/!((ăĆŤĂŰożŤ÷ßßěAé3’’’–””Ôé˛?ü0›5k–Ů{3fĚ`#FŚ`Ś1¶~ýz6tčP&•J™››[°`Óh4Ś1ĆÇqf«WŻfŚ1ÖĐĐŔ^zé%Č$ a}ô‘ŮzGŹeńńńL&“±QŁF± .•ă»ďľcŁFŤbrąśůřř°eË–1˝^ĎcĚ`0°_|‘ůřř0±XĚĽ˝˝ŮâĹ‹­>W, €]ľ|™…„„°M›6YĽnGÇ_YYÉzč!ćęęĘ”J%›>}:KOOďt˝m۶±#F0ą\ÎT*»çž{XAAA«}jµÚvËŐŃwÖ˛öý÷ßłˇC‡2±XĚrssYCC[şt)ó÷÷g2™ŚŤ1‚8pŔ´^EE›3góööf‰„EDD°?üĐâóŐŽăŘŢ˝{;]îÜąsŚă8Ó9Ľ|ů2ă8Ž]ştɴ̱cÇĎ󬸸¸ŐúmýÎ;Órž®wŕŔ&“ÉXeeĄé˝íŰ·3gggÓďs0°¦žéʬ­GgĎžmöŢěŮłYll,cڱ÷ßźýňË/¬  €ýôÓO,66–=ôĐCŚ1ĆšššŘ¦M›łł3+--eĄĄĄ¬®®Ž1ĆŘÜąsYxx8;xđ +((`ÇŹgß~ű-c쏺ŕÖ[oeżţú+KKKc“&MbŁFŤ2•áŔĚÍÍŤ}ńĹ,??ź?~śEFF˛eË–1Ć۱csrrb`ěÜąslÇŽ¦őW­ZĹBBB,>gŤŤŤlÆ ĚÓÓ“UUU™Ţonnfžžžě×_eŚ1Ëţţ÷ż›­űúëŻ3©TĘš››ŰܶV«e<ĎłźţŮěý÷ßź…‡‡ł´´4ĆcçĎźg~~~ě‹/ľ0[î˝÷Ţc‹V«e7ß|3{â‰'Lß‹Á``WŻ^erąś-]ş”eggłC‡1oooöâ‹/v¸ž^ŻgkÖ¬a/^dąąąěóĎ?gNNNě“O>1íłłzęú:©łď—1ˇŽ d»wďfyyyléŇĄL.—ł˛˛2Ćc)))L"‘°+V°ÜÜ\¶wď^ŔxžgZ­¶Ăßgpp0óđđ`[·neůůůěÝwßeDZóçĎ›öŰm·±… vx®KJJX@@KJJbŮŮŮŚă¸V÷GŹeaaa¬¦¦¦ÝşůZK–,a“&M2{ďرcŚă8vüřń×µ§^ŹÚ }]8-»p 6qâD¶yófĆł:éčř[ŽçĚ™3ěĘ•+lćĚ™,88étş6׫­­5×ŃŁGYAAűő×_ŮřńăŮřńăMű´$éč;cL¸IĄR6iŇ$–śśĚ222N§c÷ß?›8q"KLLdůůůlÓ¦ML.—›.………lË–-ěĘ•+,;;›˝˙ţűL"‘°ŁGŹšm›ă8‹ĎˇĄČ‘#GĎóL­V3Ćűä“O‡‡‡Ů2ÍÍÍL&“±ďľű®Őú¶ @V¬XÁĆŚcö^^^^« ď@7Đ/śÝysěŘ1¦T*Ů’%KÚ\~Ďž=ĚŃŃŃôş­ßÚŐ«WÇqě—_~is-uÁµ7ä‡fDZęęjĆc·Ţz+۰aŮz_}őssscŚ +†  C›űزe ›ćččČxžgŢŢŢ,11Ńěó'N0oooÓëçźž˛ß˙ť1& ţţţŚçyVRRŇć>’““Çq,77·Őg/żü2ă8ŽI$Ćó<[·n]«evíÚĹD"Q»ÇÚ–Űożť=˙üófď-]ş” >Üě˝­[·2Ó¶ÖkËłĎ>ËîĽóNÓkkÎľ_Ć„:öŤ7Ţ0˝®ŻŻgb±}˙ý÷Ś1ỏŹ7ŰĆß˙ţwłëL{uaHH{ôŃGÍŢóóó3»Ž.X°€ýíok÷ŚF#›6m[łf cڵ€¨Őjdú­[€ěÝ»—‰Ĺb¶k×.f4Yii)›4iă8Ž}őŐW®kO˝µš°c×4e?~‡Â#Ź<fÝPüýýńć›o⡇H$899ă8xyy™–KKKĂ7ß|“'Oâć›o6­{˝·Ţz 7Ţx#aŕÔ©SQSS•J…µk×âµ×^3M.€7Ţx‹/ĆúőëQ\\ ___Lť:<ĎĂßß#GŽ4mŰÓÓ÷úőë!•JńôÓO[uľZ´wü—.]BBB’’’0jÔ(B—???ěŮł<đ@›ë0ť[@8g›7oF\\Ôj5<<<,*WGßY ˝^Ź>řQQQ€ĚĚL|űí·(..†§§'ŕ™gžÁŹ?ţíŰ·cÆ đóó3ëž±xńb9r»ví¤I“...ŽŽ¶¨ś–jhhŔňĺË1ţ|ÓĚŐ%%%đńń1[N$ÁĂĂ%%%6Ý˙őÚÚwËë’’Ś1˘G÷Oú¦ýű÷CĄRÁ`0 ©© łfÍÂ[o˝@č^˛nÝ:\ąr hnnFcc#ęęęŕŕŕĐćöÎź?™LfŞCŰ3lŘ0Ó˙·üŰŐh4P©THNNFRR’Y÷@Á`Ú÷Üąs±iÓ&DDD`ęÔ©!hY±b† ¨T*üđĂ(++3mgÖ¬Y¸|ů˛ĹeíLË CŁŃh3Ň{Ťáąţw2Çs-7áW®\AMM ľýö[¨T*ddd`ćĚ™¸ůć›ńăŹ?âÜąsřđĂÁłIâ‚¶n¦Z~źŚ1¬[·.\0ý]şt éééP*• AFFŢ{ď=Óx©qăĆAŻ×[UĄR‰°°0ÓŘ.wwwłĎ}űö™Ć´,˙ĺ—_B«Ő"== JĄ2] ®×x´"-Ţ|óM¬Zµ łfÍBTTîż˙~,]şk×®5[®şş"‘JĄŇŞc»Çq]ú÷ż}űv¬X±Ď>ű,Nś8 .ŕńÇ·8áK[:ű~[tôiëx¬ŃѶ-‘€Ó§OC&“A"‘¸ŃŁG›„&$$ŕťwŢD"D"ÁcŹ=­V ‰D‚íŰ··»í×^{ UUUČČČ@EE…)IXXGHú:jéÇ&Mš„>ř"‘^^^P(`şpľřâ‹Ř°a\\\pęÔ)<üđĂv»pŢu×]­–ąöÂyřđaś8qĎ>ű,Ţzë-ś>}‰¤Ó}˙üóĎ(++CPPé=Á€ĄK—bÓ¦M¦T‘ö¤ŐjqÇwŕľűîĂ믿äĺĺaňäÉźoKżłëĎ‘Ńh„T*Ĺ… ZmłĺÂżfÍ|üńÇŘĽy3† ™L†ĄK—öXö§–ÁŕYYYHHH€JĄ2}ćăăÓ*(3 (//oŐ:akľľľ8ţĽŮ{-zzߤďją ż^bb"Äb±éˇěŢ˝Űl‘HÔę¦mäČ‘hllÄéÓ§qÓM7u©LqqqHKKëđ†KˇPŕž{îÁ=÷Ü'žxŃŃŃ8ţĽUOÁŻg4MőűŐ«W‘źźŹ;ŐrJĄŇtŁĽsçNłV’ëEDD€ă8äććšŐŰÍÍ͉DfËň<ßęĆ>77aaaV=,‰D­tÄĆƶz¸uęÔ)(•J„††¶»Ţ©S§0~üxłV™ěěěV屦|–|żť‰‰‰Á‰'ĚŢ;sćŚŮë¶~궞yóf¬YłĆôş°°S§NĹÎť;M=$Nź>mv>żűî;¬_ż§Oź†źź_‡Ű‰D|ýő× ˘Ç @ú±Áxá\°`¦L™bzÍĂÔ©S±`ÁÓSK´uü±±±hllÄąsçL­ 555HIIÁsĎ=×îz)))¨©©ÁÚµkáíí 8wîśĹe,űÎÚ2jÔ(455ˇ˛˛ŁGŹns™S§NaöěŮ;w.áśeddµ¤ŘŠ^ŻÇÜąs‘‘‘„„¸ąą™}~ÓM7A­Văňĺˉ‰śúč#äććâţçYšî¸ăČĺrÓzééé8{ö,nşé&ÔŐŐaăĆŤ¸téR‡ÝuT*FމÄÄDŚ?ŢôţĚ™3ńĆo ((Čt x÷ÝwMőT‹ÄÄDL0Á˘óÖ"00‰‰‰(((€\.‡»»;žxâ Ľ˙ţűX¶lžzę)¤§§cĹŠXĽx±©ëZ[ëEFFbçÎť8|ř0"##ńůçźă—_~1--¬ąŃďěűµÄŁŹ>Š-[¶`ŐŞUX´h.^Ľ­[·šÍńŃÖďłĺAĺő®/˙‚ ĐŞEŞE`` Ůë–€4<<Ü\\ß­711<ϛշ{öěÁ+ŻĽ‚ÔÔTÓ{ď˝÷îĽóNHĄRěÝ»ëׯÇ×_M-Ö uÁ€®˝pćććbçÎť^8Őj5ęëëÍ.ś‡FAANž$%%áóĎ?Gss3JJJPRRbę2tčPL›6 Ź?ţ8~˙ýw$''ă駟ƼyóĚZ!._ľŚóçĎŁ˛˛Ť.\0k˝HLLDtt4ŠŠŠLďĺĺĺáüůóČËËÁ`0­ÓŇ…mĘ”)ŠŠÂ˘E‹––†'N`ĹŠřë_˙jQëx:šmĚ1Xłf Ţxă ÄÄÄ`űöíxë­·Ě–ź0a~řaĚ1^^^xűí·ź}öfÎś‰Gyˇˇˇfé{[öŰVYZL™2űöíĂľ}ű0bÄ 6 ëׯ7ýqrr–-[0jÔ(DGGăŕÁŘłgŹéHEEE‡­Á"‘ÉÉÉ1c‚1aÂdddŕ§ź~2Őצßma0°nÝ:DGGă–[nAEENť:eֲі|°ŐĽA|đ¦OźŽ‡zˇˇˇxňÉ'1ţ|Ó9€¦¦&:tČ,(ÉÉÉĎó­žţ_륗^Bcc#ÂÂÂŕííŤüü|DDDŕŕÁ8~ü8†Š… báÂ…X·n]‡ë=ýôÓ1cfĎžŤřřx”””`ńâĹfß—%űYóýZ"&&ß~ű-ľüňKDGGcăĆŤX±bcÉdÚ˙}vV>ČĎĎ·z\ž%ÂőË´tç»ÖŢ˝{1fĚÄĆĆbçÎťřî»ďZý­ŃŘŘ}űöµ;I"é%öďN:cMV…… ¶Ę‚u­µk×2S*ŮO?ýÔ”žŹ1!“ÔÂ… ™““S«4Ľ/Ľđóóócb±………™Ň &$$m1!Í*ĎófN:Änąĺ¦T*™Bˇ`cĆŚ1Ą}Ýłg;v,spp`R©”ĹÇÇłüŃ´î믿ÎBCC­8kmgÁę,…`{Ç_UUĹ,XŔ\\\Lç.##ŁÓő¶mŰĆüýý™\.g·Ür Ű·oăyŢ”¤­sw˝Îľłm۶1WW×Vëéőz¶jŐ*Ę$ óđđ`3gÎ4eŞ)//gÓ§Og2™Śy{{ł•+W¶Ę˘¶mŰ6Ćó|‡çůÚ4Ä<Ď›ţ˙‘GaŚý‘ĺÚĎZ^_›>±˛˛’=đŔLĄR1gggö裏𞵠iµŻkË×r>ŻýÝ=üđĂm®síľsssŮťwŢÉ”J%óôôd/˝ô’UŮu‚ž˝e ź=”——3‰DbJůÚ]jµš9;;›Ňq[ęŰoże111fď%$$0777łĺDđöŰoł   Ţ.FźĐĐĐŔ®^˝Ę8Ŕ>üđCöᇚ¦°ŞgşŹclOßŮÇ$''#>>IIIÔźß IDAT×±›BCC±zőj,X° ·‹BHź2Đë™~|öžžŽĂ‡[=ąaGVŻ^Ť‚‚‚V2vděرXľ|9ćĚ™czď•W^‡‡–.]jł˛őW}ôĆŚOOOś:u O>ů$ţú׿šM88%&&âÂ… `Ś™ Öź;w.\\\l˛ŞgşŹĆ€'55ÎÎÎ|BHDFFZŐĄŐÖvK„Éë];Nn°k3RQQ///üĺ/éŇyhÄb±Yb@H5o«ŕŘ dŔiĐH!„ T›6m¦M›z»}ΨQŁpöěYÓkŽă:ť_ŚŘ B'„B!ž={Ě^3Ćh‘>Z@!„BHż·{÷n¨ŐjÂLěgĎžEUUużę(!„B!ýÚőÁÇqÝš“ô,ę‚E!„Bú­¶‚Ň·QB!„Bú% >ú' @!„BHżCÁG˙E!„BéW(řčß(!„B!ýý „B!¤_ ŕc` „B!„ôy| €B!„>Ť‚Ź…&"$¤ ôÍF46!ć9Č$& @H·5č HÉŻFFI-J4 ¨k4€çĄŐőÍČ,­E"H$b€14ęő0Ä"#‚]0e„7B<ZmŰČ.ćjqěr9®VĂČđßmń02ăßđPÉpówÜă Gąí~Ö#ĂO—Ępŕ\ tŤÍptt€Ł“;\=e‰D`ڎ©© ęÚZěK*ĆŢłEéŽŮcýᬔج„BČ`CÁÇŔEé2M]~H.Áé´ č F(ä2HerĹr0ĆPQˇÇń†““$‰©ň`ڎˇˇZ­)Ej$eĄâĆH7üůć@(eÂϲ B‡'r‘[®ŁüˇR© —ËÁqchnnF]]4 ~H.ơó%5Ö·Çz‚ďfEĄ®ićG˛ŻÖÁÝĂa‘>Édí.o0 V«q6«çs4xdbF»t« „BČ`DÁÇŔF±c 'SŐŘyş <ĽĽáîîŢáÍůő8ŽBˇ€Bˇ€··7***”]€ôâZ<{g$rËëđďăąÉdŠŠ‚JĄjs‰...pqqŢßĹĹĹřúT>.Tăń?…ZÜ˝ëzEUőذ? z#Ź!ŃŃpphÝ:s=‘Hooá\äććŕe⡠Á¸5ÚŁKe „@x¸QSS¦¦&đ<ÓB" >> @UŚŚáëSů8–RřűűC,îŢĎă8xxx@ĄR!+3«v¦ÜÝÝž·,Y›D"APPśťťq9+ ›ĚŔłwFB*¶.Ů[µNŹŤ?¤Ă1˘†DA"±®+•X,FXX8ňóóńé‰\¨bj !„XĄľľiiiČÎÎFyy9cfźËĺr ** ţţţ}çM­Nś~˙ČÍjj©đń† ĆŤn¸č+ĺ%}ĄáµÂ‘#G0oŢ<„……A*•ÂŐŐÓ§OÇ/żüŇjŮäädLž<*• ®®®¸÷Ţ{‘ťťÝ Ą¶­oOŕXJ9‚‚‚ÜíŕăZ2™ ‘QCŕ TÂËË ÁÁÁ×rvvFDd$˛ËęđůĎąV­ËĂöc9¨×3„GDZ|´ŕ8pqqƶ„hŻ´~ýţjęő(Ő4 Ľş M†.íŹţ‚ęŃŽ577ăĚ™3řâ‹/pćĚ455! ‘‘‘:t(˘ŁŁâŔصkŠ‹‹{·ŕŔ‹/Ó§o˝$$@m-PQś?lŰ,ZĚšěÝ ¨ľ#ć(ř<¨Ä ü1ĘËËńŇK/!66Z­ďľű.&NśC‡aâĉ€ÔÔTÜ~űí‹‹Ă7ß|úúz¬\ąăÇŹÇůóçááŃ?»äśÍ¬ÄŃKe „§§gŹěC,#zčĐnoÇŃŃAÁř5=ŁB]12IJ‹ąZ¤T#<<Ri÷˛Yq‡ŕŕ\NIÁžÄB,Ľ=€Â79» głŞ^\‹úë‚W)†¨06 Ń~*ހɀ2ŘëŃŽhµZ:tŐŐŐđňň‚··w›yŕęę ???ÔÖÖ˘°°űöíèQŁ0zôhűÖÍÍŔGŰ·2¸şm=śbLHĘË7ŢľýVVěW^ŇgQđ1¸Pb…-[¶ŔËËËě˝)S¦ ""k×®5]8W®\ …Býű÷ĂŃŃŹČČHĽóÎ;X·nťÝËŢ]şĆf|q2®®®=|Řš››Ş*+ńíŻä žďĽ2űá\ T*G¸¸Ř¦Ë”X,†ŹŻ/~MĎÇ]ńľH-¬ÁwgŠPSŻ‡ŁŁ\Ü˝ŕ«P@,1˝^ťN‡sąZśşZ7îż9Q~­ÇŔŇ ćz´#•••Ř·o8ŽCtt4 E§ëp•J…!C† ¤¤çÎťN§Ă„ ěsóÖĐĽôđ므Ż/ŕí tÔjÍq€J%üŐÖ99Ŕ›7Ç÷lYëę€_~Îť˛˛€Ş*ˇ¬îî@D0f păŤ@[˝{c ڱ.ő č(ř|(±ÂőM@č64dČšĎ÷ďߏ… š.š„‰'bĎž=ýň™RŽz˝aý¦bŕ8ľ~~HMMĹĄ|-†w2ŁDÓ€Üň:„……Ů´îîîČĎĎÇ«_^ F±aľËĺí.ĎXjkkQTTw÷§aĘpoĚëoQEH_6ëŃöÔ××ăŔ‰DŚŚ´şk+Çqđőő…T*ĹŐ«Wáŕŕ€ŃŁG÷Pi˙Ë`^~HLnŕťś¬[ßŃŠ‚%K„îY¶/§Z üë_B—ŻĆF@©ZjÄBJx¨ŐŔ… Ŕçź Ç0o0ľ°\/Ş®®FFF QUU…††0%^ńőőEXX<==űÍ5ą=| N€t“V«ĹŮłg1yňd@ff&0ĽŤ§97ÜpŽ9‚¦¦¦nwď±'#c8qE 77÷~Un@誠TČq6łŞÓ$%_ žçŕěělÓ2D"¸8;CŁŐ"22N\¨[žlFE AYYŽ\,€ş¦ Ź˙)”‚2ŕ †z´#'Nś€^ŻGttt·ĆŐą»»Ł©© ÉÉÉ€ŹŹŹ KyťmŰ€S§€đpëŹb±°~z:°t)đŐW€-?;p@čâe0-îîBđq=Ƅ֜ňr`ëV`×.`Í >Ţve±V«Ĺożý†śśD"8::ÂŐŐՔƾąąőőő¸rĺ .^ĽOOOÜxăŤđóół]!jj€ÔT ¸¨Żľ?? :Zm‚ŹÁ‹nZ˛d ęëëńꫯ***OąŻçććĆŞŞŞŕíím×rvGAE=4uMňo}LýĘÉ©E•ť.—§ÖA©PöHwHh(!±Çqđöö†T*Ĺąě,ě<-Ćźo ˛yůéMˇmOAArssMň»ËÇÇZ­żüň ćĚ™Ó37tyyŔÇ ]®şűŔF$BB€+W„–Š%Kş_>Ć€-[€˙[:Ú“Ň‚ă„›ě  áňň€'ź^{ ¸çžî—Ǣ"3\ąr§Nť‚D"App0ÜÜÜÚ˝1ĆP]]Ťââběßż±±±7nśŐ×˝8xŘłGČ`Ö’uŤçŁQřŽşĘÍ™LťÚń9µ ݰbĹ |ńĹزe FŤełí>÷Üs­Ć Ě›7óćÍłŮ>¬‘UZ Žă,š Ł#ź_\ ?üíş…BŇR=ôČ;¤˛V‰…7Ö–ˇË…˙ruu…^„”|Ä8uÚšC|ůĺ—řňË/ÍŢÓh4˝Tš¶ –z´=çĎź‡ÍĆťq???¤§§Ł¨¨ţţţ6Ů®™O>n>}}mł=ąđňľřBčţÔÝsńńÇBđ ÖÉ„®`yyŔ›o ]±î¸Ł{ĺéc żýö›©E#  Óa'´Ö;99ˇĽĽ—/_†FŁÁÔ©S­oEűí7ˇĹ§¨H(‚„–©ôʤ±ńŹq;«V ‰^{M;Óý)řčőhDH­^˝kÖ¬ÁÚµk±xńbÓűîîî„…׫¬¬ÇqpuuípŰ7nD\\śm Ü ęš&ČeR‹Z:ş17°&¸î?áłv;-©tëš; @ôŁĹ­¶:kxzz˘Z«ĹWżä#6Đ"ęŠE:ŃÖ wrr2â{ˇkI[S=Ú–şş:!88ئ7`*• rąééé¶@jkC‡:pn-// ´Tx ˙ç?w};§N 7Ç~~Ö-8N¸ 7×_"#…VŇétČĎχZ­Fyy9ĘĘ„ “mŤ‘긨ĽĽĽ P(‘‘ŁGŹbĘ”)–ýžţď˙„€ŇÉ ‰i» Ď ď+€§' Ó……ŔâĹŔOŹ>jŐĽ.ý)řú~=Ú_QŇ«WŻ6ý-_ľÜěłđđp( \Ľx±Őzż˙ţ;"##ű]żĺ˝Áâ'řÝ/±Ő&ĺ±v;-xuVÉ)¤"TŐZ–—ŢVÇb ŽăŕçďŹ+W® )« c#úg—8B€ÁWʶĄ°°lÖúѢĺéxË ~›úí7!őnÝăşE"n‚ŹďzŇĐ ´Z8; vGKrőŞ0Žä˙ţĎ&“'–––"99ůůů„z©TŠŕŕŕnĄ–V©T Eff&.]ş„n¸ˇăŢ}Wwăç'ś/KŹO©Z‰Š‹…óR[ <÷śE«ö·ŕôś™Ď­˝ńĆX˝z5^{í5¬X±˘Őçb±wß}7vďŢŤÚÚZÓűyyyHHHŔś9sěY\›óXKĐN,±µŰ]¬l­ąąŕ ë8ňr–ˇ©±ÁEę2ĄR •Ł#RĘ`4˛ÎW ¤Śőh[ŞŞŞ “Él:ˇk ĄR ťNgĘžd3ż˙.< ď‰ĐÁ¸téŹńÖÚż_H`›™ÖE"áć<) HNîÖ¦ôz=Ž?Ž˝{÷B­V#((#FŚ@LL """l2ŻŤ‹‹ <==qćĚčtşŽ޵K>‚‚„®tÖž/ŽÎM` đŮgB–±NPđA®E- Vx÷Ýw±jŐ*L›6 3fĚŔŻżţjöů¸qăOöĆŚ»îş Ë—/7M ĺĺĺ…ĄK—öFŃ»ĹÍQІ¦&0Ćúe…ˇÓéŕę …¬îWćĺ€c)ĺĐëő]žÝĽ}|‘‘çŠqWĽ 3źbµm‹N§ë±ş¦Ą;©Z­F€-'ú+,ěąą2är!ë’V۵q ß|#¬×NŠó.qvžřďŢÝĺ¬X:ť€FŁAPP<<(±ÂţýűÁq<š}Ćq ˇűÎ!CpěŘ1Ľüň˸ďľű ‹ń§?ý ďĽóŽ©os讄Á`DCCE“cő%Ś1ÔTWcdPçůĹ:ç„>ć}9»Žłł3|}}±?ą#C\ŕn˙ĘşĽş—ň´Č)Żş¦ MÍFČ$<°`mS2“>‡+$$$XĽl\\Ž9ŇĄ±źpGHĹ<ŞŞŞú]RWW‡ú†Ś ďü  Ł\Śř0W\Ě/§§§ÝfśíJv0hŞ*±'±OOďɻڑZXŤ}IĹČ(ůof4Ą© "‘5 W×ă×ô 0Dű«pwĽ"|l›7žôoµm‹T*5\=±m¶ť˛Duµ‹TgZşúvĄ{WJŠđ_ĎS@ą˝¸Č͵*ŔaŚářń㨭­Ĺ!CÚť|ÖÖ\]]Q^^ŽŠŠŠÖ]»ĘĘ€#G„ ˇ›ŮMD"ˇ%ĺŕAŕ™g„ÔÇ‘Ím·ÁĄ¨R­1®®ŕ†mż»WcŁĐ…î“O€}ű€őëŘXŰ”‘ô9€NIĹ<Ć„»âL–>>>v»1ď.ĆŠŠ áă"ÇĐË&Ęş+ŢIY)())±ý…»]ɨĹó<Ľ}|q)'eÚx9÷ě…­ľÉ€/Nć!1ŁŽJ„††ÂŮŮąÍäŤůeĄxűű«¸!Č.HĹ<ÜĄńt@—eń"žłł3z¤{k}}=xžďvúôV|}»=˘]MMBzßö2ś•– ­••B°âě  BwžžčÖ2yaQ‘UHvv6rrrf·ŕ€é;W«Ő­ŁG…ŔÖ­îîB÷Ľ„ŕľű€”hî¸.ĹĹĐ99A1u*¸N2×A&#!Ř{üqŕí·…®YdŔˇ„XdęśN«@ii)|m•ű˝<Ďwű‚¬V«QSS‹G¦G€·p[>.rLĺ‹ÉĹppp°ů¬čméjF-WWWäçç!9[i#{nĆăŞÚ&l<uMBBBŕććÖáw#‰ŕîî777¨Őjd©ËÁUča4ŃĐŘŁ‘A)ăć(wÜ1Ü .ý?›!]áíí ŁŃşş:8ÚřÉ}MM ĽĽĽÚ}`¤Óé““’’h4466‚ă8(•J¸»»Ăßß­ČěÜ)d²őŕůÚZ!ĺíµ6**„Ó?ü Üŕ¶ĹŮY7ŇSZĘcEw6ĆΞ= ''§NSFŰĎóJĄmwż;{Vh%˛UëG ±XŘîŮłŔčŃÖ×’Ë…ßAv6đâ‹ÂĽ.ÆٶĽ¤×QB,âí"ÇĂ˝qřb1śśśl˙Tíżęęꑞg—nĺĆŻ®®FA~>& ő@l uAÄŚ8_ä”×!5+ ˇaa] Bôz=Ôj5Ľ˝˝{¬Ĺçy8::"­¨¦Çş†flř! Úz†!ŃC­zŠÇq<==áyÍ GĆt:ŞŞŞpě˛ÇŻ”cö?LćeqHČ@áéé ĄR‰ŠŠ › z˝ŐŐŐmŁűŠFŁÁŮłg‘••e 8är9”J%chllDff&RRR •JqĂ 7`řđá –żé&á şF#<©¶ŁQ@ĆŹ^77 “ ~ňÉ­aa‰D(Csł0~ şZ@zŞ‹pK×0™ĺăÚŠ‹‹ˇŃhŐ3eęĎó¦q@f22l;H˙ZrąĐňqë­]>Zđ<*”wŮ2!čí‰îu¤×PB,6s´ŇŠk‘™‘Ȩ(›ŹŃh4ČÍÉFłÁŠŠ ŤF[=‹xee%rss0Ä_…űo´ş"žĂ“w„ăĂ#YHÉČ€ŹŻŻU]Ď4 ˛łł`42Čĺr«ž~Y;D.W HSeńö­Áöc9¨ŞkFÔh›t!ŕ8ppp€ŻŻ/ ±ótŇŠkńؤPHÄýŁ{!¶Ŕóű9O(—…­E]Ň×7#cŘ{¶ÎNN6źĄůz... ŹŔĺŚtě=S97ÚpÎBú8©TŠ &ŕСC())éÖ»¦¦&¤§§çydggĂŃŃnnnP(‹ĹH$V?LÉdŚŚDnn. ‘HLź.dSrt´M—//aŕńäÉB¬ČČžë*d­ęj .ÎŞ.XŐŐŐ˝–.şeňN///ó‚ą¶şfuGC4˙ůĎÝ®nĽś››í¶ďé)¤Y>rřź˙±ÝvIŻ˘„XM!á‰;Âś­Áîß ‘šš …\G•Ętˇcڎ©I¸1Ż©©Fssë§ô„x:ŕΛ1.Ęr‰Ś1üt© » pđńń››[‡Ý°ĘĘĘLłľţ}n,T ŰfAńuUŕ±?…áĎ·4ăRžYeu(Żn„®I©”‡›‡ î® t‚źëƸ(wĽPŠüĽ¦NWQ! =A*&Ôë{f®bw€›ń\‡7ţí9|ˇIYU ërÎtĄR‰Č(¤Ą]Ŷc9X<%ĽÍčě˛:l?–M\śť•Je6 ł%sŚFŁÁĄ5Îf^ÁMQî¸˙ć@(¤Ö5«OŚőÄsĹP«Ő6ťCEŁŃ€1†/ÉÇá‹eđu‘#Ę×qa®đtęúEĽŮ`DQU\=,›Ľ±+3ą·ÇĹĹ"ŹsŮU>Şgç›!¤/ Ćý÷ߏ˗/#%%iiiŕyrąÜ„455ˇ©©GK¶ç IDAT ÇAĄRˇˇˇ=|´pssCQQęöíłBŃs7ś}Z LśŚkőŞ(++ëBµŻ¬¬ Z­S¦Liý°+-MiÜÓŰ >\]Űź@ŇZđĆF @ @HŻ+Ő4`ď[ş;a“Bˇ@pp.ff")« ŁĂÍ[RN¦ŞńůĎąP*•:t(”ʶ[58Ž\.‡ŹŹĽ˝˝ˇV«q&łé%µxîÎH«nđ•21nâ“iĄđđđ°Y+““üýý­!yÚz\),ĆîÄB rĆś±ţđwłţ†ä·ôJ4č ]™É˝=-s›¤×bú(›l’~G*•bäČ‘1bÔj5JJJP]]ŤĆĆFÓěćnnnprrÂŢ˝{áăăc·î’ÇÁĹĹŽ©©Bđ1çďéFkL@@˛˛˛ĐÔÔdłôĘié†7|řp„„„´^ ?_řowÇÖ´|ô´–ąXúĘŘ Ňm€^·/©±~~~6Ůž‹‹ śťť±'±qˇ®ŕyáy2UŤOOäÂĂĂAAAw/j™POĄR!33˙řţ*^™ 7GË/*wĹűâ·ŚJäĺĺ!,,Ě&]›¤R)|®ËKo0PUU…ĚŇĽ±ë2îŠóĹťqľVMň÷sŞÎÎN6ËÜŐ•ąMJ´”n‘ őőő(--Euu5šššLA†»»;<<<Ě&óĽÖ©S§Ŕó<Ľ˝˝íZ^GĄ đß –TúÇŤ»•ÂÂÂpęÔ)”——›őÁ€‚‚¨ŐjÄĆĆâĆol{Áššî§*î­ŕZ>ÜÝ­î Gú.ú&IŻŞ©×#)« ~ţ6ť1Ü×ש©©¸RXŤŘ@gd–Öâłźsáéé‰ŔŔŔ.rąQQCv5o“†y焎–ů+Tr1|]ĺđt’™íCĄŕáŰ‚ńG˛PTT??ż_!‰ŕáá777”””`R1ŠŞđč¤PřÎ÷WŰЌ첺¶ź u‘µ-$b±ŐŤ6NIHc4M3Ž·tŐáyŢ,U9ĐRďDaذaf­FŁééépww·{¶%ĎCd4ü›A‘HČ‚ŐR©111¸té<==mŢ ˘×ëQQQ˛˛20Ć0~üxDGG·]‹…VĆşÖjŐ›Á Ě;3z´ýöGzÜŻ=H_w1W #UÎ-ˇT*ˇËp.[!~*lKČC—ʉˇaáČĚHÇž3E -MĂ×pRJ06܇yÁC%4㏠uĹ˝7úc×o…0 °mĐu-žçáçç…Bäě,HOą:;öÜň:°iwkç6aڎľÉ€˝g 1*ÔîŠ^™Ě‹žRVV†ăÇŹŁŞŞ NNN JĄ‚D"1ýÖ[ćOŇh4¸|ů2.]ş„¸¸8Ś9<ĎŁ˘˘ŤŤŤ=>OO[ř–n¤˝ĺÉ®ŚF ťnş–‹‹CFFrrrŮ­z¬ˇˇ)))ptt„Ńh„N§ĎóŠŠB\\\çuvK+š^/´ěX·óŢ >šš„śńăí·OŇă(!˝*ł´˙ĎŢ›‡7v–w˙źŁ}µeY^ĺ}÷lN&ű$& C6†„ZÚ@/ -}iˇ´¤ďK_ mß«ĐÂŻ-…@K Ą˛„lfßC&É$łfďŰX¶ly‘dÉÖ~~<#ĎćńHö‘e;çs]ľ&‘äç<:’ĎyľĎ}ßßŰj1+ę"mĘjłÓă ńZ׾`”M›/JϋŖ­ŰÎZ(¤˙;Ź3??O ŕĺSĽpt‚·”r×n : »;Ę1´ü䵓„Cł¸«Ş±Űí9[`‘JŐńz÷ -6v´ş–|ýäl I"ŁÝ:%‹ĎĎÄáp077Çłďřxâ —ş+ĽĘMkĺ*vőUQÉÇŹçµ×^Ăb±ĐÖÖ†őEÜŤ»ÝŽÝn§˛˛Ż×Ëţýűńx<ěŢ˝›©S]Č/TÇ–K’ q˝ý©(͆%»xšŮř8Ľú*9"ҵB!±Ŕ//ÇĐÖĆ-ÍÍ<ŇÝÍŕŕ uuuËşÖ§R)z{{qŹ©ŻŻ§ĽĽśÚÚÚŚ¬šŃŘD$!’ońâ[­pÓM«{\•ś˘ •Ľ2b0fVT–í‚×l63ę" ČáPÔ!ć̛șQ Á€Á` °°·ŰÍÄÄ/ăŘHĎÜŇD±ÝČÎöęJ­üřŐazzz°Í8ŠŠ°ŮlŤF4a_¬TZEqq1Á`źż>BGťë.e±D ­&3űd%‹ĎĎÄl6ÓŘŘ,ËĆ˝^ţżÇ»ŮŮćâ7wTŁ×ĺ&j¤˘’kŽ=ĘŢ˝{łNŐjµ¸Ýn čďďçńÇ§ŞŞ ˝^źł(ęRDc1¦ťNJçćذ±IYéW›6-ţ|g'|ç;°wŻř›M¸3iµâw˝^Ř»W<νĺĺĽÖŢNoB!=:·ârźźţŕ6¶ăÚ»U€¨ä•ąhť.3aí‚W«Ő’LÉxýWżXR«ŐRQQĂá żŻ—Ż>ÖĹ_ÜŐJ±ÝHu±…űîjĺ„g–_wNrtŘËččŮ©\—^z©b‹‹ŞŞ*ŽťáĄc>nß~a{[NC2•B–ĺ‹.ޞM­Ę–´ŰNaa!“““ĽÖ}’Ń™|k¦,­UTňŤÇăaďŢ˝”––RUUµ¬ťp»ÝNss3ÝÝÝLMMeľű­0áp±ş:J Í< ś3;+Ň•vě8űńxľő-řď˙łjjÄ‚~± #Y†ŮY >7Ľř"ťťĽxóÍŘ››qą\Kn2% &&&÷zq%“ÜÖÖF‘Ç#:™WU-oq˙ţ÷Ăżý[f˝4Vůčí…dÚŰW”ÂF2 âôŁËGeM˘ •Ľ˘ŐJÄ2Ě#^N-A»ŢçËÄl6ÓŇÚFwW'˙ňT/˙gO;†SM7U°©Ş€dJf<aj6Ć·źęEŁÍĽ‰c&čőzŠŠśüşs’Ű.-żŕŘĹ6˛,ú äkqs.i2łŮL_o÷?ÓÇźÜÖśQQ˝ŠĘZ ŹóŇK/a·Ű—->ŇX,jkkéďď'Ť*8ËĚeżßOé{Ţôć›0=-šŰm4|>¨­…Í›O?Ăźţ)<(:¶—•-]Đ-IB(Ŕě,%ĂĂ|đˇ‡xü–[8RZJAAÁY‘ďd2I4%4;KÁ±clîîćVŹ]$rţŘUU"%iĎńß™p÷Ýđź˙)úŐÔ\řu+gŢĎűú ±qy"$‘€ţ~qżţőµŐ RE6ŕ¶…Ęz˘ČŞĎY·Řô¸f“1Łt¦ůôBš—Ňčőz›Dyě-ĎyĎk5•Ef6W`Đk(+»°HX.N§“éPŚ1˙"7łSÔ”E(RôŘJ`łŮhhl˘{l–'Śĺ{:**sěŘ1ćć樭˝¸D&ŃŘŘHmm­łËŽ`0H$ˇvçN¸ţz8ÝŁaĄ$b‘źo‚AiřÔ§N ŚD>˙yQëŃÔ$Rš˛ů,ív¤ÖVôZ-xćv¸Ý ĆĆĆčë룧§‡ţţ~äC‡¸ő¸őÉ'©÷zщămÚ[¶@[Ô×C$?ů‰ ó7bľĂá€?üC!®Ĺ_łŇšŹą9ąřęWĹ<{zDCÇl B!Ń8Q–áŰßă¨l8ÔJ^©rš91:™QĘO¶Ěť˛OÔfh™«š†4fł™˛ň ^8:z–;Ö™LŁD㩜4K»ůć¨,Z<í­Ŕ¬§ĆeÁ?3Cqq±âsX)v»ťňň ž<äĺę–âu|WQY R©GŹĄ¸¸XѨb>ÜŻR©ʇ˛˛2Ńčłź…ßüMYzG=łÁářq‘´ŇÔť•ŹĂđ0\věŢ}úńď|öďĹÜËŤ¨ëtĐĐ€ÔÓæďźM?ú˛Á@$!ŹcúńŹŃ=ú(’Ő --H‹ÇhµN§8g““đĢţ߀­[—žĂ‡? Żżo˝%„Í™uJśONŠąÝp\{-|íkđřă05ĄĄPX¸xĘž, ńéó‰¨Z[›1™FwTÖjD%Ż´WŹ'ç`×+4; &_™đ»˙®¸ŁÓą”––˘ŐjyńčĢĎOΊ”ŠL*ŮDm´Z-˝Ž©ŮĄÓ6v¶ąD űŻĘËËŃjµľ’ÁE®"!˘ Âjµ‰ÇEÚÍű·§#˝˝đ_˙Ëit:¨«ď÷G?B’$Ě&öűďG˙˙T^--™GŁ‹ú¶61÷ß˙}xűí‹˙ÎWż*ŽŃŮ)ű ŚřDÄxżýۢ&Ćl†/ľű]hh)UďĽ#˘"ĂĂŕńç°ľ>!>»şDmĘ˙ů?đĂŞâcŁ •ĽŇTnŁČfŔçó)>ví©fzzť˛ż+A«Őâ(r˛Żw欕4±„HeČ´ř<)gw“Öjµ Ǹ×´Sh502rrŃ9ćŤFC±«„}˝Ó}/**ůfll ­V{A»Ýő€,ËŚŤŤáóů¸öÚkĎîŰt÷Ýpď˝" 22’}oDB,@A‘ë˙«_‰…ěŃŁ"•'[ cdC:íÇh„űď?Ý7ŕ{ß“IÔ|(Ů,Ć˙áĹq˙ëżŕż5'••Ů7 4D4Ăl†Ď}††.üZY"%}nGF”łÚťźQ™sS/żľ˙}řůĎ…Hşä!ňR)1÷–řŤßBĺ—ż„~peŰUÖj –J^ŃH·t”ń“×NRZZŞčMş¨¨íŰ·“\ÎM,‡Ňëó1ŚRVx¶±á”Ĺl2™D—AęX¶…ůÉdráBŻÓđŰ×Uóí§ű L©›®‚166FŻ7Ħ*¬UTr„ßďÇl^żÍ4“É$ĂĂĂLOOsĹWĐŢŢ~ţ‹ţ×˙NPßü¦HŁIG –zĎ©”Ř-÷zĹ"ô›ß„+® UB [1ă÷‹u4*"2.—,QžźŻťšç_űš¨ďH33/ľ(ú(éöUV&ęgîż_Źňň•ók4˘V˘»ľřE!nÎ]Ä{<""qđ (ŚŻ«ŁQą>‡H±ú‡îa¨ çŮd‚}>ţńĺżO• *@TňÎÎö^>>ÉđĐ -­mŠőżá ”ÉB>[VŇ„/Ý8ll&ržI×…DŁQĹ]¨’É$±x§ÍŔäl”ąhR´őug-¶Ő:Ř˝­ŚgŽŚ Őjq­1—“É„^§ep"¬ •5M$Qôš¶Z$ ¦¦¦G–enĽńFššš±$ ›ÔK/é='NÚ‚‚ńŻÁ Čɤłł"âŤÂ{ß+śĄśNř«ż‚'ź¦˘"»H€,‹Y†źý ž~ô#±Č·ŮDM‰Ńxz‘X‡ĂâŘ÷Ý·řÎűŢ˝B,)Ý|Ď`ççç?s[nŹ3ŃjˇşZ¤V=ů$ÜqÇéçöďç9•u,Ę7”$!ÔŽǶŮDŞŐą¸Ýđž÷ŔťwŠČŤĘ»U€¨ä­Fâ“7×ówŹt2ĐßOCcc^škeĂ™ëŮŠ‘´ Eç=WZ`Ĩ× …(P˘‰Ó¤‹ňřňůáy‹QK»»€+›śl«)DŁ‘Řs•›ůX’W;‡źźÇívçôsÉć‘JłwŻŘý>—ňr‘şu×]¦DőSO‰]ü3SĽ2E’ÄXýýđg¨Ź~TD/^{M¤ty˝˘VÂhsرvî„ë®»p_ŚŁG…ʢy`äݧŮ:j-…Í&"?řÜ~»÷Đ!Ą2›Ĺ‚_§Ë]‡słY|~Á x§˘,h4BüDŁ"í졇D/•÷ĽG¸‹)!ŔTÖŞQYT™ůôűůÖS˝ôôtS_߀Á;GŞ•rfęÓrÝł«ŻĐh$¶Trbl†ŠŠ E/‹…ňňrt:&“iAĹăqćććčôúŮßßGiˇ‘߸¦š­5…üöÎ*ŠL<ô¦‡`ŔOEĄűěüoÉö÷ňňËÂR¶şzyâ#Maˇ¨?xę)‘Îu×]b~űí§_#Ë‹/ö 8|X¤'  ›Z­^yE,čsA:ŐKéń].Q8ßÝ ĹĹbo6 ¦ŃäN|¤9Uąčy¶ŮÄśdY¤ŕ˝ń†pRűĘWŕĆ•›ĘšG *k†vwöţVľóL'Ž٬Ľ‚’’’5źľmF"!"6Óâ~;Ű\ěďďavvVŃ(V«Ĺí^Ľ#ĽĂá ˛˛’p8̨ÇĂ·žęĺúö>|m57m-cKu!ý‹ăxÇFs&@˛=Ź© ęYTTňMQQ===¤R©5Ůőz˝x<\.wŢy§ňÖľÍétŞ ‹‰ş ‡ăěÂďĺ’Ţ}˙Ç ÚsݤÎ]‡Bb'ţg?˘CŻ‹őôëŇ©dąŔj=R»]§}űD:ÔüĽpĘZ ń™Es$I‡CÍßwüĺ_ Ѩň®`m] UŢőÔ—Zů«{6qmk1ʇ±ĹÂ÷ëś´-pĹzq´ąíÔ—ZńŚś$ĄTŻ ±Z­457SSSĂ«ť“Ü˙LÉ”L™ĂD›»ŃtńAČmSGŃŁh4J±míFÉTT*++IĄRĚž˛_KDŁQ´Z-řŔňŇWµ "2˘TÄ×íĹĎ=´ôë^~Y,x˙ă?DMF[›čŁŃÜ,R•ššÄcJŁŐDŁѦŕŮg…ÔëWG|d‹V+Ňî\.a}üúëůťŹĘŞˇ •5‡Ő¤ăŽíbÇĚ’ŻfT9$`3é(+\ĽČ\’$~{g Ńh”‘‘‘U·Â•$‰’’9v2ČŹ_E„áh"ă‚ţlíłe~~žD2E}éúµ6UywP\\Laa!“““ůžĘy ôz}~#3Ź=&R§L™mnd„^/vÖ{lńçeYXë~ţóBôlÚ$zšX­Ę‰ |ŁŐŠbt“IDÖ˘řH#I"ý® @DA.ÔĄ]eCˇ •5ÉФ(·w~.wďS©ţ™i®h,Z˛ľŁşŘÂG®­Ćçó1::š—~………ÔÔÔđZ×$fĐHRĆóČuSÇ™™Lz-ŤeĘwŚWQQI’čččŔď÷ç¤áęJÉkŻźPH4¦ËEôĄ¨H4ąóxÎî?€ýWQřÜĐ ˘ů —ç^’DŤ…ĂŃčÚi$IÔď„Ăđď٥㪬OÔ•5Éô)wŁL ŃWb‰»ŮCg{ě©©)bń7l)˝čkw¶—0KňĐ›âzˇúŤ\R\\LŔďçg{G¨+1㛋ŻúÎ%™L25éăşV'úsj@ÉťŁłtŹÎ2:!8/ęmě&E&Z+í´ąíčµęŢ‹ĘęŃŇŇÂŃŁG˘­­mÍÔ‚$‰üš}ôôEx.6šŇcvu‰”¬4Żż.zo\¬6%×$“ÂťŞˇAy‹ßôřÉ$ k_|¤ŃëEşŰCÁ§>µň®ó*kU€¨¬Iâ‰ZŤ&#¨ĺşP]lЎł=v$ˇ¤Ŕx^˙Ź ±»Łś_í[őZ4’$Qévsüřq(13??‡,Ëyµˇ»;N7 ‹Ä’<÷Î8Ďő1M`4č1™Ěčôâ<ű zƧyöČ8f–6—°»Łłam¨l 4 7Ţx#Ź<ň444¬ {ŢH$BQ>Łăăâß\ ťN¤!y˝§‹D„=oaa~Ĺ@:%ĎďW^€Č˛x݉ţ7ß\â#MI‰řĚ^xA-Hßŕ¨DeMbÔkH¦R-vłuOR’¬ť›R)ŚY87EâIb‰T^kaĚf3v;Óˇ8ńD’p8ŚÍ–źÔ'żßĎÄÄw_ĺĆyŞýÄHďż4H(’ ¸ŘE­ËµhçiY–‰D"LNNňôá ^91ÉÇvŐ±µ¦0oEĺ]†Óéä˝ď}/O?ý4˝˝˝Ô××ç¤Ij¦¤R)Bˇmmmy›Ѩř7!IăĆΨG{äđůDÍG>`<~Z|ĹrP/‰ŔÜţńq^ďú ˘ 6Ľů¦*@68k#¬˘rgvßHÄc±……s&„NĄé3l‚•«ú•‚ÂB<Óó8¬z|>źâăgB0dp źŽZ7o+ŕĺă>ţé‰Йشi3555X,–EE«$IÍfŞ««Ů´y3ZŁ…o=ŐËłGĆWű­¨ĽK©©©áÖ[o%‰püřq¦¦¦ňV133C*•˘ˇˇ!/Ç„ST!Ą‘e1núééEEĘĽ/g^GŽr睢ć”3˘bř|Ěř|ëO|¤1™D˝Ę†F Y …řÂľŔîÝ»)))AŁŃđ•Ż|eŃ×8p€›oľ»ÝNQQwß}7«<ăőIm‰¸i„Bˇ<ĎD9dYfn~ŽęâĹíwýť,Ź‘+÷)«ŐJ2%su““™éé…®ę«,Ëx˝^z{{hsŰůÄMőh$‰×»§řď_SZZJSS3Făâ®b‹a0hll˘¬¬Ś_Ľ1ÂËÇó#ŞŢ­Ľ›ŻŁUUUÜsĎ=¸Ýn9věŁŁŁ«šf™ţ›Ş®®V´×PÖ¤k3r±Ń‹‰Féc ÂČČĘ*Á©>P€č˘F)âqŢą“C»wv80ďÚµľÄq6<śďY¨äU€dÉää$ßűŢ÷ÇăěŮł`ŃÝÖÎÎNvíÚE"‘ŕÁäűß˙>ÝÝÝěÜąsMÚ1®5,FMĺ6f¦§ó=Ĺ…BÄă 6Wgžňc5Š…Ä™7­%ČÔ}*ŰHIşPµ±ÜF©ĂÄđĐŕŠL˛,ă÷ű/ř|2™djjŠ'ŽăńxŘ˝­Ś?z_ť†“Ss<đĘĹĹĹTUU-+ź^’$Ün7%%%üôµa&ÖžCŃFĺÝ~µŮlěŢ˝›={öPWWÇŘŘžĹÜšrÄŘŘ‘H„+ŻĽrŐŽą(MM˘ţ#=RŇc¶µÁŢ˝đW%ţ?OéŁ čő°}»řinu*J5Ű•eniaŇĺ˘çšk°ÔŐ!ĺÓd`ąD"ůžĘ* Ö€dI]]333€p4ú÷ ŘĹ}éK_Âl6óřăŹ/äË_vŮe477óőŻťŻ~ő««6çőĘőí.ľ˙â sss˘ĎçŁŘf ˇ,sÇ‹Q‡Í¤[h^¨ŮĎźą8üäŤő|ő±ÎÓ 155üxÁ€$I$ "‘sáÉ”ĚćŞ>pe=5.ńe™^Ćh4RSSł˘b^I’¨®®f.ćW†ř˶ŁŃäż8xŁŁ^G%%%Ľç=ďÁétňúëŻc6›qą\9=f*•Âëő˛eËŠ‹‹sz¬‹b0Ŕ5×ŔţýPV¦l]Fzsăw~G4:4›EáąR‹ý•~źpÉ%Š űpS“§,Ť?ůÉO"=÷ś8ůŽúd‹Ă!˘ *5˛.”»›H$xüńÇąűî»Ď*Ö­©©á†nŕ‘GY­)®k.otRZhbääp~˝ę  133Ă­—–ŁÉň&ŰZig6Tt>ŮöéHG`,FŐ. źşą` @oooĆŃ™4˛,3::ĘÔÔf×·»(ĐE‰ÎN3DźĄ±XËž+Ýü퇷đÇ·5/€w† ů¸«Ş±3•$‰Şęj<ÓóĽpDF%7¨×Q Á‡††ržŢL&‘e™ĘĘĘś'cîľ[ÔA( O7ł‹ÇE¤˝]ôýȱQůęv/Ë<ÜŘx¶ř$¸ăqÖŰb>=AT64j$ôőő‰DضmŰyĎmÝş•gź}–X,–_˙őu€V#ń»××đŤ_u3::šł>J÷9—d2ÉĐĐ 5. ×¶fż»yyCűűűó Šś ‰—:‹ŽZ|[˙ö\?'ŽŁ˘ŇMqqńEَPŹg„P(Ěű/«ŕöíYG0^91‰ŐjÁ® GĽÍfĂn·ńňq—5¬ł|é Ę»ĺ:ęőzyţůçŃh48ťNL9.Žťr]Z3Qĺk®Í›a`@¤G)á•qÍÍ"ĘkŇNV‘2˝+’Iq2ą6FŁ<ÜÖvZ||â§Ż©{ö¦~ŁŁĘ/č ! •Ť\ɲřü.˝Tą1UÖ$ŞÉg¦•ś‹ÓéD–efff(++[í©­;š+ě|đ*7˝éAŁŃP^^®¸ľŇ}DÎ;™¤ŻŻR >qSÓ˛Ň{:ęŮ ŚŤŤŃŘŘY^ś`0H±ÝHĺ´W»»€żşg?}„ýýCŚŤŽâ(*Âfła2™ĐjµČ˛L4%đű ĎÍQQdćŢßBsEö7ęX"Ĺń‘ •nĹżEENş‡‡™Ź%Őţ k€wĂu´··—_|«ŐʦM›˛2RX.sssH’”ßţg"Iđ˙/|ôŁ˘đ¸¶vĺ Ú˛2ĺSş–ÂfŽŃ{D şş„3VeĄHG2™Î~/©”Xü{˝ ;:řäţýH{÷Š&ŚUU°u+|¶«q÷ IDATüăđío‹q Wh9>?/Ň٢ŃÓŃžş:P2•/‚îĆ•SeM˘ 5Čg?űY§v3Ň|ä#á#ůHžf”_Ţ»­Śh<ĹăF‰ĚĎS]Sٍ~®úD"úIĢüńmÍ7<­F˘©ĚĘ[}3„Ăa¬ąčĽ©TŠ€†6ź˝qX |ęć<ÓóĽzÂÇ&&&Î{ťQ§ˇ˝Ş€-l­-Ě: -ÍÉ©9’)YŃčG»ÝŽ ú´»óč ¤ ?ůÉOřÉO~rÖcKţo$Öúutxx_|‘˘˘"ęęęV­1ˇß溺¬,ckďĄÇăx<|>Á`x<ŽV«Ĺfłárąp»Ý™EZššŕ/˙ľüeQŁQU•˝xe±p5óÓăCÉž.v»X쏎Šťî´I&Ĺsń8ţńqęĽ^nŚĹ¨vąt:9I&áčQŃQ\Ł5 ""´ÜűG$}}b;v"ú‡>í,¦Ä9—eŃeËhiYůx ńnľŽćU€ä€taßô"NÓÓÓÝ}ú§ú'¶oßžłů­7$Iâý—WRQdâW†9~ě(®’R\.×Ó/˘Ń(˛,ç<ťa1âń8LLŚă´ř»Z©,2Ó?bxrŽéPŚX"…QŻĹe7PWjĹí4_pQţäÁ1Ţꛡ°°0/ďÇçó‘H$ąľ˝ä‚Żq;Í|řÚ~sG5ą8“ł1ćcIôZ‰"›—ÝVâîÉ °ëĚt§8›ôşôăţȆ ‹-¸8Ŕe—]–§eÎFľŽ†B!^xá VU|D"‚Á —¬°đ9 rčĐ!zzzH&“ ŚF#ŤY–ăťwŢY0yŘľ};ĄĄĄKzÇb‘űµŻ‰öššĚ;¤Ç㢷Ŕ¶mÂij=ăvĂĚ |čCpíµ""21!V2 =tV“ÁęÖV¤Ĺ˘‰LO‹®ëɤ§®.ű˘ôŮYac\^.RşŇżßŢ÷Ţ+DCyůJßµg(źůL~EžĂzľŽ®eT’1›ÍI_ĎŕťwޡąąyÝç-çËť´TŘůźcüşÓËŘŘł “ٲI$Dć盏 Ńh¸ä’K˝ąË˛LooZ­«ŐşpÓM&“DŁQBˇY‚ÁYt‰÷n-cGk1Żžđ±·{šąhI’0ő§~'E$*r‡V×·»¸as ăé?ËgŹŚóč[ŁTTTPQ‘}˝ÄJ‰ĹbxÇƸ®ÍEIÁĹý’$á°pXsóýŽÄ…őo¦Ĺç٤ץĎíăűÇصů"‹%•śłQŻŁsss<÷ÜsȲĽŞâC–e<‹…ćććeŹqřđaŢ~űm´Z-eeea4Ď{ńxżßŹĎçăŃGĄµµ•;v,yąç¨®)YÇŹ‹Ô—ëü¤4‘LM‰ź4ë]|€ZŔkŻÁźţ)\u•x|d>ń‰Ě;śëtPZ %%B$ŚŽŠHß/Ň».¶ˇ‹ÁŘ—]&Äá™QĹM›DęÜŹ~$>®¤Ţ&Ź>řAq,• Ź*@r€N§ăýď??ü0˙÷żŕŕ’ąţóźĎó ×)YĆëŹ02K˘ŐHlŻ/â˝[ËčźÓ5:ËčL„PD™t¸ËlXŚž:ä%ś—†±Áŕ,6“ޱ€źdę´ŹA§ˇľÔĘ-›«¸˘±˝]SüÍCÇAŇP\ě˘ÚáŔjµžuŁNĄR YŹăąwĆůđŽj®j.¦{t–‡Ţˇ¬¬,/Ž5Éd’ţ>l&-{®ĘŤ@¶čµâÜɲśŃÂ-›ôş´ÓMë̲r˛ŻŁáp_ţň—D"M%˝SSSřý~nľůf´Ë°˘M$<˙üó QVVFEEĹ’ăčőzJJJpą\LNNŇÓÓĂÄÄ·ÝvŰŇi¤W]%R{~ücřÉO„1›EjUú|%"J2?/žŰ¶M¸P55eýľÖ,v»:„B˘Ćdr>ö1üÇŹgßá\’D„Âj…ţ~Ń8vL»]‡´p‹ÇĹyťťnbV+üůź q¸ŘçýG$)ľőÔ×/ŻÎdvVĚkëVX‡×*ËC ËŕÉ'ź$3{ŞëرcüâżŕöŰoÇl6ó•Ż|…+®¸‚;ř‹ż`~~ž/}éK”––®Ëçj3ä óŇqüĚÇ’‹ľ¦ŞŘÂŽ'şş Ó"EĂ]ŁłŚ{˝*˛Ë(Ë2ă^/őĄVY†ŮH‚x2…IŻĹjÔ"IŃx’{n€Ł'”––RYYyÁµFَ  €‚‚*++9y’ďż8H×hÎŃYl6[ÎÜż–"‘HĐß×K,áOîlĹj\—Š˘S‘•X,¦x:Zü”Ue›[ůú•óy·]G‰O>ů$Ńh”ÖÖÖU)8O¦µµ•†††¬?•JńÜsĎ122BcccV›:’$QRR‚ÍfŁ··—Çś»îşkéż_› ~˙÷Eő›oÂŰo‹úéiQ'PT ˘aÇxŕ‘‚•Ď®îJ“>?ŹVźűţcDzgb·CcŁ W_-;xđüNôz˝¨Ă¸ĺ¸őV!P.„N_˙:üď˙ Żľ*Š˙3í·’J‰Ëř8\~ąg˙.TňËÚXU¬3>ýéO344‹ë>Č>$I PSSCkk+/˝ô÷Ýw÷Üs:ťŽ›nş‰Żýëůoţ´†ń‡cüôµ“ôc2p8K¨˛Ű1›Í ®Jńx|ÁUéÁ7<üj˙÷\]ŵ­§m`“)‡UĎŔ„ź`0HáJÝ?Ý›Cá0źşˇI’$(´śîŹ'S|ë©>ú&Â455eu\˝^O}C6źŹ×ş†ho_~Łżĺ89<„VJńąŰĎîÁ‘oŞOÍ%+.@ÂaŃ ˝¦xíĽßŤĚ»í:şoß>ü~?mmm«&>dYĆçó122BMM ;wî\Ö8`xx8ëkÚ™Ífš››éęęâĹ_ä–[nąřµÍ`€ť;ĹĎRś8!Ék¨n`Ťđ‡Áżţ+ţçž[™řHcł‰ô«7ß„˙ú/QîőŠ´¬TJD0ÜîěŠęM&řĆ7„üîwEýŠÓ)~ÎMź“e‘:73#e2 źü$üŢď)[ČŻ˛ćQ?íe000Ńë¶oßÎłĎ>›ăŮlşGgůÎłý$R˘S˛Óé\ôĄŐj1™L‹Ĺđx<<đĘG‡üŢŤőř‚Qţíą~ĆýśN§"®Qáp“'‡ą¶ŐEkĺ…wČľw„ŢńMMÍËvj*))AŻ×‰DrâŐżXúR"‘ 059Él(DkĄťŹíŞĂi[[9ö6“Ž—żßŻřtff†r‡‰˘5öž7*ď¦ë¨ßďçčŃŁ¸ÝnĚfóŞ7 rňäIvíÚµ¬ĆťÓÓÓ?ü0»wďÎZ¸ďßżÁ@ą.G@aa!‡·Ţz‹ĆĆĆe‰˘óD”i`¸–ĐéŔ`Ŕ?:ެř‘()Eî^Ż2Vi**ŕľűŕłź…ÇE­Éب+1™Ä±6o†K.ąxĽĘ†F *yg<áţgú°Ůí44,ď†TTT„^ݧ»»›ÂÂę딹±ť˘¶¶żßĎĐô ß~şŹęb ÝYC]©®Č˛ĚCoŽ`łZqą˛ďvľZ¤EEŤSOYŹF»YŘ·VÚ/ńčťĺá7= úÂčuZ¬6;&»ë©´¸X,Ć;ž0oôLcÔiصą”[/-ĎICż­.?ŕ]ČGWŹÇŮ açVĂ**ËA4#íŁ¤¤DŃkR&h4ŞŞŞ())ˇżżźÇ{ŚŰn»-c1177ÇŔŔŐŐՊνĽĽśÎÎÎ…Ô°c±˘ŤD*…hÇزâ#MQ‘hüřę«ÂîWiŚF¸ňJńŁ˘˛ŞQÉ+)Yćű/ ˘ŐéW,l6۶mC«Ő*^7a2™(//§ĽĽśŮŮY<#'ůÚcť|čšjnÜRĘ oŽ!ßMMM«Zł‘Mź `ˇnâ¦-Ąl«˝x”%–HńÓ×NňZ×$6«•ĆĆĆ%‹úc±>źŹçŢ™ŕőž)>yS=-Ëčxľť†ď¨â{Ď099ąbÁ7==Íôô4÷ľ§V퀮˘8$‰śE53Áh4ŇŇŇB__O=ő{öěÉ(ťjhhI’íFż, &“‰ÁÁAeHuµč“±QDDÍÇčhnÄ›MďçB€¨¨\U€¨ä„Ŕ\śń@„ů¨°Î-´č)s0čÎúgô…iiiY–5乬†­ĄÝn§µ­ť‘‘~¶÷$sŃ$ŃD^GÁ*»°dÓçX8Çé~K1MđÍ'{žśŁ¦¦—ËuQqe0p»Ý”””088Ŕ?>ŢÍďÝPݏµíĺŤNNxfy­kťN·ěĹ] `hp+›ś\Ó˛ľŠšUÖ馉«Yű±Z­–ĆĆFNś8Á /ĽŔ]wÝuŃ źńńq,‹â×UI’°Ůlx˝^eÜĽYěä§Rë?k5ÄG˝NŐ‚w`@¤LE""EĘíÍ Őq…QżQ*Šá Fyů¸Źýý3L‡bç=ŻŃH4–ŮŘŃâäŠ&'z­†§ŹSP`_qÍÄj“îđ«ÓéřŐţQ@¤­¶cU6}.ŕtŻ ťvéy&S2ß~şŹ“Óš[Zł.ä7 47·088ČĽ8€Ů¨eKőĘťČÎä·®«!Mp¨ŻŹJ·›˛˛˛ŚĎż,ËLLLŕńڰąşß}OíŞv*ďććć0 kâűĄŐj©««Ł««‹žžZ[[—|} Č™c—Édbtt4ăž>KrÝuđ­oA R‹Ö+«)>@ŠŮYxůexôQáŚ;˙ŢŤŃ(ěŽ?đńďř.«¬T˘˛bÂŃŹěóđë“čtZ E4”`2Ą ťEŤŔÜÜă??|yGŢĺĆÍ% OÎ-Ë—~­P^^N$azz:ăÂůlÓ¦”$zĘďÝy‘N叽5Jßx–eŹ4’$QWWG2™ŕ?^ŕËÚ|žmńJĐj$>uSŹ˝=ĘS‡<řg¦)ݍ\2EL–e‚Á ޱQBá9nÚRĘÝWWˇŐ¨7T•ÜJĄÖ„řHcłŮp8ĽüňË SRRBMM͢iV±X,gQĺŮŮYR©Ńhtĺ–ÚMM˘+÷É“˘S÷:ßłÚâ„ŘÍ˙l6Qnłťv­JĄ„kU($ ľř"´·Ăżmmąť›Ę†G *+âääßzşŹP$űT±ăba}Á€ÍfŁ´´”H$‚ÇăáŃ·Dä`µÓ–”$ ńűýżŹlÓ¦”$ŁŃHT]ř†?63Ď3GĽTTT.tź^.B„Ôsüř1zs„ß»ˇ~Eăť‹F#±çJ7µ…üüőúúú0čőŘ 0›Í ˘0Ź3??Oh6H4§ĆeánlˇYáú•s1 $‰|Oă,Ün7:ťŽÉÉI†††Ř·o.—‹íŰ·S[{:¨Ńh˘¦Jc2™oÜ\”?üCřĚgN÷ XOäC|€H±2DŠŐbYZ­HÓ˛ŮDÁŮYQ¸~ď˝đ…/ŔÝwç~Ž*U€¨,›‰0˙řx7:‰¶ö–ŚCő&“‰ĆĆF¦§§‰FŁŠÔ~äťNÇĄ—^šńëłM›R’@ŔOS™ ŁţÂçü‰^ eeeŠS§ÓQ^^Áľž“ܱ˝‚ŇBĺ­ĘlÜwW+ľ9Ţî›ć„gďŘ4‰¤X.~x+9->6mZűâ#Ť$AeĄ(ř˙ëżçYE%KT˘’5GO9á RU]ł*¶· Ň–”Z(5Îj!˲"ůă>źŹ@0ČG®­F§˝đźý /ŚŃ Ď‰óŤÍfctfžDňâŔ**‰Í›7 _ČçŁŃHssłh.úÎ;X­V&î±155…,ËŠ5=‹ŇRřĎ˙„믖˛˝˝˘Iaľ…,‹®ă##04ÄĽůf^ůčG1ďŘ”Ç>1ËB’ ¦F˛ď{ůžŤĘ:D *Yóôa/6›5ŁFVë™ůôBĘVľ8yň$‡& -{ŚééiFNžĚ¨ůŕÔl !3ń‘íů1ŤČ2Ě„ă˙ŽŠĘF ÝŔsxx8gEÝJb0¨««cll ·ŰÍĚĚŚbâ)‘HŕőziiiY¶ĂŢE±Űák_ţg¨¨)YďĽ#\ťňEüÔu/‘ŔďőrŐĐôć›ěü˙©¦ÖQAFčtÂ9ëŃG!Ě÷lTÖŞQÉ 8FĎX—«dĂńć;]+Ťâóůčíéfrr2«Ĺ‹,ËŚŤŤ100ŔMNîąúâéńD*ăÚŹlĎOzÜXBŤ€¨Ľ»H\GŁQRů\gAAA‡ŃŃQśN'$“ÉŤ)Ë2CCCh4®¸â …fş×^ _˙şřď´µlľ0 © żĎ‡ĂëeŢnç†ýű‘îľöďSë—K«—^Ę÷LTÖŞQÉŠ®Qq‘\ĎÖą™’Ďt-qŁÄaŐóŤßíŕĘ&'CCCôöô0;;»¤‘eżßOgç FGGąíŇ >~Cš z]čušŚHŮžźô¸FťzŮQywáőzńz˝TUU­+׿ňňrBˇ[¶l!™LŇ××·l"Ë2'OžÄď÷łk×.,‹Âł˝_űš(FĎEşW6D"ř_}ől·«+®Ý " ë1 ’¶é}űí|ĎDeťˇş`©dĹčL“Ѱfě$7"é]ÂP(ÄçďhÁfŇń±]u\ÖPÄ/ޡ»»łÉÍ.z]¤ëpâń8sss ˝.ËlüĆî6ęJ3Osp٠Ćsł—n‚č°Şß•w‡Âl6+ďú”c, &“‰ÉÉInąĺž|ňIzzz¨ŻŻĎŞN,™L244ÄĚĚ ×]wuuuĘL0•‘x¬V0›O?ç÷Ă/~żţ5Ô׋tˇ|±”ŐnI‰(ćž™ÎRë“Iý«¨d*@T˛"8G·:~ŻgFGG™ššâ÷n¨;«QŢÖšB6WĐé™e˙ ]ŁANNúj+Ó˝..m-âňFç‚m6Ô•X‰ĆĽDŁQĹ ŃÓ;żoőÍpMËúZ©¨,—ůůy†‡‡©©©Ywi«’$aµZçşë®ăÎ;ďä™gžářń㔕•QZZş¤I*•bzzš±±1R©7ß|3 +›ÔČ<ńĽöš(0?µ±.č"Şđŕ"˘ŕr‰~ľČ¤ĎGş–"—ĚĚHE.6őz1ľŠJ¨D%+R)™Loˇůěř˝žI/Ô7Wź_䯑$6U°©J¤Ŕ%S2ó±$’f˝6Ł4«Ąh­´ŁÓJĚĚĚ,ô/PŠ˘˘"‚Á Ľ2DŤË‚Űiľř/©¨¬s<Žőćrt “É´P‹ćrą¸çž{Řż?ÇŽc||ś‚‚l6&“ ŤF¤pĆb1Âá0@€D"A}}=W_}5öĹşmgŠ×+ŠĘź{N,Řm6±h7„#S2 ‘8 ˘ĹĹP^ž›w¦äłÉŕ™ÄbĐß/„ŘJŕ…X'µM*kU€¨d…Ő¤#™ĚĚ %źżWBľ#7ĹĹĹx< úą®Íµäkµ ›Ią?c“AËĺ NMPZZŞh3BI’¨©©an.ĚŹ_ćĎďlYw;Â**Ů255…Ńh\·i«Ťć,+pÁŔ5×\CGG=== 2::zVíXş§Č–-[hiiYąřzî9řĘWÄ"·şZ‹Ą®M˛,DI>Y+â`rRü›«ŻD6¸+¦Šň¨D%+Ę MĚG&H&“ëŞ2ňąŃëőجVş<ł ąŕ¶KËŮ×;…×륲˛Rѱ5 nw˝˝˝tzfiŻÚřf*ďnBˇĂúŤ§R‹;ăY,:::ččč •J1??O<G«Őb±X”»?üô§ÂÉĘé}'2W§I$N xŽ,ĐŁQضmÉ—¤R)fgg™źź„-»Ýn_µ^b*kő“WÉŠć ˛,nŞ«ŮD–edYFŁŃL&‰FŁÍćŚvĐłŤh¬…ČŤÉlćät~š–•9LÜrI9OĂn·Ż,mb °MĽÚ9© • O2™\בľX,¶ĐŻ#‘Hŕńxđz˝˘Ń(’$a±Xp:ť¸Ýn •{żĎ<#ÄGY¸Ýů™°–ć,Ăđ°° ţŤß€źýLD‘”´#N$ ‚íŰĎ{*íśÖŰŰËŘŘŘyj’$QRRBcc#---9i€«˛vQJVT8L”ššś\UrŕŔóknnÎČ8_Ť3…O¶"HŻ× çĎ’ńŽË*é Ńß×Ë–­ŰŤvI’„ŁČÉŃa/É”Śv…u+**kÁłŢ˛,“JĄrŤ‡Ă8ťNŢxă Nś8A<Ç`0`2™Ž éďďgßľ}ŇŃŃAKKËĘR8˝^řëż‘ŹwŁř‡EÄbąék©”33đĺ/Ă%—ŔŹ,ţ_I7¶éi!tn¸aá!Y–éëëăŤ7Ţ`nn»ÝNyy9‹e!1‘H0??O0äŤ7Ţŕí·ßćŇK/e۶mЦţެ]T˘’’$qÓÖRţű×ĂĚĎĎc6ŻN!±Űí^(ćÜsĄ›Göy2öŁ_ŤĆbăLá“­’$)Ż“µ‰ëÚŠé{9”“yŘl6FGSxý‘U)F—e™™pś‰@„ůX­F˘Đ˘§˘ČŚAíK˘’Cěv;‘HY–Ź„LMM144„ÉdÂ`0PUUĄč59Ť277ÇÜÜccc¸\.Š‹‹1™Lç˝Y–™ťťĹçóńĘ+ŻpěŘ1nşé¦ĺ×üÓ?‰…mMÍ»O|x<Âb¸˘Büd{O;S}ůË ,ýxQ‘2QT |>¸é&(-„°xůĺ—éëëĂápPWWwÁď¤Ýn§´´”x<ÎŘŘűöícppÝ»wŻ^ź•Ľˇ •¬ą¶µçŢgxx––ÖUI/(//Çn·ÓÓÝŤ×A«‘ç*źu,&0Î>ŮŠ x<ŽŐß?Ďŕ|ťV›QŽn¶žt¨}j6šSâőGxů¸Źýý3ćÎ˙ľh$h(łqMK1W59Ń«bDEaĘĘĘH$D"Ĺ7l---9r„±±±•ŰÜžÁđđ0 Ľjkk—ĽH’DAA„B!†††xřá‡yßűއŰíÎöŔđüó˘ŕ|=Ôć"íĘnÄë)Nn·ču’)UUâÜ9"MęTí ˘+J¤Özš››—ő´Ůl´´´ĐÝÝÍO<Áž={Ô"ő ŚúÉŞ,‹†2żs}-?|y€ęęęUÉŰtą\LMMĎ1 ä$­!ß$“I¡0ĺMeyťGßxŁ)ł0x¶,ý™ťśšg&"ˇŐéAN‘đ…ůuç)Y¦Ňić}Űʸ˛É™U“‰0÷?ÝÇ\věر˛ůެYÖř_·ĘZfG«‹{ßSËôôÝ]]„Ăąwm’$‰ŇR±0ŹĹLMMĺüů@Ż×óZ×Ô˘iC«A2%Ó?VÜ+ŤFŁˇŁŁíŰ·ÓÚÖNSSMÍÍ´µo˘ă’Khll$ś4đ—ů»G;÷G2·×âżę&Ą5ĐŢľ)ă^&&“‰ĆĆFęęęxłgšűźî#‘Tk©(Ă%—\śnJ¸R"‘ăăălŢĽy!­KŁŃpóÍ7ĐŰŰ{VďŽlHĄR„B!Eć©Ńh¨ŻŻ'Źóć›oföKɤčpľÖÓorív‰śŽ`čtđľ÷Áwľ/˝?řÁéó“aš“"Äb00'O‡>_ü"HŇÂçët:)RŕÍf***8zô(~ż_‰«¬ET˘˛"v´ş¸ď®V Ť2ťťť>|éééśł¨¨ŠŠ €ś+hµZZZ[‰&ŕŰO÷‘L­~1úL(F2%gĽcůă#ź^¨ÉťN·hôJŁŃŕp8hjj˘µµ_(Éß>|‚#Á%Ç›śŤň­§z1Y,47·,«÷Bqq1ŤMMśđĚňÓ˝'łţ}•ŰX,\}őŐLNN®xÓ$™L200€Ífă˛Ë.;ë9»ÝÎm·ÝF"‘ ««+ë4Őh4ĘÁéęęRĚ|Â`0PQQAWW×BÍĘ’Âýi-[˛ćZ|Č2ĚÍ çŞs1›a|\ÔqÔÖŠ‚ň•26'N€ß/j:Î$‘Ź Ŕ±cⱯ~ľđ……°®®.b±˘}ŁJKK1 9rD±1UÖŞQY1.»‘Kę„%o"‘`hh(§Ç“$‰ĘĘJ:::¨ŻŻĎé±–b9‹îL1 Ô742<ć™ĂŢśc)ćb"ÄźiGRŽĺd6›ŤÖ¶vĚßzş—ž±ŮE_'Ë2?xqYŇŇĐи˘tŔ‚‚ŞŞ«yőÄ$G†ÔÝ7ehoo§ĄĄ…ˇˇˇeoś$ z{{‰ÇăěŢ˝{Ńîę%%%Üu×]X,:;;"Ť.9n,cdd„c§™öXĘ—Ë…N§Łłłóâ/Žťş–¬ŐÔÚŐčóó°k×ůĎEŁđ˙ RŻ\ 5Şťź‚§Ż†#G„Ř8rDü_źH‰űă?i`§"mizzz(((P´Ź‡FŁÁétŇ××—3k•ü˘Ö€¨,Y–y˝{Šźż>B,!ărąp:ťËr®ČÖE 2_çŠ\÷±Z­”””ň?˝ěl/ÁfZ˝÷›îÍ‘é.h.­ŽµZ- ŤŤôööđÝgűůŇ=›(´ś˝đ:4č§×˘ąąY‘ď…ËĺÂďźá篏°Ąş0«•Ĺ$‰ëŻżY–ééé!SYY™qŹŮŮY†††e™Űoż}I‡!‡ĂÁž={8zô(‡brr«ŐŠŐjĹd2ˇŃhHĄRDŁQÂá0ˇPťNGMM CCCTUU)ő¶ÓQÍ®şęŞĄ_ś®ČĐf}UY ń!ˢ¸{ófhm=˙ů'ž˝76mRî55Âq+‘©]é$ Üx#Ü{Ż8Ţ"˘0‹áóů¨=·ŕ]^ŻźĎGYY~k"U”G *Ë"™’ůŃ«CěíšÂétŇ\Uµčn\Ćăĺ©Y`"‘`dä$±h{AáÂM:“EÁjô)//grŇÇŢ®Ivwdá"łBŇ üµbu,rÉ8qâ8ľ>Â'n:;ňőôáqěv[FŤ)3ADŮÜtvvrd8Ŕ%uË/ĆUQIŁŃhصk.—‹}űö133CII ĹĹĹ‹¦ ʲL0Äçó(++ăĆǫ6K«ŐŇŃŃÁćÍ›dhh‰‰ |>ßÂĆ‚Řä(aűöí444ĐŰŰËđđ°b.Zgb·Ű Ť.˝Snł ‹ŘHfu_«Ćju8źśbŕ3ź9˝ŕŹĹ`ď^Qś˙Řc +Ó‚ţLĐéD4erRŽôu4^u'×]˙8lÝzÖŻÎśę5’‹ľéú¦ééiU€l@T˘’5)Yć?_ä­ľięęę(VŔ*Q‰ĹüĚĚ ###466^ôb(Ë2333ŚzFSIŞ‹-śśđ2šHQX`§©ąeĹóQ˝^OaA!űúfVU€XŤZěf=ápX‘˘B%ĐëőTVşy«o[/-_č29e`"¬x:žŐjĹj±đfĎ´*@TC’$¶nÝJ]]¤§§‡ŃŃQL&FŁ­V‹,ËÄăqćććHĄRqĂ 7ĐÔÔ”uj”N§&MM€¸ö%“I´ZíycÍÎÎb4sâhÁ`’’’Ą_ĽmĽóŽâsX6«%>ÂaŃ[ă€Ë/ŕ§?…ţP¤eY,˘ć#KăLq»ˇ˛ňü(G,&j@Ţ~^ynżţüĎ"Ué:ŁĺÔÜ]Śô÷°§§‡öövĹÇWÉ/ŞQÉšgŹłŻw:«FC«Aş·Ă‰'°Űl:X­VŚF#’$‘L&‰D"„B!ü3ÓD˘1¶Öň‘k«)¶I¦d|ý$ŻśZSöľ……  ‰%1V§)—$Il®˛sřdŮí^3碸¸ďŘ(Ż÷ń‘ëjču!JE?ÎÄ^P@çčäšú>¨l ěv;×_=W_}5###x˝^Ńh­VKqq1ĹĹĹTUUát:űţI’tÁ4ĹX,–qJX¶¤óřűűű— ±X„" +ߍWK|„BĐß/RťţěĎ„Ř}÷‰¦ŚĹĹâq…YžÇ…ú‰”–BI‰čýńôÓ˘6äţűˇ˘básÍĺőqbb"gc«äU€¨d…×áŃ·G)++[Sâ„;Ö¨ÇC*§Ęˇˇ{Ôł¨”ը㲺B®o/ˇ®ôt˝ŠV#qm«‹ŹůćdžŮÖ»Ífd`<ˇ¶dő¬)Żj.捞iBˇPÎěxłE’$ EśáĂ×V#IžéyĚ&cNj‚, ^o‚ŕ|⼺%0 444(ÚÁ|ąhµÚśü¦wł—SSđ'"Ý••ůď˛Zâ„U<ßü¦(˙ěgĹűooĎ˝đČIiZ6›Jźřüđ‡ ‘­D"ˇ¸x•eŤFĂ•W^©č¸*kU€¨dĹ/ßĹ ×+j·§’$á(*"âOnm"‘”ń"Ě„bÄ“2f–’#.»á‚»5UĹf*ťf|9 ŮÖ»¤Öáčęe¶»íT9ÍŚz<´´¶®™€Ýngbb‚™p§Í@p>.ĂúŁlĹ_:­ QĘĆÇjµ‹ĹrńK÷%ą ńűŢvbZZňßd5Ĺş‹ą9"Ě`€††üG€ÎĹd‚¦&čî†űîŁđß`~~^Q,ąT*•ł{±J~QmxsH(âłźý,n·łŮĚĄ—^ĘĎ~öł|OkŮćâ蟡¤´lUşž/»ÝN8’`:CŻÓP]la[­ËŠŘTU@IqÉ«$IÜ~i9``péľËĺw;ţ=+·Ż˙ź˝ós«<Óţ}Ô{Ť4˝wwllSCď¦'”4B’ŔH`“%›M!»Ů„„$N6 K a“Ď Őŕ†)Áuě齨Ś4iÔË9ߏ5ă2EŇi4ă󻮹 ˛ćč¨řč˝ßçąď'A¶—˙ ĂŕÖsËŕóűa·Ű3ö8©Ć'f“Ř=dRĺ8L’ŻNşqÁó1‹E€Xl×Ń\Ćd2M´ŞňŤßď‡L&›ÚŕŹ=Dó-jkO?ńń>#Ł·Xś›â#LF3H„fëV¨T*ŚŹO‘>Ç č‹“Ü\E.nşé&<ýôÓřá×_k×®Ĺí·ßŽM›6Í÷©ĄĹŢ1€AV[ŻR]ś&v`\ăéĎĄXSmD]‘ý}˝9‘•8Ť2űËú"-®ZUˇˇˇŚ }LU$*BˇcłJdâńäާTĹ_b×V-ĎŃ…ŔiŔb»Žć2………H$ĽOźć8ccc(--ťzč˙ “sEżéNÉťý$ńśřĽ++sW|$Đj“ Ě㏣¶´n·›÷ö=—Ë…˘˘˘¤â ,,„¬ ńÚkŻaűöíŘ´in˝őVŔ\€ľľ>|ë[ß­·ŢšłU„éč°ŽC­V§ÝkźÎ¬ŹTŰ•Żi8–ţ…a|é˘Jü×ćtuv˘–§Ůé b€ýü\„Ż[[ ·?‚==D"(((ŕµ=#Ő´Ä—śD,B4ĆâčĐ8¤˛ĚôHAHĹ"5ŮŹXś×Ń\F"‘ şş˝˝˝((ŕŻŇíóů Q_?Eş`0<ö­3$€ËN.ę9ŽĚîÍÔ˘"@§ĂŘÎťŮ'łPÜEE@s3–ŹŚŕP4 §Ó ‹ĹÂˡÇÇÇáóůpöŮgór<ÜC¸rg^xZ­źúÔ§N¸ýÎ;ďÄđđ0>řŕy:łô±Ž…ˇP$·Đ›Şr‘NűKŞ;։ũL2·Ź¶Q#Ă7®®Ź ˝­u"jp>đz˝¨´hćüśŇEÄ0¸ăÂJś×ʎˇ!ěŰ·Á`p^άéURĽ×îÂ/‚’~§%÷zQS¨†(Gü/§‹ń:šë¬\ąŃh”·ä!Žă044„ĽĽ<”••ťz‡×_§¨˘"^oJFG€Ź?ZZ(Ĺ©ąV­.ą8±ňqůĺ'Š–ĄůN牾‰h ŕBŠ›•Ë­ę={ĐĐЫՊH$ýî,Ëb``fł•••s?OśD¨€dććf455ť˛´üŘź#GŽ,8eďÇ ×$÷‘™Şr‘ŤÁ}áp`âaÇş,_…‡nhŔ˙níFkk Ěf 2’w>‘H^ŻW/›â‹; „˘qěnuâ˝öQ ş&EËĺ:eZr8F$A(Â¸× żß‡Úşú‰aR|á÷ű!1(4(đ—]˝Đ )чĂaŚŹŹăĚUĺĽ[ 9ău4×1ŤX¶lŽ9ťN7çsV«~ż—\rÉÔ•Ó­[©ňÁłůŽ÷”Ŕ}÷‘ÇbĺJj%đ†Ĺ‚óřCĄĄ`‘JŠÇ©J’ZmfÎw¶ů(ąF8€ő?ţ1ŃÝÝŤşşş´±8ŽCoo/"‘.¸ŕ‚ś ?ŕA€d—Ë51řéxţ —Ë•íSš3b†™ ;ŮSáóů ’K§ĺG$čř÷›±ý˙Ü; ‡ĂĆĆF¨łd’†B*ĆYősö ÇaOÇ(ž{H ˝••¨ŐjČd˛S„±X ÍÍÍ˙_š§„;Ăčč(JJJx=7ĎŘj 5đ…b ˘ş:3;§6› Jąëjs+nútb1^Gk×®…ŐjEgg'ęëëÓř###°Z­8óĚ3Q8ŐđĽx8x0ó o…X˝šLîCCÔŠuŢy˝yóf8ŐjŚ=ř nąöZ0á0ĐÖF÷ŹFi`i)Eß? ̤`ZH(€Ő E,†+®¸/˝ô:;;QSS“rë2˲čëëŰíĆĄ—^šsQ˙ü"äßř †'/ß~űí¸ýöŰç錽J w˛§ă8xĆÜXQ®ăµeF*áŞ3ŠŤsxuź5kŹÇ—Ë…OźW…4{†ÄhŚĹ_ŢęĂŢ®Qäĺ塺ľdÖç,‘HPQQľľ>ŕş3‹qdĐ‹÷:ś(**â­—< Â;>Ž›ÖT˘ÇဩSućH$ÓéÄÍëK ĎâkĎ7›6m:ŬͷÁ8WÉŐëčB@"‘ફ®ÂË/żŚ¶¶6TVV¦…ʲ,†‡‡a·Ű±téRśqĆSßŃn'/F6ć\0 MŹĹ€ŤeË€•+I|8ť€[ľ÷˝É÷łÎšú8äÇD˘Ňáó!ż°6lŔ–-[ĐŇŇ‚˛˛2čőú¤Ş~żýýý…B¸ä’Krb.N‚Óů:šI’!L&Ó”»s‰$!“iúíŤ7bőęŐ;·t)5)1Üť™hZ>đz˝†Â8·ˇ"#ÇođŔ`0@šä̉ą ŃŰŰĄĄ:śß”źńÇK‹łřÝÖ.´ ʧ<é>??FŁ˝˝˝xlkn\W‚x,›ÍĆËÜD/ąQ-ĂÚ#vv@"%ő~¤€EĆ6¦ZpďŰ·kÖ¬™§3JŤĹx]((•J\ýőŘąs':;;a4QXX8cKV"íĘjµ" aýúőX±bĹô PʇţĚÂ5u‚’Ş`üđ‡ŘüéOĂévîşë®äÚ}®˝–LóŃhvĎ;WItE«vX,Ü|óÍxűí·ŃŐŐµZŤüü|čőúS®Őńx^Ż.— Źyyy¸ňĘ+‘źź˝ďĽdXč×Ń\E bĹŠŘ´iX–=a÷÷đáĂ€eË–ÍשĄMc±oA(ĘąX<–e148š ę‹Rߏł\ăařĂq0t*) jéD%ĄÝ:Žľ‘ŞŞ2źGîőzŃÓÓŤBť w]ZťUôßß@ŰĐ8jjkˇK#‘F,O¤čĽřŃ0K´h˛AŻ×ĎąmÍétÂăńŕîËk ‹ŠĆ!‘$WťH5M-ŃżŽfwřŁŔ‰,Ćë(ݏÝÔR”h *,,Ţ&Ëĺr\yĺ•čččŔŢ˝{ŃŇŇ•J­V ĄR9ńď$‰ Ŕëő"Ť˘¸¸gź}öŚU%€ĚşgzĚü|ŚíŢŤĄv;ŢţüçńĺŻ~5yŻÁM7ü#Ř+2łŮµ F© r\µQŁŃફ®Âŕŕ <ľľ>4Ř5!Bb±Ř¤gÓdÂ…^ÚÚZ!Őî4B âĆoÄO<çź·ÜrËÄíO=őJJJ°~ýúy<»ôXV®‡B&ĆČČČÔi&óÇq@$ĆgÎŻNú‹$‰ăövąŃăđź2lN.ˇˇX‹őµyx§Ĺ µJ c’‘Śéě¸GŁQX­VŚŚŚ ˇX‹Ż]V Ą,{í?ÍĽÝâDyyyZâ#Ă0¨¨¨@{(»'ŚŇ<%ş»:çdHĂŔ@?>ŃdĆŞJú˘“ŠEIśKÔŻŔü±ŻŁs¦« xá`×.Ŕf;őďu:ŕÜsi§~íÚÉE~š0 úúzÔÖÖ˘ŻŻÝÝݰZ­' '‰D0 hjjBmmíävWťç@_ %‰„DRCPSC÷Ëfko(„±÷߇Áf,Ŕ—Żľ:5ŁłNÜ{/đóźÓ˘űtźŇí÷“;ÉďÁ0 ĘĘĘPVV†@ «Ő ·ŰŤ`0Žă —Ëa0PTT4§ď…‹ @2Ä•W^‰Ë.» wß}7Ľ^/jjj°iÓ&lÝşűŰßd˛L"ÂĹKÍxă ‹ebčß|Âq†‡‡át:ńąOT $oönśĺ°łŮWöYŽĆˇÓéPTLS–¦ąh4Š@ €n§‡úzIżo©î¸Űl6X­ĂŠ|ň¬R\˛Ě‘({ź–ăđÜűĐj5Ľ”żE"Ę+*ĐŇŇ7°pôčQTVVÎľ+zÇÁáp`hh++ ¸íÜIákÔČŤĆŹÇÓN\™ŽD”dž0˙c^YŚ×Ń´~ůK`Ű6Şvčt”ä$—Ó4Ë’źÂçŢz زX˛řÎwx‰v‰D¨ŞŞBUUÚÁŽD"`rąüÄťë€ßţ–ţ”H(…J.§?9p8€ţ~ŕź˙¤ű'ě gŚ“‡ ––‚ٶŤÚ˛jkéőLfţSźvď>ü07&·ĎGź·«®šńn*• 5 ±) p A€dÍ›7ă»ßý.ľ˙ýďcttMMMxć™gNŘÉ[h\±˛ď¶ąĐßׇں:^‰„­dŹ‹ĹĐßß·ŰŤ›×—ŕĽĆŮΞ@ŹoëF·Ý‡|łu……Ó¬őz=ŠŠŠ&úS“%Ő÷1÷( őrüëµ P+˛˙Ďňč ¶±x{O_:Ź>ß8Bˇ0z{{ŃŰŰ‹úúzhŹĹ_NÇqđů|‚ĎçÇĄË-¸i})Älj˛ň|ęE÷űýĽď ů|>E Š ąŐjx:˛ŻŁ)óÁŔC‘Ŕ¨¨ ôT eĄ’vä‹‹ifE_pÇŔ7ż đlľ—H$§¦…ĂŔŻ~<˙<ĹłVWÓůL·¨…h®F‚$¦z¬ÄÇEq:'ž c:ŤŔ† Ŕm·3´ŰŠDŔO Ü}7Ąe•—Óďžn¸ÝôžĎ"@¦B D­Vcăƍظqă|ź o(db|ůâ*üęŐvô÷÷ŁĽĽś—«×ëĹ@D"1 a0¦íŤFŁpą\pŘm3ŔW.­ĆšęŮ/ţn?©ă!ő I§'©TŞ9gáĎF4Ĺš&óĽř¨Ó •RÁ{Ľ°Á`H"ŠFŁhkkC8F{{; ¨¨h˘ňÄqÜDĺiÜëA0FIž_ŮPʆâSĹJ‘Q˝Jб±1Ţgl őĹZHçiřŁŔ$‹ń:š»v˙öo´Hol<ĄŐeJ†*$Z-yD~ń `lŚĚ™ÂçŁÚDz2ŠÖťí»Aˇ xŰLs˛řHL8OŚxśZ‰<ŕ™gčçÎ;/~qú×[Ąţ÷üŘą“HQQv˝Ň%áµác“‰e©pýzj§HA€¤LC±w\P‰§vő"ŹŁ˘˘"­h4 ŹÇQ—ă>?Jň”KDčîéD,‚ZŁ=eq řáóű!bśSoÂugC§š=‰$cń›×:á “řČTűX:ŢŹH$‚H4†âyL\j‡FkČhK‹T*ŲeˉD&LÄV«ő”űÔ2śQ®ĹşÚr4–h§='ĂŕÜŢ8ä@qqqĘ™óÓ0îóáÜuUĽO@ mZZ¨…J§ŞŞR_82 -đ%2N7ÜŔ˙yĆbŔGŹuuŮ©h$ËtâăxÄbzŤu:ŞŮlTy˙}ŞčLצTŹb±xbx],ŁÉë^/>ěĹ;­N¬«ÍĂ-g—B« dX xúi2›óµi"“ça×.Ú•ć+JýOd2 ąÂ\ĹGĄ’L˙|@ŃÇ7ßśÜď‰Dôz$^“x°Złăw9ʇÂŞŞ¨¦ŃĐ{öŔ@k+Ud,–™[˛8ŽŽcµR%íN 5…€źý xéĄÉxy'” IDAT*‡V;}Ő.FG)IěťwČătýőü>ośG ĽPiVŁŇ¬ĆgÎă0Â5A8‡T"‚I#CžF6/‘™Ń8‹ŹşGaĘ/ČÉG.— U5Kć/=Qy‰&™Ĺźj•g&D"JKËĐŢŢŽć/–—Ďž©‰±čqř1č Ŕ"Îr(6*q¨Ďööv”——#???íĎ[â÷¤R)¤R)t:JJJŕt:±żw­Căř—+kP™FĹF@ )öíŁZc#żÇÍËŁěo~“RµÎ‡EEŁQŚ{˝¸â¬ů-?+dbčTRÁyy|ŤFµJ‰w[ť3 áŃ ¶˛ăŁn7˘1"ąL †!–ŃĐßߏţţ~Ô›ć·đefłz˝=ÝÝřĹËíx`C=Ş,‚Č~HŢľÓ÷D"ę٦–  h÷9Ý*ˇ’9´CC4ű$1ěĎhśÝłŔ·řHPT47oĽ1űNýصϽü2 €äR)˝§™€ăč}HÝ˝^ŞX¨Ő$4oşéT¨RQjŮg? Ľň y6ÚÚHřŹĹBme69žxřÖ·Č|_[›ş˙G,&Ń"—SH‚ÁŔ{\´@î"E‰ÓĆ˙nëĆ +‹Ĺ’ńÝtp8‹¬ŻK~0_˛pçxĂî |AZśk”0ëä',ĘĂŃ8|Á(Xfś÷óH†a`0ćáČ q–;aÖ@Ź|0·ŽŚ@&“Âl)„^݇R©<áyÄb1ŚŹŹŁ··,;i&7™Lijb±z˝>mQ"“ÉP[W‡®ÎüfK'~đÉ&r@l ,2:;i':Uc­¨Ż\.VŘŃüîw©ŚĹ¨•'1doÇ,( …±ÇCâiş×$Sâ#q.:ÝĚ„eIxüîwT90hQ~|V¦číĄŠ@BŁ© ¸ë. łE«›Läç¸ă06U5¤R3µ´>ő°wozâăx éóô«_«Vń28S ÷Ŕ˘ch4_ľŇŽ'BCccŇł-ř0W'K0„ĂnÇ•« x5ź;ÇĂŘudvŽÂşĄJ§’b]Ť-µ ‰ăńmÝŕŔ@ożAZŤCC,†ÝA”™&ŢŰÁo^ë„ÝBIi)Ěfó´­t‰FŁFŁ@---¨ÍM"f‹“ŮeůňĺÓźL±XŚęšZ´´ĹÓo÷áëWÖž^ą2ŹĂ‘zëQ*0 źO‹ă®.jˇyâ‰Ô É˙řyřnK8—GĄöž‡˘ęÂT˘"“â#VKćéxüÔJL0HFőwߥ֢ââěµ[%¦‘Ż[GďcEEú•3©4yoÍFé`Ëô a©PRBĎă'?ţň—Ě 6ś@ ‹Š1żzµśHŠúÚş¤“ťţĚŐł‹ĹĐŰÓ ‹^Ž«Î(âĺ‘‹÷cgłb±cj‹©Jx ˘Ń(‚Á <ŢjĹöĂ V©°dÉ(RY|ĚBŞb.Ť<:™ Ţ@?©ľ0‡†Ć¦”ĚT*VŻ^ŤŚŚŚŕş5ĹxéŁačŤys $ JKËp¤»-CăXR:EÂŘđöŰŔä0›3˙*UÚŰi÷ů;ßIî÷"j™1™fßaO—Ä"?á=&'–O6Ä@mjá0EĐźđř¸÷^IµµÔ.–Mü~z?ľüĺěVţúW Eü|‡aču=z”ZűÖŻçç¸9‹ @ ÇáOoö"SżćęéFŁčęęŹâîË!ăaҶs<ŚßľŢ ‡'ŚÂ˘bX,–)CĘd2Čd2čőz”––Âáp ٬¬Św~Şb.ńřáKżĎrřßmÝSëÓ™ÝÂ0 ĘĘĘŔ0 68(>~á0G 4j5ßŢŤ».®Â˛$ ô§04Ds4^ťv×52çšřoÍśµš~˙řpíµŔ˛eł˙ÎîÝÔňłdIćÎ+áEP(€çžŁÝůĽĽď“-ńLV¤<žČO~Bţą¶!Ą‹ÓIbuŐŞě=f4Jľ‘d|9© ŐŇçńĎ֬ɮi_ ëä^,€@š|ÜíFŰđ8***SéŔq8.ů [ŹÇÖÖ0ńŘPŹBĂÜ+Îń0y± Ć&%5•^$ˇ°°IűüĘ'SjecY A¶ë]vŞŞ«ç482ő«V«`4x©~ěšÚZČ•üöŤN|Ô5Ę۱N8Ž>ůI`űvÚI^±‚†ŞŞ2WY ł™ďHîţďĽC÷Ďä\ĄpxrpßkŻQeářk[6ĹÇńßôöŰŔ«ŻRŰŇ|ŹPĽ<×^›Ý)ăGŽP»߯w˘˘ňńÇŔ/Éď±rA^ , 8ŽĂ«űlĐëtĐńŃŹšĂĂðŰí(((€Éd‚\.?Ĺ Ŕ˛,<ś##𮬣ˇX‹/^TÉ‹q9Ťă¶t"ˇľˇ!+˘+S„Ăa€I#ŰÁË[‘źź _ę Ă ˇ!3}ę‰555čííĹßě…Q-CMaM‚ČMâqŕÇ?¦ą  í¨óą“ś* OČűďS‹QAÁĚ÷?|8łâ Ö˘ş:ňĂŘl4ą;Á|ŹDLy¬ŹSŰš^je&[DT™ŮżźLđŮ!­­ôX™wŃëi^ĘłĎR|đyçń˙9 @® †ÝAÔÖf'Ň–eY8Gŕ8ŁNl6ä2)ä Äb X–E,A Çq¨0«đ鳪±ŞŇŔ›aůĹ˝Ăń†ŃĐŘ´ Ĺř|>HĹ"52üüĄ6°óÚ.•I“8Ă0¨¬¬D{{OěěÁŹnYĘKkťŔ"ćż ÖĘĘěµZ͆Áô÷ď˝ÜxăĚ÷µZI°d –ĄŮ7ß twÓm‰Ĺî|U>]‰¶{öĐ@dž†ů3LËdôÚżź%ÖÔQľŻŹ^?±>_µµŔÚµü B …€7ßĚ\J@9Ż—†žu–ĐŠµHŢUEÁ‘$bQÖŞN§ń8‹ÝşFµ ­C^tŮýpxB„cÔj”ćĺcI©<´[Ď7ŚťG(..IÉśť«xĆÜh*Ńâ™ÝpŽGćUTĄ“†Ć0 ***ŃŇrŰŮqÍjžŚ™‹Ź×_§ÝÝňňÜ-ňÔjň3Ě$@8ގ™Ümw:Ép~Í54” ťţů-č׬™|Ţ۶Ńë•ÍVą©Đé¨ó“źĐ˙K$$”D"zŻâqO,] Üy'pÁ鉇÷Ţţëżh> _ćó©HŇ[Z€ť;Ë/ĎÜc Ě‚Xô;PŞÔY‰CŤD"°㜆|čĹYpŚÄ1ęŹbĚE4ÎB9ƨ/8†••”ć)y;ż7›%°$vă0ăăăđů0W[°ă°•••Ľ&rĄJşih …&S>¶¶ăň•Š…*ŔIŚŹÓ®®ŃŮ BşH$dŠź †ˇąÇ|[Ľ‹QËŐWĐŽýÇÓíˇĆvěń Ń{wĹ“·}ř!‰Ź\‹-)ˇj^?ő9Ĺădžţő_IH=ü0ÍßHŽŁČÝǧÇX˛$µČćtP©Č”ţę«‚Y¤D`QŕňE!“%wAśËĽŹx<Žžî.h"\·¶[ÚđĆA;|ˇ” 9”*5Z-T"âń8†ĆCh·9đňÇVTšŐ¸am1šćŮĘq>ěrĂ——y6á8C(ÍS˘o$ŤZ…Ľú©31»e.ihfł###8:ŕĹĘĘ» ,~ž}–Ľ K–äĆÂődÄbÚ-źŤ‚ŠÇͱů-;ě:‹Íźř&ą!ˇyS*+łw3!“‘™±Ş$yy$DŽ>ýiŕ7żˇö¬ćfHérM&±UTPü±Ů üţ÷”LU\L˘%[ź]ťřč#úLmX‹áXDă,DIî8§»Ă‹ĹĐÝŐ…H8„Ű>QŽ_ĽÜo&S>Ę«-Ó¶BqŹÇ»Ý†ŤŻuŕ¬:>}^äŇôL§vOăÁ( K3űšŤÁŚCCC¸u}%ţôf/ŞŞŞRŞekvK˛(•J(ä2´ Dŕ$X–˘nŤĆÉ…l®Á˛É™Ë—.Ą$¬L PPuhófŕK_ôzŚŮí0Řló#>Ş*hµpÉ%´ć˘8Q%éîľđz±µl%|Ń(ÍHŚř|$p’­đ…ZMąÁÁÜ{Ľ±˙őśŠB*F(Oęľ©îpł, Ż×‹Á~7®-Ć_Ţî‡T&GSÓ’Y= ĂŔ`0@Ż×Ăĺrao׆ÝAÜu]ZSЇGiç1ÓŢŹL.î9ŽÍfÝnÇ-g—ÂŽCtěuJ…lĚnIĄJŤÁŃ í ,\şşh׼®nľĎdz˘Ńä|)çťlŮBQąsÉž–ÂBÚ•ßą‡ž}+ćS|$Đë©í*ÎÍęU*H$dX ÷OŻ'áyüóŠF©íĚí&ăýlÉh™ áČ"D ‹‚˝ގĚ,úöďßh(ÖâŇĺ<ľ˝jŤŐŐ5)µ@1 üü|¨T*tvvŕĎAyľ ,ËA­ Đ @mˇőEHf¨ćřB4 X’äî[ş•ŚL-îc±ŕņŐE¸dyţôfT*UN¶”ĄúúIĄRŚ"pÍÍ´Ŕ›ŹyÉ[·Ňnřg? 4N_}Áô<ěv2ÓóŤ\(řŕąçpđěłĹš0Ůž2~< íÄwtLT *bńĚ‹úÄŕÇůŠ& ˙±Řüť@ĆČ˝o{4¨˛¨áŹ'WI•LŚŻ]VŤ˙÷î UĘâă„c©T¨­­X®Ć°O{P‚ö‘(¶ÁŻ_ëŔ·ţz/îB <őE7ůчDś‹¤už©ŤFg|ýc±ěv;ZŽÁ¸w _Ľ¨מIQ»®ńdIî¤ţíĐ=˘ ¤úú1 –Mő]Xô S‹KŠě ęë©Ď˙­·H€üŕ´ ~2 pÇ”V• /H(„±în¬ę)ÔíŮ57‚‘Hčńć‹„ézh"b9.9żŚ@ú$„G.‹v´* ‹‚ĺzüżw·ŰŤ|ÓeBˇŕłź¨Ŕ«űlđchZR?çťz!µ'ÜĆq‚Á \.Ţ8äŔ[GťřüXu’— ѶŹÇ“Ş‚dŁM‰eY=r±x:ťJĄrâܢŃ(‚|~ëëL¸~m1ŚÇ c Çؤ_Ólű>R}ýb±Tňy*'›ó;l0 2ŇbëVJˇúíoOÝ-˙ô§i’»ÍF“Űů"µkµ" ÓáÂ{ďS]MÓľ·lˇvˇL´}ÍFâúôÝďNŢvl€Ş@†8öý‹˛˛ů=Ś EQ#òr=şvL&Ţânm6´J Ş,*üéÍX !ĎĐ—Ă0P©TP©T(((ŔŔŔŰÚ…k×ăšŐ…Ď©đŘL‘`0­V›‘sIŹÇX<Žłęňŕ Ĺa'ĂZĄµfW–au•:Ő©ó=ä|áĚxx˛M8BMÁüĹ ä(™Ś®ĺ†ˇô#ťčé!3řźţDÉH ärZö÷ó÷¸'Ďů(-“hńúĆ7hř_Oµ@e[Ě%fS0 5‰$óQ´§;ăăĹś˘7P`a EĂukŠđß/´Âáp €ĂśĎçËĺÂmç”aĎâ,˛6wC&“ˇşş6› /<ŚŢ?j 5XRŞC©I •\ŹÇ“„ă88vTYÔ¸ó˘ôvBÍ:9lňđd“X,żßŹšÂyě›ČM hG—ăމY.§ÖŽűŰäDr€ŇĽřU'‹ŹłĎătN‘u:ŠŤýŇ—€ÎNŞşd;M,“Ă÷N„e)mlÆů> ‘Ăͨ©QaVăâe  ÁçóÍéXŃh˝==¨4«ń‰%fęó@§Ó&müć†aPTT„ňňrôşăxé#+~Ľą?zţ(ŔqpŹşŔćŔŽęčč(|>?®;ćçH–ă04„ӆϟ9O¶p»Ý‡SÚćĐÔD‹Ş…ćHh±?< <ö؉WP09#c.L5á\ˇ ńˇ;nnRm- ē˶6š[Á ~«EÉČ}¶nĽqľĎD CD`QqÓúT¨ŃŐŐ™¶‰D"čěh‡\Ěá«—UCÄ˝#¨Őóc„3›Í¨ŻoŔĘU«P[[‹+C G$ĂđđđĽśS‚`0Á~¬«ÍĂ’,ŽxĂxfw?ţő˙áGĎE‡ÍѱáŤ|mŁ:@>‡Ý†3ŞŚ0¨stÎŔü±d Í’p»ů=.ÇŃB<“~…‚|!Ď> X­“·××Ó`Ĺąl„L%>ŚFj55§šöëꀿ˙ť’¸z{I)I‹‹pÖn¸ać‹ A€,*¤b•ůJ´··ĂfłKa‡lll m­-‰âxđÚzäidFâEăI{?2µřez˝µµu¨;6KŔn·Ď[$ ˘łłz9>s^rQś‘‹żż7€ďý˝»ŰÝĐčM¨««ĂĘ•+qĆg@ĆSKĹ\’żŇ}˙¬V+"‘®;ShÓ‰„ÚIFGů©$§…xs3Đ×—ąŠ€ŮLbŕąç&o«¨ ńá÷§wĚéÄËŇó:çś©Ď`~ňŞČřýŔŘXzŹ/{Äăôy6{ďťďłČ ‚D`ѡ”‰ńÍkę°ů!ěhÂ¨Ë łĄFŁqĘŞÄ Á‡Ţńq,-Őá VNĄw·ąĐ|‡dČFJ“N§Ă˛eËŕőzçl¸ŹÇă…BP«ŐI˙ŽÓéÄŕŔ rÜuÄ"űşÝ8ÔďAŹĂ—/‚hŚ…T"BžZ†*‹ ĹZĽqĐŽoĹĹ%°X,›ű1Łz:ďźŰí†ÍfĂ k‹QdĚě€HĚg?KÓĐ­V2×ÎŽŁÖ¨N'7m±¨¶nnűűß©:’ÎPÔéÄ@"-®ľzćc¬]K?­­4@qˇxk¦&Ł íń8đË_žŘ~'°čŔ˘D"á–sĘpV˝ /}4ŚĂýýčďď‡ZĄ„L®€X,˲F"üłĘóUřĚŮ5XYˇźXÔďlvŕů=0›ÍĐ$™Ež­”&ą\łŮ żßʶ¶6455Ą<Ýď÷ٵµ°bĹŠ¤DV<G__ŕÓç•㣮QĽ¶ß_(•J µZ‹‚B9D"X–E8Ćá!ötŚB!—ˇˇ1őóĚ&©ľ>ź===XSmÄ« 3tV‹‚‚ŕ+_ˇX[ťnî ¬ÁÁÉęÉ”9ń‘@§Ł˘ÝN"j÷n şšŞ;©0“řÇéř^ÜôëĎ}Ž‘Ç#¤%-d<ú,Ż­Čhĺ/żHqq1\.'ÎoĚGŚĺđ^›Öci5+W®<ÁűŤFůůůĐ͡D$ˇHČĹGaa!ZZF±ă°W -XÉ RQÖŁŹ/Ľ@ ú‚jqšîzŹ“7Ân§)@ž f%MÂŕnłŃ"2•9DÉ€^ˇ!ňu¬\™Ü± €Ť{îˇ!••Ůź2Wü~PÓĄ™©ŐTčę˘Úl‰N>±ZéÜ/¸€„sM yxŠSŹpXřD çp°ńŐDYęëëg¶—H‡Ňétp»Ý8<ĐŹďnj ŞŞŞ`4gJĄ°X,čďV§Ďř®=_~©T ­V‡awe¦ÉAaEEE§´<­LöK] )”J%ňóÍxă  /ł@&Y »ŻŮE.ľű]ŕ˛Ë€_˙šâdĺrZh*•ÔJÄqdĆ)ŠeK/Ąx˙÷äůČćŽń±Í „Bôg˛^®dĹ09]|` yĐ}xŕz- “«,EŁTuđűIPeSĐ“ž»ť"†ýkŞ4 > )ł™žŹX üřÇŔË/Óąć°—îśN®_˙:U;N{"S8˝al|µśH††úÚ¤} ‘ĽĽ<¨T*´·µĺX444¦lxV*•¨oXx8ĄR‰N›Ý?JKKa±XrÖ·’+đŃ‹GFFp°w kk…)č)°nđ׿RŚîöíŔľ}§ĐâYݧ–›őëË/'ńqë­ä˝H,ÖłEb˘JEç–L«S*â<ćź˙śúěeË€gžˇĄ×_'ŹŚ^OU•ăE]˘ĄÉ㡉„*ńxvH,F‚Çăˇa–ĄEů]wMVnôú©÷›ß¤ĎHw7 fL2~Ţŕ8ĂĂŔM7ź˙ü|ź‘@Ž lŐĄ€ĎçĂ·żým\~ůĺ0›Í‰Dxřᇧ˝˙ľ}űp饗B«ŐÂh4âć›oFOOOĎxag9<ľ˝1N„Úşş”ÄÇń( ,YşË–-Ďé´ĄŮHuE˘µŞşş‚řH‚ąĚ 9…BµJ‰ć/Ç[Ě×Ń)`ę˙ć7©˛ńöŰŔ‡ŇĎöí” tÇ$>l6jĂ™iź)Ľ^J˝Ňé’›7’Şř&Ź»tizç—üבąę*Şutßfß>`˙~ŕČjwŇ逯} xí5ŕ“źLďńR…ăč\:;IxÜ~;đâ‹ŔżüKrmc*đ»ß‘íč *I¶aŮäŢżźžçđ0đĄ/ßůŽŕń@¨€¤€ÓéÄO9í"ݵµ^x!VŻ^Ťçž{Á`ß˙ţ÷qţůçăŔČĎĎĎňŮç>oAż3€ĆĆĆ)çu¤Â\?HŐRYY‰ňňň›2•j5˘˝˝2™ éűtřŚLV©5čvŚóvĽĹŠpťŽŁöŁŽÚÁŹF©-«´”ĺGŽĐýŇMĎJ—h”vě?ójmJÜ6ݢ9ńLN5żđÂąťom-µ¸}ç;@?U•Ľ^jc2™Čpü秬lŇťÉE2ĂĐă;ťŔŹ~D•­T),žz řö·IĚäçÓm3UC8Ž„Ă\ż˘Qjq‰¨JŁŃP%îxĂ|˘ş3>NŻë#Ź×C@ŕ8ţ*-‹TVVÂív\.ž|rúĹË÷ż˙}(•JĽňĘ+ó#Ö¬Yşş:<účŁřéOš•s^(Dă,^Űo…ÉdJi Ţ|ĂW ĎT¤ş8ffÁŠ uÁ5>N‹ý`0€’’RhµZ^«>©ľ·rąöQoŹżX®ŁÓŕvÓ”ń—^˘*@‹:‘ĺG˙ͲôwiVÓĆjĄÇĽáZ¨´ĐśJ€¤+>€É6Żúz~Î[$"Súl3EV¬ ,ż?ó⮼śň?ü!°ysz^Žü|ŕ ĎĚţ@-|:ťűÉ"żź*%ˇ łTÂŽ'§ĘQ$ś>pŕŔägőx¤R×]\tQfgÓ,X’&Ü ĺÇX,†W^y_řÂN^W^^Ž‹.ş/ĽđÂâúâäć~Ć1,©Ę˛pŽdcęů|‘Í!Z¦ IDATIq5© .©T‚Ą%¸ýQttt@©C§7@­VC­VĎ9@ Ő÷V$!gÁqśĐţ–$Âu$(6m{Ś„†Á@‹Dµzr¦Ç‘Ga|śvÎłťđŹÓă^~9ízëőT‘ńxNm›‹řČQP@)IŮdÉŞL¸\™ C•ŁGI@¤ë‹H¨…ë†hBý¶mŔÁÔňtTJĹ‚óldkęy¶ůۡ{Đîző¦‹Ňţ} sâ…eYÄb1,+ÓáĽĆ|´ ŹăývŽ ¸`·Ű!•H°tٲ9U„R}oY–…T"ÄOś×Ń@xč!ŕ˝÷h‘X\<ő =†ˇ6…"ůů|"“č8|ÄXLń'ž Ń”8繊ŹXŚČwdß+ źúUŠŠ2ż€–ËIĽmÚ|öłs›]˘T×_O?79Ř/Ńn–T‘đź˙ lŮBⱸxö –Ąč\›ŤŞ.żúĄutÎĄĄô# "‚É.µaäĺťš†“——71…ş Űq9L·Ăµ&Ͳ°ďÄąęMĄ- 2] …Bŕ8 Đ Ă0h,ѡ±DŽăĐď ŕ'˙l…ĂáČęś’P(“f/†sŚE …ČxÜŇBŹéRŹr…ÂBšÍ±gpîądÚ~ę)Ú//ź»ř¨ÍK$ną%#OaVn»ŤĚëd¶Ď´2™€övŞ„,[ĆĎ1†„ÂTţ(™Ś|'çťüâä'J¤„©Tô÷ CB0"ăőŇ˙ßtpď˝iW‡X–ĹČČśN'ü~?âńř±řx-, °ysšqÚ ]»váâ‹/NęľrN€?\ľ “‹äcw=ŰíE ŤąVv2]ňx<ŠE¨4źčbf5.[^€íÍV †¬UŐ~V•/˙×Ń4á8Jj:z”v“‚ďMĄ˘ź;H€ ŔÝwÓŽ¸R‰±>›ř§ťöů—ÔŰřBŁţýßÉÜm·“čĘôă‰ĹäĄŕK€ĚĂW\A&˙×_^}•Ú¶âńSď[\L-^7Ý”vKśĎçáC‡ĐŃŃp8 †a “É ‰ŹÇ96TS§Óˇ©© K–,I;S`aqÚ ĆĆĆÍŹÇSVV–ұMÇ.žŁŁŁ§üÝčč(†q†‹ó7ľń  †n»ýöŰqűí·§t ŽăŤ±%Y‚ćcw}>Ľn·R©ô„~öl˛XDÇquaUĄŇi†ţ]{f1xĐÝŐ‰ú†ĆڎA‚!,/Ď­‰ľ›6m¦M›N¸mllŚ·ă ×Ń4ٵ‹UU C|´pU«Ź?žĽí¶Ű€;0¶e 6[úâ#$Ágźűݧť2_ Üy'Í!ČÓ©ťy†ˇö©ľľĚ&äňɶ­PÎÁĺ"!˘Ő’GeBeY8pűöíH$‚Éd‚Ńh„JĄ:ˇŇŹÇáóů0::Š?ü‡Âů矏ĘŮB˛H¦ŻŁ§+§­),,ÄżřĹŚ»¦¦JĄ‡:ĺď>Śşşşű–7nÜŐ«WgäÜr†a 3`é.łŔÇîú|x7ş»»!•Jçm8Ń•ËbĄŁŁˇP—®¨šö>2‰÷^Y‹Gţنöö6ÔÔÔB‘Áˇmv»ZĄËËs«ŤfŞ÷ľ}ű°fÍ^Ž/\GÓ §ŞÁ@3+J%Ž>±ď™Í8Ën'ńqÎ9©‹ʇż••Ô” ‰I÷ÜCUާž"źNYYćRÇD"z ć…hhŕíp‘H[·nĹđđ0 QXX8­O,CŻ×CŻ×ُ¸Řşu+V®\‰uëÖĺD[V¦ŻŁ§+  ‘Hpíµ×bóćÍđ7$¨żżoľů&nşé¦y<»Ü$O#G8žďÓČ(«V­BSSoÇă8‡ă„ĎŘL|~ĺ“I ľôe‚DünľöÔ–˝„dÇa;^?`A-E(Ć‘#GĐ—ˇ]Fżß—Ë…«Ď(‚T,\RůbŃ^Gß}—|™nďÉ ™’ŹĹđnŢĽÍ55Řůĺ/CyĂ `FF(¦5šýXˇÝ·ł“¦Á?ńDúń°|Ă0äwřéO)ĆöčQ2pgŠE0·*A,ĂkŻ˝‡Ăúúz”””$"—ËQSSŇŇRĘţsľDĄ›_{mB|Üu×]“מ €Ë.¶oŢxŘ·ďÔj\N^Ź+® ą"9v˝?…ŇR@fHQEoÝ üóźT»űnŕę«sF”q«Őж¶6 4E…KŻ×C"‘Ŕĺrˇ˛˛rÎ…- vďŢŤ˛˛2¨TŞ9O ÷HŠôôô$}ßŐ«Wc۶m<›ĹĂŞJ”21ěvűÄâ#W°Ůl°ŮlqŘQRZm–Ú˘Ń(|>X–E$AŕŘŽ1˱X_›‡Ö•ŕĎoöbtxńx|λůŮ€ŻĘŠZ­AŹcď·»đô[˝P©ÔhZR“Tâ•T*Eyyů„éëëKą‚äóůĐ×Ű Ăâ×ÔÁ¬ËńETŽqÚ^Gý~č—CŰ”°ůƧ ärŕškč‡ei~D°k0©;|©pÖYŔqü‹‚Ä`GŽ#‘c·?řđÚk””–ާ†gśN'Ţ}÷]8( čőz”””śd …ŕóůŕv»ˇ×ë§ŚÎN‡ŇŇRx<ěßżçž{./ÇČrĹ"° ĆXŚŚ‡ÇÁĐ*%0iĺIď Ë$"\±˛/~4 łŮś3 Ăá0;šJ´ĹŃŢŢŤF Ł1Z­rą"‘’Ľ˘QHĄRŢ*‡6›  ŠQ–ŻÄ…ő…XW›“VŽW÷YŃ6<ŽŠŠŠ!>f"ŐÖ,ą\Ž@8†§vő"??ĺĺĺIżî ĂŔl6Ăd2Áfłť’”4ǡ»« ŃX ?şu) ô™3· ,2făLšAŞRčtü/”ě..†óXőfJńq2"EąçV:\Ę\u ź/s>•DĘXu5}NöďľđŚ8łn8ŽCss3öěŮ…BÚÚZčtş)ßsµZ “É4±yČ×w D"ŮlFkk+Ö­['Äó.2öŞE`^ „cxżÝ…ŹşÜčń=É+&•P_¨ÁşÚ<¬©1ÎjĐ˝tyŢoEoOęćä—`Y,ËÎiaÎqş»» —đµËk “p°w oµ8Ń680ń|E"ě±˙)//‡™§IĹůůů°Ůl¸ęŚB\fń ő.»/4Ś˘˘"äO5pj‘jkVâµĐét)‰Źă‰D(NcaÄ0 Ę+*ĐÝÝŤ÷ă®KŞDű›@éĎÉŕ y+ärDÇ—Ń=ÂŘŽ8Űn‡_©ÄeŹ=vz}ćׯ'a`µRű\¦ź»^ÔדA˙ž{€§źÎşghďŢ˝8pŕ PRR’Ôűť‰Ď„Éd‚ŐjĹŔŔŞ««y?ľŔü!”‰ł¶˛ăŐ}VDâô:JJË T*'üŃh@ýŽěęĹć‡đÉłJ±¶Ć8íEJ*á«—Uă‘[ŃŐŐ…ššš´DH$AGG;â±ęęŇ®¦Äăq„ĂaÄă,ÂQ ©gTqF•áh}ÎśŢ0BQű{Üh·úxmĎ’ËĺČĎĎÇ»­.\·¦xâ;Źă8<ł{*•*«“ľgÂď÷ź’ďž ©¶fi4 ¸¸x^BUUUř¸»5j\˛|NăČ.‰j[4š™ăsMU//vîśśp=έVt:\vß}§—ř¨’ó­o‘7ĂáČNEB.jj€¶6ŕg?~8óŹyŚŁGŹâŔ(--EÁJň”řú•µ„ühokEđXÜc˛ŚŹŹŁ˝­‘pŃX­­­¦ůe/‘HĐŘŘąLŠŤŻv ™ś+—ŠQ_¤Ĺ9 ů¸x™J™Ťš÷Y&“ ăÁ(şě“1¤­ĂăčwPśä®T¦‰ÇéuîîîÎÚcĘd2”––Îk(€Ńh„ĹbÁ cÔ—»±Ĺ9„R X,ÔëĎ7GéRkÖ˙ýß´cßßO>ŚtIŹÄ„óÍ›Á,YÂĎą»w[¶a}ď^`Ў“9ĂÚµŔg> MzZ2ŤBAČ_}•¦ĄgŹÇ÷Ţ{fłyŢĹG…B! ţ[„¤qű"řŮKmđG8Ô×7$=Ń[©T˘¦¦ŁŁŁŘ×Ó ·ż÷_]Ů4S¬ëŠ´xčúF<ľ˝--Ga2壠 `ÚĹ}"Đn·ĂívٶPĎ_PŹź˝Ř†8#™S+—Bˇ@MmÚÚZ±iw?îĽčÔáwǡĂ6}ž%íÇ™µZ ‰XŚN›uET]ů }J… üö·™},{öěT*EiiiĆ+Y$ɢźv:"¤ÄXüzK'ü ľˇqĆ ÄÓ‘——™L†ÎŽüéÍ|őŇęiwđ‹ó”řŹ››°ó°Ż´ăÓ •R •Z=aüN´Hü>Ca52|ţ8»Á„—?F GSSĂśwÉ•J%JK˰§Łç6䣾řÄ…ż?G Ga’­^©,đ†B©€ÝC_ŽăĐ<č…Nź—±ęÇ\˘r{ş»QW_ĎŰĽ“\G,Ă”oĆűíÜĽľtZQ- 0ÁWŻĽB‰X|ĆńJ$Ŕňĺd`îě$łLF»ő]]”Ľ•¬‰÷dńqß}`îż?ýsózi>Č‹/Ň9éő´řW*éĽ9ŽÚŇ:˙ÇţřGŕ«_nż=˝Ô,żxöYŕ™g—‹G©ś ±™ö9X±‚ ßçź?ł ‹©şôË_ұ˝^/™Śeňó|đµYřßčJ066†ľľ>TTTĚ{äüńp—Sç#Ŕ‚HŠÍ Áá ˇˇ±)-ń‘@ŁŃ ˘˛ű»»ń~» ç4Lo –ŠE¸bU!.ZfÁá~šű=čńĂĺp#g!“Ż“cyŤËËőh*ŃA,bǰý°fł…·–(“ÉçČ^ţŘŠO 1HÚđžę_,–Ŕ˘Çđ…bFa.Ęś!1U?F´hLŹżý ̆ éźGk+đ•ŻĐsnhH~č TJFzÎů®»€'ž]„pđ—żP«’Á45Íü žĽ<+‡QĹĺţÍërţů$Bvě ŹĆ޽䩪â`ˇDBďekkFČŕŕ t:]NU8ŽC0DMMÍ|źŠĎäΧL gŮvČ©LĘ낾¸¸ĹřňÍá~´ZÍś*5Sa0Ŕ0 Ž xN¸]«śLţʱX:=FüXÜo˛íWq.óćhŻ× ĄLŚ"ŁU5ľws*óčěěD{[FGG‹Ĺćü8,ËâСCčččHęţsyî;tĎ„€™ †aPS[xôĺ6ěnu¦ý¸§ gź Ü|ódln¦É&[ťFF€˙řšĽírŃ®k+ů#ZZ€®.l>˙|ĽsË-8rÁPľ÷ŢÜćËEž ‘Î!oN÷˙Ű»óř¶Şk_࿣y˛eÉ’g;žíĚ! HH ŔëđĘ<\J[ ŔĄPR†ňÚôv¸}÷Ţ2äÝŇ^h›K 444PH[ć’9ŽçŮň [¶¬yŘďŹ9q,Ű’}t$Çëűůř“D’ʶy묳÷Z ¨¨ŕW˙~xň„ú—_ćÁGn.OÂŹç9ŤF$…ĂŔ]wńml“Q(ř–şź˙Řą“ß–¨“w…‚Ź ÂCĘuw»ÝČĎĎOöPČh„L( ă ýČ´d‹zUD­VĂnÄÇuýX5_Ü=­M=n荙˘ŕűýő:-šz\X5˙ÔíĄf n·™™â>o8†ÇăEž‰oUÓŞřjQ¬'ôbuO0„ÍfCN†fd%ČlPá[›*p¨eoěFăÉ®×zťsŠK¦´Š …⮲5ťź=ŢmrŤ••hmmĹËkB.`e…řďAryŕŕµ×řĄęęÄőyP(ř–ŻcÇ€§žŠţ‹ť˝˝đ2&—cŢűďO~‘Ł»ŘżźŻ° đŰ22ř Ŕ˛eŔ¶mĽq_uőô:źkµ|üź}ĆŘo¸!úă>ů„Ż\ääL˝ńˇRÉKßÖŐń-YŻĽ{žÎÉ­¨ @H`"v0D0ýÂÝtőööB§Ó!G¬ž6$ePB&ÔŇë†/}+ ¤Ťhim…Ç9±ž®`(Ś!O¦¬Ř®|Ĺ»MG©RŁĎ9öĘúÜü4ěkc˘&‡ !ĚŞóůÖL 2đz˝1mCJ´ČŞŹÍášÍá}AŔââ ,.΀ÝéÉN'ţ|°µ'jPPXł9ö$zĆśQ‚2't›ŔT‚APTTĆ~ő×䙵(ĚL­«‰$E9üŕüď EâNZ#´Zľ‰1ľ* “ńfŻčď‡ăĐ!äuuáR‡Ů{öŚ˙»ÉŻőë_‡ź:v$ß+’ŘQR"N×÷ôtž;ňď˙Î+dť¬y˝Ŕ÷żĎW1¦Űu].ç㮩ţó?Śíű"c …&~ÜT1–Đf„áé”kNŹÇţţ~¬\ą2Ą¶…qĐ˙(™PGż‚€„,Ëęőz0đ“W±DzŚÄZ…)Ţm:rąľ(}LVVdÂëőÁétĆuĽÉ¸\.€ÉŔŻJ)ä2Yô˘?ĎTiµZ,]şř廍híŰß 3MŤ Ş,xäšj,-6˘ąąuuµŚ)oF¤§§Ăjµ˘°°EEE)űa BÔj5~ý·„cĚ "łČ+Ż·ÜÂó*+y&rë&ĄÓńŘHŔŁTJ%‡Ź4Ě6™ |ĺ+Ľ/Ç™ÚÚ€[oĺ Ř--|Ubńbž+QYÉżćÍă·•”đ@@ĚÄáÜ\žËňÇ?Ž˝oçNľĹ¬ @śpµš'˘ďŘÁWzb‘‘ÁsjµJá÷óž ˘T*!ÂHQ‘d ‡ĂhiiAZZćĎź?ů7'5?ĹIĘô :91M&ž}óźđŢÜP,‘2¨±N˘_]üb\IʡPę(ĄV+s (ĚÔˇ«ł#ćdôXX,Čdţ|ŕÔŢßĺĄ%ŻB 2™ %%%P«5xţÝFBŃŻ¤iUrܶ¦÷­/‡IF}}=:†úz´··ŁŁŁíííQ˙ď***PTT„¬¬,X‘´+"™L†‚Â"´ôşq¨epňo łÇü/ájµňö´´Ä÷‘Ď™Ąv/żÂŇĄ|ËŃcŹń’ąź~ Ü|3ßšTQÁż23O­|ś.’Řť›+îϦRń•Ý»GßÎď}b2ń@,YY|ü§ż`ÁľíLl~?_YZ°@ücź$“É––wóßD`ڎąąŹkÖ¬™5eÝgÚ‚E&ł¸žăŮ79n$±:Vţ`GÚQÓáD»ÝAOačŐräůP˘&рߋeěö.Apýůř×]üĘ~FF†(ϧV«aµfá/‡{půâhTrśW™‰?|މîîî”IĚ“ÉdS\‚ăÇŹáý#=X·xüýş ŠŚ_Ž6»šhčF[ź}¤ś±Ĺb™ń8iii0ôŘ{¬KŠĹy/îŹä˝-ňóyžB2E >"«ĹĹ|ŇÓOó€—ŃŐëůĘF27ÓÓyÂĽŰ}Ş÷FC_M*/÷ąärţ|ďľË+yĹâ’Kx^L0=8›Şţ~ľbµrĄxÇŚ"77---`,öĎ}±A477chhkÖ¬Iů Ndę(!Ň©‚1MHń\Áשcű@óúCřóAŢ;Ú Ż?­F ŤV•V9w0cÝ|;W"–‘Cˇ\n7Š­ŃK,F¶‰ťÄgµZŃÝÝŤÍśW™‰t­kfcϡnÍfQJ#‹A«Ő"3Ó‚=‡ş±fa6ä˛ńß/‚  Č˘C‘E‡pág»ëPosˇ¬ĽB´Ţ-Éf2™QÓŢŻ?ŤH9Nd†˛Ů€çžă«©|üJ~a!ßJt×]üDZ§ăUĄ’˝őQ§ăUŞZZř*Ě‘#|UIâë«´4ždďrĹ–±aO„ďîo»T8ĚË5_v™¸Ť+Ł())Á‰'ŕv»ˇO`ľI4‘*\ťťť€őëף°°PŇ1iQB&”•®F(F ýÄÚëĺÁB¶qňÎťNĽř^\Ţ 2-V”Y­ăž¨†Bˇ„\˝‰ä,Ś×lîhŰ 4j•čů2jµzťGۇp^%ݬ´iY.ľhr ©©••U)ÓôĎjµâx_Žw aAal… v°áD‡ĺ0$řVJiii` hîuˇ:?ůHýß˙Ë˙Lö ŐdÁG„ đ>GŽđ¦€óć%?řN%´?ů$ď îtň• ł91ă‹\Üioç%z'“‘Áűüć7<ŘăbJW_Qąí¶ékHKKCWWĘĹ^Q:C8†ßď‡×ë…Óé„Ăá€ßďGqq1.¸ŕ‚łęł€D—3 Iee'›Ş % V}$‘şµĎ=˛zpş`(ŚzŰ0ţđŹüä­Z@®ÁÜyóQXX8áUrą\.z’2c =ÝݨČ5ŚjBxşÖ>´şÄ\5ŇéőŁĽU  B8€úşş„ő ‰—V«…ZĄDMGlIň}NŢÚß…ěśś”¨ę5™xňś"ďŃޡĕÎ$3@OOęÎĘJîöĄXʵ𗤭®w;ŃtDćő†ľR]͓ދ‹ó|‘˙Żxň:n˝•wśonž~E¬ÁAľšrűí< L0™L†sĎ=”VN¦¦&=z FYY6oŢŚuëÖQđ1K¤Č¬BR•AŁ€IŻ‚Óé„ĹbőŘŤJ…˙±§*… VebĂŇ\„Ă ďęĆGµvxü!Če¬Ö,[â6v».·W^Z9îcú]~¨b\¶Ž·üŻJĄBGŻ?x˝PZ•ŮF5V–›±÷hď¨ÎăÉzŤľµJ«ÓŁ-J5¬höfS0 IDATě†L.ź15ŢăÉs ą jT•!IňÎ;üO‘{Ĺ%Ţŕ#B¤\6Ń(|ë•N'MP)(ĎsétĽĘ­·ňí[ĄĄS <ř÷§Ą^ČW{±Íě ĄĄĄhhh@KK 4M¶řF.Ţ|óÍĐëőIýÜ"ÉA™P›ÝŤ—%Yâ÷±Z­°Z­đů|°ŰířŕDŢ?Ú P*ä0gZ0Çd‚N§KęääńxĐŢކ•fTĺŤ˙ łW^âMŘOKK1=ΰ‚L€ŰBW›.7O¶÷‚hhh€Á ‡Ĺb…Ńhł-‹1·Ű »ÝŽŢŢ^”——ÇÔß%î^)J%Ü“—VĂř´®™™Ö“tOžc aĆ ÓBó¬öŮgüÄ1Yďń©©JĘ•R˙É2íń&BWVň\űďNśŕ«ń\Ő…xđđŔă+_áĎĎç‰îW_ÍW§@¬Zµ oľů&ęęęPUUőTşŘOB©Tž,ÖA«ł dBźÔÚˇR*`Jŕ–Z­F^^˛˛˛ĐŐŐA›››'Ą^Ż őuČJWáć '^×(ĺq•˙Ť‡^ŻGyEĹŰÁ ĐÓÓ Ż×‡áa†‡yď­F ĄR¡ Ľ^/‚ˇ0 ţkď÷ÇÖ%Ţ`I&“!CełĆĽPBß[É 3dčEhÄFf®ş:qËĂĆăl >¤I>źĘ í’%<äŃGySC“‰2Ăäĺ‰ĺrÄ˙{8Ě›-Ż˝Ć{ɬY|ë[ )j R©pĹWŕ׿ţ5‘••%úsB™ĐáÖ!¤3$YP()Ső‚1‡ĂÖÖX J|scĹJFľ@öa?|0T ҵ ôÄpĺ_L …V«™™™čîîFWW'˛Ť¬šgEĎîÂŚA«Ň"+=e9”eđí_LX° ˇŹˇęSKŻ r™,eŞx‰-ŇD˛Ŕ|vţ|$FĎ˙Óçtçž;ő÷ÂBŕWż:U‚ą¶–÷3ŃjyB˝ đ­VVëŘîgn·Ňëů6>Ć»řŕŕ“O€gžţ韦6ľ h4¨Őę„ő› p:ťřă˙´´4X,Ć´*O΀q‚atz1gNv˛‡"Şp8<îV)ĆśN'şm6 9ťXRśŻ^2z5˙UéôâĂvhvÚÁ}şd2rssˇ×ëŃŘŘ€·ľ°aŐ< ®Xž;2öÓYŤj¸Ô+Ĺçő˘,wâ+ľŚ1txˇV«bnr Äľ ,8dTă- łcŇ7¤ŕCĎ©~#S%—×\\upčjkyu«ş:ţwl9sř{Ébáů9--|ä©§€őë§7Î(L&ÜńŚ-fł‚ Ŕëőbhhuuuř裏ťťŤeË–ĄĚĹH’8€q9Nv(ʵüîL8Iôűý8|ř0A€Ůl†JĄ‚L&C(‚×ë…Ű5  <“˙k]ĎáIÝCî^ű´źÖőCˇ#Ý9s˛ˇŃhNn9 Ăçó%=‘.==UUŐčééÁźľ°á/Gzpă…XY1:¶"Ç€kDo8 ár»Pž3~­ÇÂËmÁţ¦dÇxe8Ţm`‘â} áŔĆĄŮIO$3xU©Pđ!ž¬,^ÁěľűřI˙tČd|[Ö’%üß˙;đíoóŐŹHĂÇx(<Á˝ĄřŢ÷xĺ­ĄK§7Ć3äççă‹/ľđ˘ÝTŤĆQ«áp‡˝˝˝Ř˝{7Š‹‹qńĹź5}ˇČX€qBĽ4n˘«“áTb6^đ`Ŕ1„`( µRkş eĹ,žcDIÖ©Ş5CxţÝ&řC ……°X,Q_“TI¦Ójµ3gňňňĐŢŢŽíď7ŁˇŰ…/(„ědsŔĄ%xďH†‡‡‘&be•€‹çD_FwzřÉ[učôˇ¤¤$ćüŹx·MDŠ÷igg'2`Ő|Ú;=ë•”śJ(N4 >Ä•ť ôö;wĆŢ =đÄ€ŃČŹ©^¤`ÎŢ«ĺŃGů8EěCUZZŠĎ?˙ČLp7™LłŮ “É„´µµáő×_ǦM›fD‰v? @ȸ´'÷ń'*W@,ń\Ń–ÉdШUX5׌kĎťĽSíf~ůN# iĚ-.R9sŠ•J%JJJ`0đ·c­„ÂřęĹs *r Č5iaëę‚Á`ĺ*}8FO· KŠ3ˇ{‚†ńooף×@eUuŇr?ý>Doo/n8ż`$áźĚbË—‡óDâD6óŁŕC|r9ŻşµgʏČ/É“ĘçÎťţöĽHÓČăÇ—_ćÝëE’‘‘ÂÂBŘl6L&ŃWA˘‰ěNĐëő¨ŻŻÇ®]»pÍ5×Ţŕ—$Ő‡$ă2ę”PČ…‘Žĺ©*Äb«ć!—Ëŕ LT5÷¸đü»Ť0Ť(/ŻQÁÇé¬V+ćăŁö‘2Ç‚ ŕÚsó0ätŠÖpĘfłÁď÷ăŞsň˘Ţżół´Ů=(-+?«Ď›š± ĐŐ hő€W+ xSąDˇŕ#qŇÓySAglÍU'ĺpoĽÁ·^‰ő™˘VóőW_ĺŤV®\ źĎ‡®®.QŹ;µZŤŠŠ ř|>üĺ/c“WV$3  d\2A@±U?ұĆfŤ3 c v»uµµ(¶čpűÚČfř{†¤ĽX¶Św´NÄIT˘‚Ź`ho—6%E.–´´Lýđűßóľ ›7ó×TäĆľ°ZyŮŕ?ő°fł+V¬€ÍfÝnőŘ“Q©T(..FWWNś8!és“ÄŁ„LhiqśCC˘–âűďC÷Śl›Jä÷DĂ×€Ů0qŔ{Gz`öcNq‰$ËÎRČĎχL¦Ŕ[űO]ÉúĘEs›ˇA}]íHŮŘx444€(´čŽr’ő§/lP«Uge=y—Ë…††z477cyiľą©eň{ŘňŤođJGÝÝâ7QÁc@k+ogçôŹ7“Eň§r!nxřÉO€ŤýoĹÓëyʱWÔ5~ěO?÷¸/^ŚĘĘJ477٧§GŇŐôôtL&ěŰ·ápX˛ç%‰wvśY‘„9Ż22Đ-âgĽ[¦¦ú=Ѹ\.0Ć0Ç:ţUř`(Ś=»‘™™™r8¦ÉĺrXł˛đi]?\>PjTr|kS Ěś8q6›-îI^ˇP ''ZŤ˙ţç<ő?ÇQŰyęĂÚĺ â@łkÖŚZIbڎ¶öŽ;ж¶6Řív ahhv»ííí¨9~ 555P†}¸ë˛RܲşxŇŐ52 -XŔ»YwvŠ·+‘Ű®ş»yŠyóxvŠŻ‚'Täd;ŢƸ‡×]üîw|{ÔÂ…@Eď÷‘¨‚%j5oz(2ApÉ%—`áÂ…hkkCCC¤[łsrrŕrąĐÖÖ&Ůs’ÄŁ I2!Fµ ł±çx'äSI+qx``zµE–ńÚŽµÁĺ bNYę]­źn§ĚĚLtttŕpË Î«äUMôĽ˛oüŁďî@__/,+L&ÔęÉ{X‚€üü|äççĂét˘łł?ŢU‹ KrpŐŠ<śčp"f3®ăąĂá€Ó9Śś |.š{zFÝź®Sb~nÎ)ËĂÂ"ăH…1B˘şç^ 룏€âbŢ{ŞąňŃŐĹżn˝•'^ß{/pđ ßJ6Ľ=ĚćŘżçďzoßš;—7”‚Jôő%äĐ‚ ŕüóĎGnn.>üđC=zFŁ&“ z˝jµ:at:´Z-š››1gÎś„<‘ dR—ć`ÓšPYU yĽW‚RD8FżÝŽę<=äś,ďpBŁVĄd˘ôt1ĄR ťV:ŰđH ą םW€ Ş2ńö>­ë@GG*++ă*Ó›––†ĘĘ*twwc÷8ÜuJ¨UĘűÉL…Ř˝=ÚŰZ±°Č^_đBpzůĘ‘A­€&†nP(€ţ÷lxçžźj‹O¬|x<<çĂéäAÇ˙ţ߼ÂŇŹ~Üy'P_ĎKľÎ¶NŐ.ß.UTŰ㏾óľĘQR’ŘĘgg ĆŞ•SU\\Ś‚‚ÔŐŐˇ¦¦ÍÍÍŁîĎĘĘJHAÁ›Í&úqIňPB&ĄVĘq÷ş2üź?ś@}]ĘĘËOë§1łh4ďp˘©Ç…’¬č۰Úíh´3çJ_Ľ'ßjŤvÜ.îy&-®=7ű™|JĄA@NN”J%>®m¤Ĺ¸ĺ`Ş„˝=Bˇꡒ_ąřÔŐ6µR5ĺvéP©€gźÎ9řŮĎřÉŞÉÄżôúŃŰ|B!žCŕ÷óc@üŕ#ŕÇŔO”ÎËž{8÷ÜSŹIKžxě1žŕś•̦.ŐCCŔâű­b¸Ý<řĐh¤>žÜ.b_§ń( Ěť;sçÎ…×ëE__†‡‡ń·żý-ć˛ýńR©Tčíí˝y.IÚ¬Lb’gŇâ[›*úPsü8†††’=¤¸Éd2”WT@«Óáç»ë1੾W2ŕÄŐý]Śäřé7?FˇPŔĺ‹ţ!ÁĂím† W`îÜyÓZíĘĚĚD^/Ék•­©ćúÄ[ m<>źuµµř˝řƆru3łô2Ia‚lŮĽů&ßć$@]pŕpô(ďçpä˙w}=O‡łňqü8ĐÔääßý.đ?˙3:ř0€źţ”—¤ťfĹĽĹëĺČĆŤ±=ţżţ °ŰůJQ2Š—ř||{ź„4 P]] ŁŃ°‘sŽ@dK™ńfćel’ĹV=ß2/˝×„şş:ÓÓa±Z‘žž>c*EÉĺr”••Łćř1üęŻ-¸Ců«)á0"Ć+,©Đý=ŢmYڱq· jDM‡ĺĺĺ˘ô=ÉÉÉAgggĚͶ’ŐĚ2ŁŻŻ]ťť0häřÖ•U(ś OiËČŕ9·ÝĆsCŽl6~©Őąą<ˇř·żüţÄl» …€Ż} ¸ďľÉ ň±%¸#vJéěäąë×OţŘáaއĂbáÉŕR …řv±ĄKĄî“äryÂ*Uét:8ťÎ»ű‚Ś53ÎSÄ;;nş ĄĄĄP©T0™Lذa>§îöţýű±víZ¤ĄĄÁd2aË–-hjj’xÔâ2TxđĘJÜvi ô ^~őĐÁ¨=QĆĆFtvv¦|Ă …B‚Â"oÂѶ±+9:•<®îďbĺH%Ŕ¨Ť>‰ż} iŚ"íó‹/ĆĽyóD9žXÂá0|>ŃÖÖ†ŁGŁ­­ +ËMxâşą|$ÍŁgÉx‚÷UWń€äľűxP˛iPZ ‰K8gŚŻ~Ģľž lńI ýý|kÚ·żŰö«÷ßçy4É*5>0ŔŐ«“óüŕy~ż8+ŁŃëő3ćb'™ýOĆá…^€ÍfĂC=„wß}/żü2<VŻ^Ť÷ßÔckjj°jŐ*AěرŰ·oGmm-.şč"ô%¨J…TAŔŠr3žŘ2Źo™‹kĎÍÇü\5ĚŞşşşĐŃŃ‘ě!NĘh4 ×ăĎÇ–ÎÎPĂëőH:©¶r1Ćŕő¸Q96ÁľĎéCc÷0,‘ýć"Q( M@Ź—ËĺÂ/ľŔ‘#GP__ďđ.¬4ăű7ĚÇW/™˝š®°%ÍŁqP«áčîNL©Ý` ±ţľ··ó?S¬4yB8ť|ëŰúőŔĺ—Çö=}ÄłdĚuŚńrÉ^Čóx’Äb±Ŕív'ä"¤Űí†EěćŤ$©č“6żřĹ/Ć4R[·nĘËËńěłĎbőiWžxâ hµZěÚµ †“ ¸Ë—/GEE¶mۆçž{Nұ'‚ (ČÔˇ óÔŐâwuă>i‡R©DvvvG71Ai± ¶Ą'+5E”g°Ż±ˇPH˛Š_Rmĺr»Ýđů›ź>ćľš^ë_¬ŐŹTŐÓÝ …B†;×–"7CĚ4%5JćŃŘ5˙čG(¶ŮÄ>ľ]ŕ«/ń<~†VAŚY?>–,<ćíŁ8věT×t©Ůl|őĺžäć#b˙ţýŽ«zâd†‡‡±xńbŃŽI’ŹV@â­‹łZ­FUUÚ#W‡AěÚµ [¶lůĐ€˘˘"¬^˝Żżţş$ăM†µ ł°nQ6ÚŰŰŃÚÚ÷~PŹÇ#Y·ÓȉöéMó`Iqcčďď—d€t[ąúúú¦U˘2oě‡CGż:Ť:!AW0D[[[Â*¤ÄĘĺrˇ`7śW€…EFXŇW»žDGóhlvî܉˝W]…–… ˇť?_ÜŕŕUŻrsy)ŕXDr±Ŗ1žďp$ćř±đzy.NSpŮeŔĎ_.GoorV?yß–Ż¨Ş’ţůO“••…ôôtôśŃ3işz{{!“ÉPZZ*ęqIrQ2MřüóĎ1ţü‘Ű"]B-Z4ćń .D}}}B÷I&“ Řr^nş°ýö>?v v»}Ň Âăń ±±ÇŽĂńcG100đ\Ą’÷§č˝ÝĘdPańś ôôtK IÁăńŔnďĂşEYQ“ĐÝ(”‰©ţĺv»ŃÓÓ“Ô˝űˇP-ÍM(˛čđOŐ´”źJhmçÎťčëë_ŻGŃý÷C…N5ÄC0ČO\ŻĽ2ö+ü‘Ŕ1Żą×Ë«k54đJ`‰šűÝnľ’ăóń/§“w}Ż«ăĎ+“Ď<<őTü‰ä€ô•Ż0]x!ĎJ2A°lٲ“M\ť“C ü~?zzz0wî\Q!“ÔA[°¦éŢ{ď…ÇăÁcŹ=6r›ÝnŁtN5›Í`Śa`` Ą·(MתůY¨ÎOÇď?nĂŃćft´·!-ÝťN•Šoy đz˝vÁĺö CŻÄ†Ą9hîqăxc#ÔjŚĆ ¤§§#===¦+Őńö‘đůŘs°WŻ}đęyxęµc°Ůl#Ądg˛p8Ś––fd¦©±zAô$ÉpĹ|2ď–±Hâŕŕŕ 222bţ^1„B!44Ôá n_SN]ËS ÍŁ§D‚¸ýöŰ! ńň®ťťĽĽ«şşřVŞëŻŹý{**řź.—řy >˙sÝ:`Ďä]I*ć«,gR*ův«M›řóOuCŁIxŔˇ?ôô—^ʦ©UQQcÇŽˇĄĄŐŐŐÓŞZĹCss3T*–/_.â(I*HŤwlěÝ»—^ziLŹ=pŕ@Ô«pŹ?ţ8^yĺüâżŔŇ$–ľKU9|cC:ú=ř´ÎŽcíNtv >uu+CŻÂü\––äbŃ#r~˘ÚÔă‡5}řđDzzz0ţü®~L%—"{µ-߬ĹĆĄąřÓţ.čőúť™Ä˝ľqu”ňčWé´j9¡خnĆ[.7äÄ‹­:475˘¤´lJŻ)c áp8®mb^ŻMŤŤ}¸C˛ŚtM,4ŹŠkLđ!Ľóř˝÷۶ńҽӝ‹††ř‰ëý÷ó±ĘČ*+ů÷Š]Š7˛ě›ßäŰ-~é_ňČ#Ľ‘˘\ÎKěžÚ^6yyüçHĆxžG?˙’Éx…®›nŠ}K‚ `Íš5Řąs'ęëëQ>ĹĆőϭááalÚ´ ęd”6& 5kęęjĽřbl'Q…QşľnÝşĎ<ó ž}öYÜsFâWćÉÉ9ZA?A€i‚‰˙›ßüć+Ä7Ýtnşé¦Ć›jňÍZl^Y€Í+0cđřB…´*9”Šč'Ă%Yz”dé±vQ6ľ÷űŁ1 ńžk5*\Tý˙âŠeąh·{p¸±ĹĹ%ţźŤÇívó˛·I `‚Á š›šŕtᎵĄ(¶FďţŮF Ľő é4ëőzˇRČđŔ•Uř廍8ÚPŹÜÜźŮ99°Z­"@ÝÝÝčíéAfš woŞFľ9II˘IňꫯâŐW_u›CÄ“$šGĹ5ř¸á^eéłĎxҸ~üßă ąÝ@s3o6xóÍń˙ŐWó@Čç/@ř‰űm·ńm^|{Ř9/CC0Ŕ«;•—?üáÔŞY]uđüó|űOIIüßMg'ßöٶađ˙ţ?Ů+P‡ůĎżn]â¶*]|1đÚk<Č›j€ŤĂÁÇ~÷ÝĽÉŕÂ…â¬Ř$ŐjĹ5×\wŢyÇŹ‡ŐjEvvö„żłÁ`}}}°ŮlP*•ظq#ňc-’@‰žGg«Y€LŐSO=…­[·â»ßý.üń¨ŹQ(¸ňĘ+±sçNüđ‡?9™kmmĹűᅬx@Ę!ĎhJą %V=ěCCQ«çLÇĐoBX‘;ţɶR.ĂkKđŢ=^˙¬ýývX,VL&hµÚQ' Ś1ř|> ŔŢ׋@ €5 ˛p¤mMMŤ¨¬¬šVwńÎÎNŘl6€Vن1Ă˝^µZ ™L†P(Äsj†‡1č€?ÄňRn8żúÉ·Ą•f鑦UÂn·‹€řý~8‡śXľ¸ — ¸zE>–—šđćç]8ŘŇŠ¶¶6čő:¨Ő( 0Ćŕ÷űáq»ŕó®Uâş•X5ß …\†«ÎÉĹgőý8Ü:„–î.ř‚§ŠčÔr”dé±xqÎ)3Q_ŹDóč)“:đź˙ lÝ Ľű.ß•—7yéWʇç| «Vß˙>?ÖThµŔO<¤§O+Öŕ Đ×<ô˙y`ËžóbłńŐ1ôőńU›©¬úÄjĺJŢÔ±»›7C¤żÇ’%Ŕ­·ŠsL eddŕÚkŻĹˇC‡pđŕAôôôŔ`0Ŕ`0@ŁŃŚtN÷ů|pą\#‰ëUUUX±b%ťźĺč“9?ţńŹń˝ď}ëׯǦM›đÉ'źŚş˙ĽóÎůűÖ­[±bĹ \qĹxä‘GŕńxđÄO ++ë¬ůŕ”Ę9e&üţăvřý~QÚőŰíČ3k'Í kfcY© {v㣽°ŮlPČeP«ŐŁ&Ń@0Ą\†sĘLXż$9¬ňáą7jP_W‹˛ň‰ŻÚFĂ >¶¬ĚÇ«žčĂ‘¶ľ‘€ätf U›ńOUäűĺH&°zľ»öw!77W´×ÚfłAŁ’cEůčdâ‚L Ă~lq Áć‚mĐ·;ą\@Ž^‰Â"3椣*/mTĺ® ˝ ëç`Ýâ0Ćŕń‡1¨2hTgyź‚ŽćŃSb>"´Zŕ?ŕÝ®ö3Ţ{"-ŤoËŃéřŐ}AŕŰš<ľmÇé,ž¨Ľ~ýô·mŘ|ň đöŰüů¦ş˝txo-şč˘ŃÉđ pË-|ĄĹdšţj‚Ďǰ«ŻŽ˝çÉT(Ŕ]wO>É·{ĄOĽâ“ľ>ţ:%ążÇt( ,[¶ ,@cc#ZZZĐÝÝ Ż×;ňĄR ‹Ĺ‚ąs碼Ľ|Ú»ČĚ@HvíÚAđöŰoăí·ßuź ŁzTUUaďŢ˝xřá‡qÝu×AˇP`Íš5ضmŰČŢf›ó+3ńĆ?:`łŮPTT$Ę1].¸ú’Ř«Ęô*|é‚Bl^™ŹĆnšz\čsúŕ „ˇ” 0ŚcŐŁ"׍ňÔI°5]Ť‡®ŞÂOߪCÍńcČ/(„ŮlŽ)ĎÂëő˘­µCN'¶¬ĚÇşĹ9€ŞĽ4^ČŔŔ°ţPĄ–4Ň´S_eątAŢ?Ú¶¶V”––M;dxx}˝˝Řr^Á¨×ät& «ćgaŐü¨wOJčh•cĆ y”‹;řŢť{Íŕ˝÷€?˙řüs~’}:ťXľś—^*޶Aŕ úŕăŹů*…Ő{`ĂO˘nk-âŐ™y`_˙:đÁ@}=Żľ5Ő|“@€÷öČĘľő­©#°óIDAT7»v‡ó„ýé\Äq»Žľím†l%śJĄBuu5Ş««đíV@ … …‚ú1ÍBKtłłČžÂ}űöÍ˝ËRŮsІťźv ˛ŞjÚŰÂá0jOś@ş:ŚÇ·Ě‹Ú#\Ţ ~ó÷Věo€N§…Ĺb…ŃhłŇ‡1<< »ÝŽ~u*|í’9“ćpĺ@ł˙±§yyyČÍÍťňqü~?jOÔ /C…‡®Ş’ěu&;Űç™™đóM9řc€ÝηY|;“Ĺ’ŘęHÁ đŻ˙ üţ÷|&7—ŻÄŚ÷śŚńľ6ßzuĹŔŁŹŽ\Ří|%¤ŻŹç›Ä»âńđ• ŘľťçÍHÁnľúUľ RV6µŕÉĺâSi)đ Éë°NĆ5ć™TG— ÉŚ°fa6ö79Fr)¦Z’Ź1†ÖÖVx˝|s}µ¤'ĹzŤw^VŠÚ.'ţ| GŰZŃÚ ¨UJ(•J~ő7„Ççc ™®[Y€‹çY%M ^Rś+—çâŹű:ÁCnnnÜ'H^Ż őőĐ*ÜyY)„ś$zđđ“~‹…IEˇľóžWňăµµüD9˛,˛âŮ6<ĚŻęßűOÚžHf&ľýmľŐ,+‹çXL–D ńRÁÝÝ|ućg?/—$™™Ŕ/É·MŐÖňçÎČ-Śä|tvň”ű7 >ČY‹2#Čeî^W†˙óF ęjkQV^WY? ŇŚŻýýý¸őŇY’łĎ´27 •ąiöq˘Ó‰Ž~Ý‘ŇÄŮF5Ęr (0k“¶,˝iY.d‚€?|Ţ ·Ű…¢‚>ĆúúúĐŮŃłA‰ű7VÂCĂĂĂhkmßďĂíkJpNŮŘîĘR3hX^jÂňR‘ëÝ‹@l\–‹B‹żţ[ Ž= łŮ łŮ Á0ć5÷ů|p8°÷őÂăőáüĘLÜxA!%„rŇY|DDÎ=—˙Űçă[ăÁÂtN¤ ^ęÚky™Ű?ý hjŠţŘěl^éęúëůjI2Ť|ečĂyBýŃŁĽôq$p’Éxŕđ 1^Ië®»x©]BÎr€ŤWáŃk«±óÓě=ÚŢŢdfZ`4ˇÓéF>ÔcBżNç0Š,:|mc5 2©ÂF¬ńý/ÍÇߎőbďŃ^ÔŐŮ!4jä X8  €@ ™LŔâ9F¬_\‚â,ëŕ2ĂťŐÁG4j5żâ/&ł¸ývţŐ×Ç~ân4ĹĹÉ:˘ąđBţŐÜĚ‘ăÇů+Ż—çµ đǤâř I @ČŚŁRČpă……X5ߊwuă Ýčęę‚ Ş“ą`ˇď QžcŔM+K±´82ĘE›F)ÇşĹ9¸lQ6Úű=h° ŁwČŹ?ąL@†^…|ł•ąŞFEČf]đ!©ó]ÄP\Ěż!(!3XN†_ąxnş°-˝n´÷{0ä <’KˇAi¶~ZeiÉ)‚  0S‡BZA"$&|BHt€O!—ˇ,Ç€˛ńşwBČtPđA!ă“®¶'!„2 PđA!Ł„B „29 @!„PđA!±ˇ„B™& >!$v€B!Ó@Á!„ćB!dŠ(ř „řQB!„L„25€B!q˘ŕB¦ŽB!$|BČôPB!„Äh×®]|BČ4)’=B!d&`ڎżż‚ ŕ¶ŰnŁŕB¦B!$‚ ŕć›o†BAť„2´‹B‰„2}€B!„B$C!„B!D2€B!„B$C!„B!D2€B!„B$C!„B!D2€B!„B$C!„B!D2€B!„B$C!„B!D2€B!„B$C!„B!D2€B!„B$C!„B!D2€ÄáŔX·n ˇR© ×ëqÎ9çŕ…^úřýű÷cíÚµHKKÉd–-[ĐÔÔ$ń¨ !$uĐšG !„P'ô$űâ‹/Ře—]Ć R©d:ťŽ-_ľś=˙üóQżoß>¶fÍf0XFFŰĽy3kll”xÔÜž={ŘŤ7ŢČJJJR©dlýúőě>úřT»Óéd=ô»ě˛ËĹba‚ °'ź|rÜǧÚŘďż˙~–——Ç4 [˛d űío›”±Ś'ž×7•^[Ćâ{_§ÚŘă™ORměÓAó(ÍŁń˘y4±h%“ˇF„I688yóća۶mŘ»w/Ţxă ,Z´wŢy'žyć™QŹ­©©ÁŞU« ±cÇlßľµµµ¸č˘‹Đ××'ůŘ_xáŘl6<ôĐCx÷ÝwńňË/Ăăń`őęŐx˙ý÷Szě}}}xá…píµ×AúŘTűćÍ›ńňË/ăÉ'źÄŰożŤ+VছnÂ«Żľ*ůXĆëë›jŻ-űű:Çë|’ŠcźšGiŤÍىEóčĚ›G%—ěDwńĹł˘˘˘Q·]ýő,++‹9ťÎ‘ŰZZZJĄb?ü°ÔCdÝÝÝcnóz˝¬  €­]»vÔí©6öÓőőő1AŘÖ­[ŁŢźJcë­· c®Ô­[·ŽĺççłP($éxb1Ńë›JŻmD¬ďëTűxÎśOfŇاćQéĐ<šX4Ź&ßlťG…V@RÔ™őíÁ víÚ…-[¶ŚT€˘˘"¬^˝ŻżţşÔCDVVÖŰÔj5ŞŞŞĐŢŢ>r[*Žýtl‚4¨TűëŻżŽ´´4\ýőŁn˙ú׿ŽÎÎN|úé§’Ž'㽾©öÚFÄňľNŐ±Źçôůd¦Ť}:h•ÍŁ‰EóhňÍÖy4Q(IŚ1A8ĽôŇKŘ˝{7|đÁ‘űŕőzGuŽX¸p!ęëëá÷űĄrTřüóĎ1ţü‘ŰfĘŘŁIµ±9rsçÎ…L6úWwáÂ…€ŁGŹJ6–éJµ×v"gľŻS}ěÍ'©>öé y4ůcŹ&ŐĆNóhrĐŢ|rçťw¦üŘiĄy4Ńh•ÍŁ$ @D”““[nąE”c-_ľápmmmČËËCYY´ZmÔ+O‡FEET*Ő”źo:cßşuëČ×#Ź<2ćţTűd=öx-Z´Żľú*Âáđ¨ýˇ,X°@˛±LWŞ˝¶gšč}ťęc?Sd>immĹňĺËSzě4ŹŇ<šh4ŹJ‡ćQ2.i‹n‘XÝyçťLˇP°ľľľ‘ŰľôĄ/±ěěě¨%ß}ôŃd “}˙űßg‚ °Ç|ÂÇĄâŘ#z{{',™Jcß˝{7ýîwżuűĺ—_Î X8–t<±čőMĄ×öt±ĽŻSuěŃś9źĚ¤±Oͣҡy4±hMľŮ:Ź&  IvĎ=÷°ů—aoľů&űŕŘţđöµŻ}Ť ‚0¦ŽtMM KKKc—\r Ű˝{7Űąs'[°`+((ő+•m۶1A؆ Ř'ź|Â>ţřăQ_©IűOÍŁ4ŹĆ‹ćŃĢytćÍŁRŁ$É^zé%vÁ0“ÉÄär93™LlőęŐěż˙űżŁ>~ßľ}líÚµLŻ×3ŁŃČ6oŢĚ%5·jŐ*&“É cľd2ŮǧŇŘc¬¸¸xÔxO˙{KK˨ǦŇ؇‡‡Ůý÷ßĎrss™Z­fK–,s%/Äúú¦ŇkËX|ďëT{<óIŞŤ}:hĄy4^4Ź&ÍŁd2ct"„B!„Q^B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bd(!„B!„H†B!„Bdţ?äX=Ů• ľ˛IEND®B`‚Shapely-1.3.0/docs/images/buffer.png000066400000000000000000000452301226057120100172740ustar00rootroot00000000000000‰PNG  IHDRî,śŐ6čsBIT|d pHYsaa¨?§i IDATxśěÝYŚ$÷ç÷oŢGeVfÖ}t]]GwłIŠ˘Hq)i$ŤDig4y<ëő6lŻÝyÚď«/ö0ĆłŢ5`{˝€`1–fv¤‘H‰¤Ä!Šą¤D©›ÍîŞęşşŽ¬;łň¨ĽĂĹ${Z]ÝŐ•‘™ż@p@Ž"ţ쪌řfÄ?ţá2 Ă@DDDDDlÍmőDDDDDäáî""""" pq…»(ÜEDDDD@á.""""â wP¸‹8€Â]DDDDÄî""""" pq…»(ÜEDDDD@á.""""â wP¸‹8€Â]DDDDÄî""""" pq…»(ÜEDDDD@á.""""â wP¸‹8€Â]DDDDÄî""""" pq…»(ÜEDDDD@á.""""â wP¸‹8€Â]DDDDÄî""""" pq…»(ÜEDDDD@á.""""â wP¸‹8€Â]DDDDÄĽVŔJ5Ă ™*°ť*°ť.˛“.9®p\®R(Ő(UjVRÉĺ‚ ĎCČç&č÷Đń3Đ`0d8$Ńĺ·z"ňµZŤŇéôÇ Ęĺ2ĺr™JĄbőšÜn7^ŻżßŹßď'Ť‹ĹĹbôôô ­˘Ř”Ë0ŚŽjÓítëkinmf™ßĘp\Şŕő¸ xĽ>Ün7Ź·[7$äüŞŐ*µZŤjµJĄ\â¸P¤ţq델<áŇH”ÇÇct:ú;´-†Áţţ>ëëëlnn’L&?ŽsŻ×{rŽđx>>?č!çeĆÇç‡Z­F©T˘P(|üďăń8ŁŁŁŚŚŚ066†×«s„śčp?:.óîíC~ľ°Ďęn·ŰEWW‘H”H$B(Âëőârą¬Ş´1Ă0(•Jäóy2™ ą\–|ţŹŰĹăc1ž›íáÉń>Żb@¤•2™ ,,,N§ńxÄçóŇ?0H__ź®­łłłĂţţ>Ż›Ż=9Ŕ×?5„_WŕELµżżĎŰożÍúú:@€ÁÁAzzzBb[†aĎçI&“¤R)BˇO?ý4W®\Ń…ČÓVá^®Ôxĺ×ŰĽôË-Ü/Côőőé—ZĄT*±˝˝ÍŢî.±°Ź˙âóc|j"¦+€" *‹Ľűî»|đÁA†‡‡I$úl‰Ł ’É$űűűôôôđ…/|ˇˇ!«‡%-Ň6ᾼ“ăßľ¶Ě~¦ČŔŔ ĂĂĂşz"ŽV(X_żC:}Äă1ţŰ/M ů¬–#­®®ňĆoP.—f``@Á.Ž–Ëĺ¸sçą\ŽË—/óąĎ}N3 :€ăĂÝ0 ~tm‡˙đö:ápń‰IBˇŐĂ1…a¤R)ňąř§_ťbn$jő°DŁZ­ňÎ;ďpíÚ5b±ăăăřýZŽUÚaěíí±ľľNww7/Ľđ===VKšČŃá^,Wů~ĽĚµµ4zÚZÚV©Tbee™l&Ë>7ĘמÔŐB‘‡ČçóĽüňËěíí1::Ş«ěŇ¶ŽŹŹY^^¦T*ńĄ/}‰™™«‡$MâŘpĎ*ü«,°~P`rrŠxű¬î2µÇ=Ĺ9.ó§ßź'[4›»¤×KÇéďďÇëőňŢŇ2ĄĘ2ô”â]ä#©TŠ_|Ż×ËĚĚŚÖ“Žârą¸pá>źŹ÷ßźJĄÂóĎ?Żxo#Ž:ŰĘUţŐ9:®23;§h—Ž•H$¸8=͵µ4˙ćGËTŞ5«‡$bą\.Ç‹/ľŰíV´KGdllŚëׯółźý N®S8&Ük5˙űŐ%6 LĎĚęÖ§tĽX,¦xůHą\楗^˘\.+ÚE€Ĺ{rL¸˙đý$7ÖŹş8M8¶z8"¶ x9ńÓźţ”t:ÍĚĚŚ–{ůâ˝ý8"ܶ2üÍ»› ÓÝÝmőpDlEń.ťn~~žůůyĆÇÇő‘{(ŢŰ‹íĂ˝P:Y«=‰0<Ž÷Ű·ů7?ŇVĄ}†ÁűďżOww7]]]-Ü/äĘ*@ˇĺ*(wä<Ľnđ{ ę‡x¬84 pýúu˝aŐ!lîŰ©ﯤĐ/‘HďŇŽÖ××988`nn®%űŰÉÁü>¬¤ _ţ»˙Ng(9Ź»żđy\0…™L÷śD}«(ޝǖáţÖü>^݇žž«‡"âxŠwi77oŢ$‰Dšşź˝<ül¶2ŕ÷y‰'zŽF ř|>Ün·"GÎĄV«Q­V)‹är9Ňéo¬fůů<=WŔݢ_-Ĺ»łŘ.Ük†ÁŰ Äă Ím1‰â]ÚE©TbmmŤˇˇˇ¦ĹEÍ€÷6á—I\Ľ8J<WĚiÜn7n·źĎG$appb±H2™ägë{ĚŔ S ¶f<Šwç°Ý™űv2Ëa®¤«í"&Ó«Ň–——©V«M;G”«đň"Ľź„‘‘®y3jOOŻ©Ű1›â]Ŕfá~+7e‰/y8Ĺ»ŘÝńń1>źĎÔmÖ×ÉÖ*2âŠw±U¸ËU˝-UÄBŠw±«jµJ­VĂăńşÝcđűĽ¦!iĹ{góZ=€»Ë5"&”RÎC­jő(ĉĽđ8óîŃÇń~ű6˙ćGËüŃ Sx=úB-Ö*—˦_ÜÉ—Ńť^qśzĽ//-ńĘí4_ź†ńXkö=00Ŕőë×xţůçőlb Ů*ÜËŐš}®¸ÂŤo[= q*·f~˘ĂVŹä\ďb7•J0?ÜË5pąmtÁHäŚďťÉVáîő¸¨Őlrk>‡ŢK°ëäď=ÓVŹHś$ů+XüĚü®â]Äő)2fßš÷şÁĐťUq(Ĺ{ç±U¸|ű„»Ë_<ůż÷ç!:˝łÖŽIś#2‹/+ŢELRź^­šŮ!ď'ÓpDśHńŢYluú<¦”RŹ÷Ţ9Xyö¬‘8…Ű 3şOâ=łeőÎM¬Šx<\.óďĘ&BP,•?žŠ#âDz`µsŘ*Ü»C^ű]ůPĽËy)ŢELărą¦ź#†"'Ďd2¦nW¤ŐďťÁVá>R.­ĆoRĽËy)ŢEL‹Ĺ( ¦nł;prŐýđđŔÔíŠXAńŢţlî±…BÁž?lĹ»ś—â]ÄńxśbŃü‹;Wú ujʶEZMńŢŢlîA*Őšý¦ËÔ)ŢĺĽď" ‹ÇăMą¸s©ü^ŘÜÜ0u»"VQĽ·/[…űÔ``󹆊w9/Ĺ»HC©ŐjäóyS·ëóŔß…CR©”©Ű±Šâ˝=Ů*Ü»C>†âA˛Ů¬ŐCy0Ĺ»ś—â]äÜúűűńz˝Mą¸3×{˛„ŢęĘ2ÇÇǦo_Ä Š÷öăůă?ţă?¶zwK¦ ,%Źčď°÷Z .Ä& ”…­÷ Đ á^«G%NŕrCâ"d“°ýţÉšď¨ŐŁ:—`0H8ćÖĘëűÇ|z*ŽŰmăĎ­8šËĺbkk‹L&CoŻąÇ[— Ćşa%e°˝wH<žŔëµŐ«NDÎĹĺrŹÇ9Îs#Y¤/ ±`köÝŐŐ…×ëeqq‘R©Ä… ěÝv`»pxëÖ.ńxüănŘ–â]ÎKń.r.Ĺb‘Ű·oÓßߏŰmîMcŻ¦â°°_cw˙X<®x—¶ xo¶ ÷ľh€×?ŘĄj¸čîî¶z8§x—óRĽ‹<˛H$µk×đűýtuu™ľ}ꦰ¨x—6Łxo¶ w·ËĹA®ÄâĆ!ý6ź.S§x—óRĽ‹<źĎÇöö6‡‡‡ôőő5e~Ĺ»´)Ĺ»óą >-°˛›ăůë›\Ľx‘D"aőpÎÎ0`ő'°?“_†ŢY«G$NQ«ŔâËۆ™ß…č°Ő#:·t:ÍŇíŰ<1ăŹ^Âë±Ő3đŇn߾͏üc®\ąB8nÚ~˛%ř›[PĆÇěÜ%@ÓöŐ‰jµą\Ž\.GˇP T*R«V©Őśó »ŰíĆăőâ÷D"Âá°í´V«±Ľ´ÄŃQšŻOź<Ý*;;;Üąs‡ÇśçźŢöVvcËpřÓďÍł‘®réňegýPďr^Šw‘3©ŐjüĹ_ü>źŹ‹/6u_ŠwsŐj5Ňé4ĄÓÔ ŻâA ŕźCP®B± é" j€Çí&ŹÓŰŰK4µmĂ(ޝɶá~cý˙ýĄfggť1×ýnŠw9/Żșܸq7ß|“«WŻ 6÷^żâ˝qµZŤ˝˝=¶“IJĺ2˝aIŔh7ô„ fŐUk°›‡Ť#X8€Ł"„‚‡†ééé±eś*ŢťÇvsÜëú˘~~˝–f÷0Cooźł~ šó.çĄ9ď"g’H$¸yó&ÇÇÇMźR©9ďŤ9ůżČáÁ!Sń_™‚Ď ĂPÂľ“Sf;p» ⇑(\í‡Ń(ެm§8J§…Ăřý~«‡ůwhλóŘ6Ü].#‰Ż_Oâóůš˛z@S)ŢĺĽď"ĺv» …BÜĽy“h4Úô«ŕŠ÷GW«Ő¸sçëëëô‡«üÎ <Ö!›Żôl—ëdęĎlĎÉ]…Ít…őä¸\D"[ŞâÝYlî=?{GEćďěŇŰ×gúš˝M§x—óRĽ‹řŕăőÝďÍgK·oń–ůí)=ú(ď§SĽßźŁÂ ôry4ĘOoîJ‘°Ů/ů™)ŢĺĽď"§ŠFŁôöörăĆ Ĺ{‹¤Ói¶wvxá"t륲ŹLń~:Ĺűor\¸Ä»ü\Ťň–â]:•â]äTńx\ńŢB++ËôĘ<3bőHśKń~:ĹűßĺČpĹ»â]ätŠ÷ÖČçólnnńą1k™†(ŢO§x˙„cĂď"Šw‘Ó)Ţ›o{{›J!Ç'4·Ý Š÷Ó)ŢO8:ÜAń.˘x9ťâ˝ąÖď¬1Ń]e*aőHÚ‡âýtŠ÷6wPĽ‹(ŢEN§xoŽrąĚĆĆ&OBŻÖm7•âýtťďmî xQĽ‹śNńnľ\.ÇÁÁďÚă?ÉVď§ëäxo›pĹ»â]ätŠwsĄÓi˛™#ž» ůí͢x?]§Ć{[…;(ŢEď"§SĽ›çđđJyž´z$íMń~şNŚw—a†Őh†•Ýöâ^_™ŮY<ŹŐC:Ă€ŐźŔţźŹîînV7wřŕNšg.&đyí÷3Šë ńÓIŽŹŹ‰·h.¬é4ç]äTšó~~ą\Žl6ç†ĚÝnýsľ˛˛Âţţ>SSS¶ŰŰIş0iÎ>ď¦x?]»Ć{G…;(ŢíHńŢbŠw‘S)ŢĎÎĺr‘Íf8.–¸ÔÄÓŹâýÁď§kÇxď¸pĹ»)Ţ[Lń.r*ĹűنÁúNšË}'ăoĹű)ŢO×nńŢ‘áŠw;RĽ·â]äTŠ÷ł ěloă÷Ŕp“Š÷SĽź®ťâ˝cĂďv¤xo1Żȩďçv»)—ËÜŮĎóř4ű#§x0ĹűéÚ%Ţ;:ÜAńnGwÇűŤő#>;“°ĺ‹vďöswĽoóô”C&bŠ÷‡ $“;xÜÍżę^ß_=Ţšš˛ĺçÜ.ńžčé±U×Ř%Ţ+• .\hÍŽMÔńáŠw;ňů|DŁQV6¶YŮÉńětnďö  …B|¸ĽĹŃq…'Ć»ťů3ŰPĽ?×ëĄZ«±´ťc¦Zń2ěúç|yy™ăăcĆÇÇmů9·:Ţ?Ü©ÉfI$zlőçcuĽ{<đů| ¶fÇ&Q¸Dńn?~żźp¸‹ůŐ$»GE>=·Ő§Nńn?Á`źßĎŻ7qą\ĚŤ8óżCěCńţ`]]]ěěłuTc®÷äTÔlÁ`żßĎââ"###Íßé9XďC]đA˛D©T&Ź7}źŹÂĘxŹD"Ôj5nÝşEww7˝˝Îé$…ű]ďö|°´EĐďaz°I‹7Hńn?áp—ËĹ{ó›Śő†Š·čŚ mKń~:·ŰMWWw¶ö)Ua,ÖšýÖ?çóóóôööÚ.N묊÷hş|đáÖ1@€p8Üô}> +ă=ŤR*•¸yó&ăăă¶űł9ŤÂýŠwű …BÔj5Ţ›Oru¬›DW^ŃgĹ»ýD"ŽŹŹyoa‡ĎÎôjćzuŇď§óűýxĽ^·Žđy U×Yęźó……fffđűíyް*Ţ{CpT„Őť#z{űđxěu´*Ţ].ÝÝݤÓiVVV››łÝźÍý(ÜďCńn?‘H„ĚQš÷—÷ůüĄ>|6|XďvS?0ďîíł°uÄós˝¶|VBśEń~ş®®. Ăŕćf–ú»šżĎúç|ooŹÍÍMćććl{ܵ"Ţ]®“‡†oěË[Ţ•°2ŢŁŃ([[[d2¦¦¦šżÓ)ÜOˇx·—“W7ë[ŰJUoŃ}ŘsPĽŰ‹Űí&ÜŐĹâę‘ —©”„´=Ĺűé˘Ń(Őj•7s-‹÷úTťµµ5‚Á Íßé9Yď^÷É_óÉczzzl÷;ÖĹ»×ëĹçó±´´D?±}űî¤x·—“Ť‹k·“|j2N,ěłzH§RĽŰ‹ßď§\.smi—Ď_î%ŕł˙íP±?ĹűýŐŻ€·:ŢëźóĄĄ%.]ş„Ďgßs„ńŢ‚÷ \5lyŐ¬‹÷P(D6›ĺÎť;<öŘc¶n=…űC(Ţí%“J§XÝÎňąK˝¶ŽaĹ»˝D"¶wv8Ę—yjŇž'-qĹűýYď‘H„ťťňů<“““ÍßaZďnTj°ĽwĚŕŕ mĎGVÄ»Ëĺ"łąą‰Çăaxx¸ą;l€Âý ďöárą‚,®%™ěb UŹźź“âÝ>Ün7n·›–“<;ÝC$hźČgSĽßźń^˙ś///3==M0hďsD«ă=â‡kŰ'WCˇPÓöÓ(+âÝçóQ©TXYYáęŐ«¶}PUá~FŠwűđűýdŽŇ$r|ţRźŐĂy(Ĺ»}„B!ö÷)”Ę|JWÝĹDv‰÷x"a«ŕ°"ŢCˇűűű”J%Ű_u‡ÖĆ{Ŕ Ë)(VÝ$‰¦ěĂ,VÄ{8&™Lâ÷űjîÎÎIáţďöŕrąđz}ÜľłÍcŁÝôDěąô×Ýďöŕrą0 WwřüĄ^-)¦˛:ŢöjěÚó÷­Ś÷úç|ee…K—.ŮvyČ»µ2ŢÓHUpŔC[ďʇR©Äť;w¸zőŞ­>Gu ÷G¤x·‡@ @ęđ€\ˇÄg.ÚűŞAťâÝBˇ»;;xÝ..Źv[=i3VĆűŘGݏĎĺŹmůŠűVĆ{(bwwŻ×kŰ7ŞŢ«Uń^ŞÂÂ~ŤGôK«ă= ˛µµE,łĺUîç x·žËĺ˘Z«q{}—Ż>>€×¦ëşßKńn=·ŰMˇPdc'ÍWp柿ؚUńňť¬ňÁVŹÇC$bŻ7M·2ŢO>çvvvxüńÇó9oEĽ×Ś“Őe‰„#îF@kăÝëő’ÍfÉĺrĚÍÍ5g' P¸ź“âÝz>źŹäöÎG1ěŚWâÝÜn7ëÉ]ŹŮöMĽâlVĹ{,Ĺ*,%3ôööÚjľ;´6Ţ=[[[ŚŤŤŮîKĚ4;ŢÝ.řŐ6twwŰúŐ{µ2Ţkµëëë\ąrĹvËŠ*Ü x·–×ë%›É;.đܬýÇ{·żď…‚í:•CăÝď÷łż·‡Ç ŹŹŮűeâ\VĹű`nîCľP"‘čiúţŐ˝ń @3®˝řý~ö÷÷q»ÝŚŤŤ™ż&ş;Ţ Ă »ŰĽi}.ŕ—IĹb„ĂÎąčżďCĚßO `gg‡h4j»—y9°2íe˛ż‹ţ{łTʨV«Vé|\.ř"ôÎÁĘë°ż`őΤ;ca+KµfX=”G˛—)ňëµ4`Ďe©ŐjVéüÜ^ůűĐ5‹?€Ě–Ő#z(—ËEw,ĆŤő#«‡"mnrr’Ż}ík¤Ói–––0Ść«üxvS7}çárą¸pá˝˝˝Ľ±Íř(Ö_gż±±aţĆ›lźÍÍM˛Ů¬©Űvôݱż‹Íŕv»™şx‘®H”—á° żâ^Ż—H$˙–îě IDATÂúúşůoÂÝŠwëD"J•k{y«‡r&{™"ţ“UţÇż¸ÎŰ·S ŹŚrĺ1{>ąţHď‘H„dŞ@¶P±z(Ňć¬÷Ůű`{{»éű:/—ËĹÄÄŃh”/Cľlţ>˘Ń(‡‡‡ ó7ŢűűűĽňĘ+üŐ_ý[[[LLL>ĎşüŃu"'źwÜn7ÓÓÓxý~´tňb)łE"’ɤíľŕ8÷§f3Šwktuuáq»ąµ™±z(tż`żzőq†††l7őÜďŃčÉ”žĹ¤ąWłDî§ŐńîqĂcý:<°őůČĺr195EŐđđó&\ܬÎëWŻíę~Á~őęUúúúLź^UżVa§—uť‡Çăaęâ4©"üş ßO#‘Ĺb‘ĂĂCó7Ţ…»‰ď­çrąw…ąłoĎ+îěwsPĽűý~~Ë;9«‡"˘Őń>ÓŐšA:ťnę~ĺóůeńLžöŕ÷ű?žënG­ öşôG7&Lo±P(ÄŔŔ ď'?ůBb–®®“§¦wvvĚÝpî&SĽ·^ $™*Z=ŚżŁă‚ýnNŠ÷@Ý´˝~w¤˝µ2Ţ»ÂŃ‘ýźĺčííĹďór­ WN€íľĽXěu‡p»\ŽY ňa©.nî™»]ŹÇC °ÝçGáŢŠ÷Ö ě¤ ¶‡ÖŃÁ~7‡Ä{ `űHá.­ŐĘxŤB.kď©„p2gą·ŻźĄC¨š<_9JĄĚÝč9Yěu›čŠt9sâűđů|ÄâqĚß¶ßďW¸w Ĺ{ëJ• 2T°ß‡â=°§p ´*ŢűÂP(–±rU,Ł\]“g>2kżĽŘ!Řáä!ÎÍ DŁíőÖčx<Îá±ů8űý~ŰÝ­Q¸7‘â˝5ęŘ—Z˙ç«`›Ç»×ëĄP®RsŘr˘ŇZďőÔ‹ö˙‚‡q»]ý؉×ëĄ\.[rWÖ.Á^·š:‰wÇľ;äől™ý»ăóůl÷Ůqö#ĹPŹ÷?{qĹ…ffgťtőx‡“xčťµl8w«/iU,·îŠŇ^¦Č~™ä­[{xĽ^†GFéďďwć϶ŮęńľřňIĽĎü.D‡­đÉďN©Z#čÖĎNZŻﯾú*KKK\ĽxŃÔ  ôŇÇrąlű·dş\.‚GEs—n¬Î+•JËŢ‚ążżĎ{ď˝ÇĘĘ @€‰‰ z{{-źžňáDşş›ôĘQ‹ř|>Ü.™˘ą_ÎÜn7•Š˝– Ö÷¨Ç{6—ăý÷ß§T*Y=¤óą÷Ę{zÍę|Ë…róݏë ű9Őă=8‰÷c{,Żőq¸7c`‘3ŞÇ{*•âżř…©ÓZ|ťĺť0UŔăńböÍÓú±ą\nÂBń÷°Űö»íäN¦ÉôŰěM fpą\x˝ÓwÜn·ífK芻Čč {ňű°ő Čď‚?zň%Đę'ŇjUSeDäüěz…˝Î0ŕí m7MćnfÉ].—íľô*Ü[`e7Çź˝¸@¤«ËąSeŕ䓿úŘź‡É/ClÜę|üm8č3˙ĎUÁŢ z°§–O‚˝~ÇĆeŹ›}˙îřőó묬¬đꫯŹÇMź*ă´·dV«Ěţ8Ö?çÍ&c÷`Ż[<€­ ĚĚŚŮnlf0 JĄÚ”ßťVMŻ:+…{“ŐŁÝë ¶W´Űd~;|r 8ŕ3ďĤ`oÍ˝®Z­âr™ű»#ň(ęŃ‹ĹLŹvřd• »ĹÇý†AˇX¤»×ÜíÖĎfľ)Ô)Á)ÂOďś<‹Ĺ¬NS”Ëej†AĚäwJU«UŰ­wŻpo"E{kÔ ™đU[ÁŢ ‡{]µZ%ŕőŕ¶áÉVÚ_łŁśő–Ě|>O­f0Đeîv륚ńçë¤`‡“d^]—ÇÇř¸=î’7C6› ßäß…{Q´·N±XÄďu ž˙×YÁŢ ‡{]©T"Ţe˙+‘Ň~Zí{yüŽ*“N§ńąˇ?lîv‹Ĺ"Ńh´ˇm8-ŘáäEVŻÜ†‚‹ąąiSď8ŘM*•"úd%ł”J%zzzĚÝhÚ÷§h!E{k‹EbÁs@ě rh°× ÇĚőŰ{‰ öµI°ĂÉUšRąÂHBWÜĄ5Zíp˛’Çí˛]xÜO.—Ą? Mľ¸Y*•(•Jôöží“Ý0`á~şnŻŹąK3„Ă&Ď;˛™ăăcvv¶yz-{_ů|°ß[fî&Q´[#—ËQ­Ő¸4ň૦ öµQ°×0;±x$Ň ZíŐÜŘ…x˘ÇöóŰKĄŮlŽĎN™żíL&ŔČČçQ89ضłđÖ:ěć §§‡ńńń¶?żU«U–—n ŔSCćo?“Éŕ÷ű5Ç˝)Ú­“Ífń{ÝŚ÷Ý˙Ş‚‚˝Aměu™L†‘žÝ!=ś*ÍŐęh‡“+Żů2L6}_ŤJĄR¸€ń&¬TÉdH$Áűţűvö÷¶`ý¡ łłcm?5N–řĽ}{‘r©Čď_1˙ą8ůݵÝ_…{íÖ:J§™Žŕq˙ݬ‚˝Aměp2Ĺ*›9âéËöş’"íÇŠh/Uá?nB"'˛˙T°L&Ă`Ó_žc™L†ąąąßřwíěˇ`€©©‰„cĆßrąĚíŰ‹Žó|câ÷˙NÖjµJ.—ă©§ž2ă R¸7@Ńn­b±H&›ĺŮg&?ţg öµy°×ełYŠĄ2źšhĎ—‘=XíďnB±âbćÂXKöרă|Žń&L#Îfł”J%¦§§?ţg vç2 ÖďÜÁç®ňÍ9ó×mŻ;<<Ä0 [®}Żp?'E»őńz\|z2®`oT‡{Ýţţ>˝Ń3Cšß.ÍaU´ŻĄáú\¸0j»ÇÜO­VŁX*ÓÓ„űűűD"ěVżs˛ą±N.ĚTľ0͜帿żĎ… DěwŽP¸ź˘Ýz†ap°żÇXoo˙|]Á~^ěpr 4uxČď==Ô'=i=«˘ýđ^[†X¬›–ěłQĺrłßV­VIĄR\¸pW_}UÁî@ő`ßÚÜ$›ËŃß_™á&Żŕ[(Čfł|öłźmîŽÎIáţíö°łłĂqˇČrˇČúaQÁţ¨:0Řëööö¨5žoĆ‚ŃŇń¬Šöí,|÷&'§v•J0)żµµ5ŞŐ*««« v‡ą_°˙Ö \č†VüçďěěśślţÎÎAáţíö±ľľŔ訂ý‘tp°ĂÉmůťí$ĎĎöұ˙4q«˘=[:‰v€ÉÉ)GľÚŢĚ?Şú\h@Áî V;ś,Mş··Ç3ĎüiűC°˛˛ĚłÓ=üwż=©yíŇ0E{ó†Á­[7 yţÓËö ľ{ÝěCĂťěĎ Ű;Ř Ă`{{›ŤŤ ž~úižy櫇ôČ:>ÜíbK öGv÷ůł3=üă/OâqŰôě!ގhoťL&Ăüü<_ś€Ë6_JÁî¬`‡Oć´ďííńéOšgžyĆ‘?ŻŽwE»ŘŽ‚ý\jµkkkěďďó{OóűźväYěEŃŢz++ˤř‡ŹAÔ†˙Ů vç;ś, ĽĽĽL&“á·~ë·¸|ů˛ŐC:·Ž wE»ŘŠ‚ýÜňů<«+Ë‹Eţë/Nđüśs2űR´[ŁZ­răĆt{Ë|óxmrT°;3ŘŽŽŽX]]ŕ…^pÄZíŇ‘á®hŰP°ź[­Vcgg‡ÍÍMFAţÉW¦é Y=,iŠvkĺóynÝşÉx·Á ÁĘo vç{µZess“ťťFFFříßţmşşş¬VĂ:.Üíb ös3 T*ĹććĹB‘žä?yvźGvŇ8E»=¤R)–nßf"_ť‚VĽěÎ vĂ0ŘŰŰckk‹Z­ĆłĎ>ËO<Ń6?»Ž wE»XNÁŢL&ĂÖÖ&™L–+şůĎ˙Ţ]eÓ(Úí%•J±´t›.řÚĹÖĽUUÁîě`O§Ólnnr||ĚĚĚ źýěg‰D"VÍTîŠv±”‚˝!™L†äÖG™ Ł=!ţđłŁ<®—*‰‰íö”ÍfYş˝×UĺKĐ¬Ź˝‚ÝůÁľµµE>źgxxçž{Ž6y ď=:"Üíb{Cî öo>3§&bq2•ÖQ´Ű[©Tbuu…ŁŁ đěÄ‚ćl{'ďn*ŘŰ%Ř?ó™Ď022bőĐšŞíĂ]Ń.–P°7DÁ.­˘hwĂ0888`scťrąÂĹx¬†"Ź™Ő¬ĄáÚ$ł v»ł´u¸+ÚĄĺě Q°K+)Úť§V«±»»ËŢî…b‰.?ŚwĂpzC'Wâď]…¦\…tvs°™…µ”k‰t100H<ďcŚ‚˝=´m¸+ÚĄĄě Q°K«)ÚťÍ0 ˛Ů,‡‡‡dŽŇŠĄŹ˙ťß>Ź Ă€JÍ T=ůç. Ń‹“H$…:ăÁv{{iËpW´KË(آ`+(ÚŰOĄR!źĎS*•¨T*T«U\.n·źĎG  ăvwαYÁŢžÚ.ÜíŇ ö†(ŘĹ*Šviw ööÖVá®h—¦S°7DÁ.VR´K;S°w†¶ wE»4•‚˝! v±š˘]Ú•‚˝ł´E¸+ÚĄiě Q°‹(ÚĄ)Ř;“ăĂ]Ń.Mˇ`o‚]ěBŃ.íFÁŢŮîŠv1ť‚˝! v±E»´»€Ă]Ń.¦R°7DÁ.vŁh—vˇ`—»92ÜWwsüoŠv1‚˝! v±ŁŐŐU^yĺE»8š‚]îÇqáľť*đ'ß˝…ŰëgfvNŃ.çŁ`o‚]ějkk‹_|‘îînE»8’‚]ÄQážĘ•ř“ďޢPq3wé^Ż×ę!ťŹ˘Ý: ö†(ŘĹÎřîwżK0dff¦eoÉT´‹ěrŽ ÷rĄĆź|÷&»™ s—.ă÷ű­Ňů(Ú­ˇ`o‚]ěîřřżüËżÄĺr17׺»±Švi”‚]…c.Yëgël¸¤h—Gqo°O|QÁţî ö˙ęëÓ v±Ă0xíµ×¨T*\ąrEŃ.Žpż`˙­gűWľň{“9"Üß[:ä'î2>>N8¶z8çŁho-{Cěâ$ďż˙>ĚÎÎâóůZ˛OE»ś—‚]aűp?Ę—ůwo¬’H$čëëłz8çŁho{Cěâ4űűűĽűî» ŃÝÝÝ’}*Úĺ<ěbۇű_˝˝NŐ€ńńqgƢ˝5ě Q°‹†Á›oľI0lY<(ÚĺQ)ŘĹL¶÷Ĺd–ź/0>>îĚdíͧ`o‚]ślaaíímćććZň;«h—Gˇ`—f°m †Á˙÷Ö"]agN‘Q´7—‚˝! vqşJĄÂŰożM"‘ Ť6}Šv9+»4“mĂýĂŤ k{yfggťŠöćQ°7DÁ.íb~~žăăc.^ĽŘô})Úĺ,ěŇ ¶ ÷ü2IW8Ü’+)¦R´7‡‚˝! vi'µZŤ÷ßźD"A0lęľíň0 vi%[†űĘnŽů­LK_Wm E»ůě Q°K;Z^^&›ÍrĺĘ•¦îGŃ.˘`+Ř2Ü6żOŔď#Ź[=”łS´›KÁŢ»´ł[·n‰Dšú^E»śFÁ.V˛]¸Wk˙qńx˘×9‘ˇh7Ź‚˝! viwů|žŤŤ ĆĆĆš¶E»ÜŹ‚]ěŔvá~cý\±ÂxOŹŐC9E»9ě Q°K§XZZ ‘H4eű9E»ÜCÁ.vb»pż~'M0ŕ' Y=”‡S´7NÁŢ»tšµµ5˘ŃhSŢíQ¬ŔK‹P¬y™»ä¬h7 JĄBµZĹ0 Ün7^ŻŹÇcőĐKÁ.vd»pżą‘!í¶x(ÚŁ`o‚]:Q­V#™L288hú¶ ţv2%7s—ćlíĄR‰ŁŁ#2™ Çů…bĂřÍ˙?ź×C ¤«+B4Ą»ŰçW‹)ŘĹÎlîGÇe’©““CVĺÁíç§`o‚]:Ůîî.•JĄ)ËĎďĂZ¦§§l{Ç×0 ŮŰÝ%“ÍІ‹Q÷C—üp» RBŽŠUöŹslíçŘŢŢĆëq“čée`` éKi:Ť‚]śŔVᾼť°÷ÚíŠöóQ°7DÁ.ŰŰ۸ÝnÓW“)WáçĐÓ“°ĺjf†apppŔÖćĹR™á(<=“qśń,npp ‹5níﲻ»K"gtô‚íď.4›‚]śÄVáľť.ŕő¸ńů|VĺţíŹNÁŢ»Č'R©Á`Đôß˙[űPŞŔěȨ©Ű5CˇP`uu…l6Çdžž>ąĘţ¨\.č źüő™X؇÷¶RÜř ÍĐđ0CCCw\Q°‹Ů,Ü‹M9(›BŃţhě Q°‹ü¦T*Ő”«ĂîA<·Ý•çÖVWű ľ1{”fđşáJ?ĚôŔ/¶ ~µąÉŃQš‹§í{áĚD vq2[…{2UŔç·×P´? {Cě"§K§Ó¦Oe9*Âá1\¶ĎĆa°µµĹÖÖ3=đ…ń“ąëfóyŕą 0/ç¸yóCfffm;ÇżQ vi¶ ÷Łă ľ@óŢ„w.ŠöłQ°7DÁ.ň`†aP(Lż"ś ;E{]<3ďlěĐÓÓCWW—ŐCz »t[…{ŔçţřŞŠ-(ÚOŚY=GP°‹Ł>ťĹěpű tT2u›geÇhŻ{r`ýÎć.]˛ĺ1KÁ.ťČfáî±Ďw‘(ŘEĚĺńxp»Íż¸Ó‚RąBą\né\w;G;€ŰĎŤÂsd2ş»MZDŢ véd¶ ÷D—ŹíĽ5W>DĚ `ižP(ôńCŞfţhČŁŁ#z{{MÝöiěíucÝĐ‚íí¤-Â]Á.błpŠYOe­†Č#S°‹4_,#źĎ›şÍ°şŕŕ`ż%áî”h‡“~|ŢXÍP(–ŚCÁ.ň […ű`,ŔqaĂ0<â v‘ÖI$šľÝÇúáő• ů|žp¸y/tR´×M÷Ŕ۰˝˝ÍÄÄDK÷­`ůM¶ ÷ˇxZÍ X,ZöÍ^ä,ě"­ŹÇ) Ôj5S—žé÷¶`c}ť™Ů٦|Žťí^7<5oŻď100Đ’7Ş*ŘENg«pż8ÁdłY…»Ř’‚]Ä:CCC†A.—#Ťš¶]· >??\̰··GżąUíÔhŻ»ÚîÁĘň2—.7ďĄL v‘‡łU¸‡ü.ô…Éd2ôőőY=‘Ź)ŘE¬×ÓÓßď'“Éîă1¸Ň7ď¬ MŰľÓŁŔㆯNÁwnłşşÂä䔩Ç>»ČŮŮ*Ü®ŚFyăĂÍs[P°‹Ř‡Ëĺbdd„˝˝˝¦l˙s਋‹ \Ľ8M,ÖŘű*jµ«««86ÚëúÂđ•)řŃŇ!ŕbbb˘á+ď v‘Gg»pr<Ć+żÚ&›Íš~EEä¬ě"ö411ÁĘĘ ĄR żßoę¶=nřú4ühŮŕöâ"Ă## ťës_(XYYć8źç«S'y:ÝĹÄIĽżľr@±X`rrę\ÓZě"çç2 ðzw«˙ĂżżŽ'ÔÝň'Řť źĎł»»ËŘŘXÓćv˛{ý›ĎŚ(ŘEl¤T*ńçţç 144Ô”}Ô xo~™„P0ŔđČ(ńxüLÇrąĚöö6»;;„}/\üđCĆÇÇM€Ş“)ŘEśăŐW_e{{›Ë—/7ő3ş—‡ź­ĂVü>/ńDŃh”`0ĎçĂĺrQ«Ő(‹äóyŇéGGGx\đÄŔÉj,>OÓ†÷Ňé4‹‹‹ĚÍÍ5ő®uą ď'áÚTkĐ‹‹Ĺ‡ĂÜn7†aP.—9>>&›Í’:<¤T.3§‡ě"çaËpßNřßú€‰‰ =¤ú‘|>ĎÂÂ<ىŻ›őT…ËWSX6HÁ.â»óą\.žzę)^{í5rą]]­ą„ërť¨ť"ôŢh÷x<ĚĚĚđÎ;ďL&™śślŮXĽîŹćó;äŠú˝ěâ¶ś*S÷/_\`yżČ•+Źuä\÷űE{݇ëGüË—¸xń"‰DÂÂQ:¦Ä´—Z­Ć·ľő- Ă`¶Io;µ»űE{ÝŤ7xóÍ7ąrĺ ápŘÂQÚź¦Ä“Ř:Ü·ŹůźţňCĂ#÷zP´×ýë,˛¸s̕Ǯv䛳P°‹´Żµµ5~řĂ255ŐqwfípňĹćŰßţ6µZ­cżŘ<Ś‚]śČÖáđ—?_çµë;\yě*@Ŕęá´ÄY˘>ůb308Äččh‹Gio v‘ÎđňË/łµµĹcŹ=öńÚ®íuő/6“““ôöö¶x”öĄ`'ł}¸JUţĹ·> ć0;7×öáuÖhŻ{ń[|ďÝMć.]"‰´h”öĄ`é,™L†oűŰÄb±–Îç¶ĘYŁ˝îo˙öoYZZâĘ•+sńë4 vi¶w€…­ ú˝y††‡±z8Mó¨ŃP­üŻs‹­t™ËW:çŠÓ˝ě"ťk~~ž×_˝íŻ,?j´ĂÉ «ľýíoărąë€‹_÷Ł`—vâpxé[|÷ÝMfggŰr ÄóD{ÝîQ‘˙ů/oęŠrqzşŁĚ vxýő×Y\\äňĺË„B!«‡·­’w "IDATcşóD{ÝÖÖßűŢ÷`ll¬‰Ł´»´#Ç„{­fđݏČüV–ŮąKmő”|#Ń^wýNš˙㇋ô÷wĆYÁ."w+—Ë|ç;ß!—ËqéŇ%ü~­ŮŘ F˘˝®ľĘĚŘŘMĄ}(ŘĄť9&Ü ĺ*ú˝y’és—.·Ĺ|=3˘˝îŤ»üű7׸pá&ŽŇ>ě"rš\.Çwľójµsssx˝¶}UÉ™™íuo˝őׯ_oŰe„ěŇ î™ă2ňÝ[d‹Ó3łM+\3ełYnß^4%Úëţúť ~ř~’ŃŃQ†††LĄ=(ŘEä,R©ßýîwńz˝LOOăóů¬Ňą˛ĽĽlJ´ĂÉ‘Ż˝öËËËLNN¶Íš vé$Ž w€l‰?{qžĂ|•éé™–˝5ĎL©TŠ•ĺ%¦şřgż3CČoÎCĄ†ađý÷¶řţ/¶bddÄŃq«`‘Gµ··ÇK/˝ŔĚĚŚ#ďÎîî¶Ćôô4_ţň—M[x V«ńĆo°°°ŔÄÄ}}}¦l× véDŽ w€lˇÂżúÁ"ëÇLNNŹÇ­Ň™†ÁŢŢwî¬ń©‰8˙ä+SřĽćż<é•_%ů«·7H$LLL8nµ»4âččď˙ű‹E¦§§sÇ0 677I&“<ţřă<˙üó¦÷ ĂŕÍ7ßäĂ?dppŃŃQG[ěŇÉîĹr•űÚ2ż^M388ČČČ­ß Z­VY]]ĺđđ/_íç=?†ŰÝĽĺ{K‡üżŻŻŕóů™ş8íiE v1K>źçĺ—_fooŹŃŃQl},)•J¬¬¬ÉdxîąçxňÉ'›6^Ă0¸~ý:?˙ůωD"LMMŮ~Z‘‚]Äáá'ä_ŰáŻŢŢ 1>1iËĄŔ˛Ů,«++µ2˙Í'xfş5s 7Źů?_ąÍ~¦ĚđČmO\ vi†jµĘ;ďĽĂµk×ĹbŚŹŹŰnĹĂ0HĄR¬­­áóůxá…ZŁ[[[Ľúę«T«U.\¸@"‘°ÝqWÁ.ň LJ{ÝňNŽűÚ2ű™" ŰbzHą\f}}ť&ú»ř§_ť˘ż»µó- Ą*˙ᝠ޸±K¤+ĚŘř„m–ÓT°‹H+¬®®ňĆoP.—bppĐÇ™BˇŔť;w8::b||ś/}éK-żř”ĎçyóÍ7YYY!‹166f‹çě"ż©m \­ń꯶yń—[¸=^‡čëëłdúLĄRaww—ťí$~Ż‹đÜ>w©·…'ŠŰÉ,˙î'«$Sz †GF,™>cŮlVÁ."-U,y÷Ýwůŕ [v…ąT*±˝˝Íîî.]]]|îs˙{÷ňŰĆqŔqü§Ý%ą4—âC”,)?Ň(ne#hE(ŠŢúżöŇSÎnRA ˇ  (ěHŠl=HŠ\’»Úg2‰ (7•-Žôý\x%ç°óÝŮŮá´±±qĄ×Ŕ/^čńăÇ ‚@­VK«««WňtbúâŐ«W;đ®U¸Ouýsýőź?ę«ďű*µ–W´ĽĽüNÎôŤ˘HÇÇÇ:==‘ň\ź}ÜŇ_~».ĎťŹó„“4Ó—»]ýíë—Śc5 µ–—ĺyŢ[ź0˛,Sżß×Éń‘Ć“€`p%şÝ®žÔŁGŹććĚů8ŽŐét´˝˝­$I´´´¤V«őNžŇ¦iŞn·«““…aH°˙ŵ ÷©ăA¨Ď·ŹôĹnWYž«V«©ŃhŞ^Ż_ę*|’$:;;SŻ×•ďŹT*XúăŻWô§ß¬hńÖ|ľě§™ţľsŞĎ·ŹÔE*»%5—ZŞ×ë*•J—ŇyžË÷}ťťťipÖW'zđţ˘ţüđ¶>~ŻJ°¸2§§§zúô©ž?.˲TŻ×Ől6µ¸¸x©×¦8ŽŐëőÔëő4™LT.—µµµĄĚÝ~ű©(ŠÔétÔét†ˇ*•ŠšÍ‹ůó2żs–e‡ę÷ű ʲLwďŢŐÖÖÖµ˙‡Wŕ—¸Öá>5 b}ő}_˙ř®§NƲ¬y•Š*^Užç©\.Ëqś7şPçy®8Ž|ß×xäk4žH’>ZŻę÷6őɝƥťËţ¶ey®ď^ŽôxçT_?ď+IsąĄ˘Ľęâll\×}ăť,Ë4™L4Ź5Ź5ůŠăDőJAż»ŰЧ›-­5ćďĺa7—ďűzöě™vww5 d۶*•ŠŞŐ‹9ÂuÝ7^Ďó\Qi2™Č÷}ŤF#A ˲Ôn·u˙ţ}µŰíąYa˙9Y–iooO;;;ÚŰŰ“$•ËĺŮŘ”Ëĺ˙i±'MSM&ŤFŁ×sÄHišŞV«éŢ˝{ÚÜÜ”çyoó'F»áţSGPßěőíˇŻo}Q*IrlK®ëĘv ˛,K¶m˲,ĄiŞ,Ë”¦©Ň$V†Ę˛‹![,´ů^UżZó´Ő®©^™Ď•“7u§Ú}9Ň7űýk¨Óáą$iaA*»®lÇ‘m;ł›ś<Ď•çąŇ4UGŠ˘HQśH’{A­Š>\óôÉum,ßbuŔ\Ëó\ÝnWłłÔ“äő5Íq.ćŰžÍ ʲl6GÄq¬0 5ťV«ŐŞÖ××µľľ®v»=/|ţ?Â0Ôááˇö÷÷µżżŻÉäbŃʲ¬ŮŘ8Ž#۶gsÄt|˘čbŽŽgˇPĐĘĘŠÖÖÖtçÎ5Ť«üi€1n\¸˙T–ç:: u48ýĘQ¦0N%™JŽĄrŃ–[°T»UĐjÝŐJÍŐjÝU«ZĽÖ1:9OtŘőc/Đ«łPŁ0Ń(Lä‰Ň<—c-ȶTr,5«E5˝˘–Ľ˘Öe˝żT–cĎď™úđs¦ďĺ ‹í~ÎĎĎE‘â8Vš¦* *‹* ňąEŻ×‹~ż?t­ßďÇÜŃŢŚ'"‹ąŁŰďťî±_šńDÔÁĎ®âÎ{»ń˝mÎ^O_0áľĹââb\şt)ÖÖÖnüÂ7ţ'Ľ¶¶_űúJś:»Xń„ÔŐ©ł‹ńÜ Ă÷Îł˙đŤ¸ăOĹ˙\yłâ)Ąź]Ä_ľx9ćůL|ăźľ9ôŚXYY‰ĹE}Áx|Uć7żłú­ożoĽőNÜyŕ@|řŘqęěbľÇ§šíÍ×7âĹg–âĘĺŐčE Ę2ćŽöâż÷'qőµÇOŢz+>÷kGăţąĂUŹ Ŕ”ÝŚöµ˝ç=÷Üń¶ď¸łoÂ}„W~p-ž~ţŐ8~üxáě‰xöK´Ăîw`ĎÄ;°W˘vO¸ű"ŢÝí°7ÂŘ7ńŚK´ĂŢ w`"Ä;°Ńű#܉ďŔ(˘öO¸%Ţ[‰v áLśxní09wT=ąĽůúFĽřĚR\ąĽť˘AYĆÜŃ^ś:»‡ď9RőxÔČÍx_[»_|ţr|úW>űW«««QE”e˝^/ăČ{šH´Ăd wĆvíµ«ń•§NÇcŹžŚîÇĎDQ1 b}}=ľüäB1ßoĽŻóó«1±´´ä;îĐ ˘fK¸Ź Üagă;ĐL˘fĎU`×F]‰ěТŞ!ܱ v@´Cu„;°#ÁDv¨špFěŔM˘Ş'ÜŰv`+Ńő Üw vŕV˘ęC¸‚J´C˝wh1ÁŚ"Úˇ~„;´`¶#Úˇž„;´`v"Úˇľ„;´€`Ć!ڡބ;4`Ć%Úˇţ„;4`vC´CÂD°»%Ú!á Ř˝í‹p‡Ä;°W˘ňî`öC´CNÂěŔ~‰vČK¸C‚Ńą w¨1ÁLŠh‡ü„;Ô`&I´C3w¨ÁLšh‡ćîP‚ŃÍ"ܡB‚ŃÍ#ܡ‚&ŃÍ$Üa†;0m˘šK¸Ă v`D;4›p‡)ěŔ¬vh>áS ŘYíĐÂ&H°ł&Úˇ=„;L€`Ş Úˇ]„;ě`Ş"Úˇ}„;ě`Ş$Úˇť„;ě‚`Ş&Úˇ˝„;ŚA°u ڡ݄;lC°u!ÚáCv ND;!Üá=;P7˘¸I¸Cv žD;°•p§Ő;PW˘¸•p§•;Pg˘F¸Ó*‚¨;ŃŚ"ÜiÁd ÚíwM°Yv`'ÂťFě@&˘‡p§Q;ŤhĆ%ÜiÁd$ÚÝî¤&جD;°[Âť”;™höB¸“Š`˛íŔ^ wRě@v`?„;µ&ئíŔ~ wjI°M"ÚIîÔŠ`šF´“"Ü©Á4‘h&I¸S)Á4•h&M¸S Á4™h¦A¸3S‚h:ŃL‹pg&;Т&áÎT v -D;0mÂť©ě@›v`О,ËŞ‡¨“ŤŤŤXZZŠo}űĺxă­wâÎâĂÇŚSgăđ=GŞŻroľľ/>łW.ŻF§(bP–1w´÷îóą5ŘOźě@cÜ<#VWWŁ(Š(Ë2xŕ—cîcźŽ˝}P´S%Ü·¸zőjś>}:Nž<Ýn7Š˘Á`ëëëńÜ —â‰óË­Ž÷kŻ]ŤŻůą/ĹOďě@#Ť:#úëëń÷Ď˝ź}.>Ţ­zL Á„űçÎť‹C‡Ĺüüümkkkkńň÷7ăń'/T0Y=<{ţ\śřČčçó/ßýa|áüÓ‚h¤ťÎÍÍ͸pˇ˝g0}î¸o±şşgÎśşÖívăżů7qíÚµOU?üď—ă7?ţ;C׺ÝnĽôŇKń±_üĐŚ§ŤťÎ‹/Îx" m„űEQDQ ˙Ą¸ÓéÄőëďÄ«Żľ:ă©ęăúőw¶}>ŁÖš`§3Â;6áľEY–Q–ĺĐ—ď`0>ź˙­ăLVżţ×¶}>n]M¶ÓáL›pߢ×ëEżßz±ßďlj‡Ś{¬`˛z8ńĐŰ>ź^ŻWÁTł±ÓáL›?NÝbcc#â‘G‰n·ťNçĆúýXYY‰ĺĺĺ8r¤˝_•ń|€6óŞ&Üo1ě˝˝^/˝ĂóÚÍ;¨’p€:UěL¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wH@¸@Âî€p€„;$ Ü á wHŕ˙iąÁÂÝď0IEND®B`‚Shapely-1.3.0/docs/images/simplify.png000066400000000000000000000466531226057120100176710ustar00rootroot00000000000000‰PNG  IHDRî,śŐ6čsBIT|d pHYsaa¨?§i IDATxśěÝisŐľ6üKó`ÍRËŽ‡xvHL€°™vÎ>;! ©SużyŢßźčţ"Ď›»ęěť°‹löN'Äłc[±Ôšg©ĄîçE#ÇrâAR·¤ëW傸ířʱW_Zý_kEQ@DDDDDşfÔş"""""z9w""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨0¸őw""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨0¸őw""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨0¸őw""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨0¸őw""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨0¸őw""""˘ŔŕNDDDDÔ܉z;Q`p'""""ę îDDDDD=€Áť¨µ.€č0’$!›Í˘R©@’¤–o•Ş„­´ŚťśĂCuĚř»Í‹Ąő›ÍfÇăŐjŐú?ŹNˇZ­ľô!I…:§,¸¬Âă<üţđě=Âb±hýźGÔ’AQEë"hpɲŚ\.‡L&t:˝ďźĹb±ĺçL&ÔŤ6Ä• öęT3lV+*Ő*Ěæ$†8,rőz˝ĺßa·ŰáőzáóůöýÓăńŔd2uň?™Ž¨V«!›Í"“É4ß÷rąÜňsL&Só­ ;~.OBRLp«xÍľł"ˇ^Ż7ßZq:ť-ďn·F#›H; îÔ5Š˘ “É ‰ ‰ Ź#—ˡń#h4a·ŰałŮ`łŮš˙n±X`4a4š-đH4`= `@ „ p:ť(—ËÇăHÄEÔę2Ć=Ŕ˘ `Ě­@‘ëeµZ •Jĺr•JĄůďĎŢ.— Á`gÎśÁčč(j"˘“eÉd‘HOź>E"‘@>źo^7™L-ďfłFŁ&“ .˙ő€Ů†‰ł“ŘX_Çą†˙\żO¨+ŠEQPŻ«÷I’ZŢ#dY ¸Ýn„B!ŚŽŽbtt^Ż·ů5‰:ŤÁť:ćů ‰DP.—a0044§ÓŮxív;,KËÁŻZV“ŔR H•»ÍŠF0„Ů|°Ű«1řÇŠņ¬Ŕ˘ś ţ1X?_g­VkÔĺrĹb…B˛,Ăb±4č3gÎ  r&":%EQH$š÷‡§OźB’$ŤĆ–÷łŮ|ä±÷ŮĐ>żp‹ĺrËŹďG©S’¤–÷EQ`·Ű166Öśěa§Nbp§¶*•JŘÜÜD$Áîîîľ îrąšoGiGI–€‡"°śę2ŕőů Ün÷‘ĹBˇQ‘J&(ń`xxŮ_!Ë2 …rąňů|3Č[­Öć=== —Ëu¤Z]>źÇĆĆF3¨W«ŐfPwą\p»Ý:ŐSÎVˇ˝á¤á˝•z˝Ž|>ß|{>ČŹŽŽbjj ‡ăä_„č9 îtjµZ ›››XYYÁÎε?°15¨j@ßLK"°—,f3B‚€P(tŞĄµZ ‰Dq1†rĄŠ€Cť…ź –#¶´äGFF0??Ź™™Řl¶×HDÔŹ*• Ö××±˛˛‚˝˝˝¶őg˝(´7´3Ľ?«ä÷Ć:­ńńqĚĎĎcjjŞĺSb˘ă`p§‘e‘H+++ŘŘŘ@­VËĺ‚ßď‡ßď?öŠü|x$Źâ@ą¸].á0|>_[9*Š‚l6‹¸("ťÉŔb‚ŔbđŮŹ÷wŐëu¤Ói$“IdłYŤFś={sss8{ö,h"XµZ Ož<Áęę*žź‡ŮlĆôô4ćçç1::ʵSt" îtdŠ˘ Źcuu«««(•J°ŰíÇžmV`7§Î®oĄ“ŃŘ\lÚŤG‹•JĄąUŞŐqĆ­ÎÂOůă1_+H’„d2‰d2‰b±‹Ĺ‚™™ĚĎĎăĚ™3ěw$˘ľ§( ž>}Š••¬ŻŻC’$8ťÎć=˘“[,'´7t#Ľ7T*$ ¤R)”Ëe8ĚÍÍannˇP÷:2wz)EQ°µµ…ű÷ďCEX,řý~8ťÎc8•đ8ˇöŻg+€Ăa‡ „4ŮŠQ–e¤Óib ů| p!Ľ†NĐťS.—›tĄR×ëĹoĽůůyΰQß‘e+++řé§źÉd`łŮŕ÷ű a·óQć ś$´7t3Ľęý´X,"™L"•JA’$‚€K—.arr’ž^ŠÁť%Ë2VWWńÓO?!ťNĂĺraxxřÄ+ćĹ‚ÖW“€ Ŕçó#chhH7U±X„(ŠH&PdS>µŤćŚëĺ‹Yź§( ňůÂá0\.W×ĆôÓ„ö†n‡÷†ĆÎkŃhů|>ź—.]Âěě,'yčP ît@­VĂăÇŹńóĎ?#źĎĂëőbddäD»§Ôd`=Ąnĺ(«ĹŇ\lŞç“éęőzs1k©\×®¶Ń,ë  ”J%ěíí!•JÁjµââĹ‹X\\äbV"ę9•JKKKxđŕŞŐ*ü~?FFFşľ{J;B{Vá˝!źĎcoo™L.— Żżţ:Îť;ÇI:€ÁťšŞŐ*>|_~ůĺrą9;ťÎc˙]ŮĘ‹M«uŔăqCÂ=·żmcÖ\cH§Ň0ů€âÇ˙¶ R© Ť"‘HŔh4bqq/^<Ń÷¨›ŠĹ"~ůĺ<|ř˛,# bxxX“ v†ö­Ă; ~Ź“._ľŚŃŃQí "Í1¸¨Bˇ€{÷îamm .— Çj×P úűbÓőŕ †††:V·Ţ”Ëe˘D"Žz]ĆYŻz2ë„çx‹Y+• vvvN§1::ŠË—/Ăçóu®p"˘H§ÓřňË/‰Dŕóů0>>®ůšśn„ö=…w@mˇŮŢŢF>źÇěě,Ţ{コ×ŇÜLŁ-ćűᅦÁ`ŔŘŘŔ‘gxĄşş+Ě’$K€ÝfEH# ô"šz˝ŽT*1E±T†ËŞ¶Ńś öc|[2™ ¶··Q­VńÚkݱ}†şJ’$üđĂxđŕ¬V+&&&ŕőzµ.««ˇ˝Aoá]Q$ D"(Š‚·Ţz‹í3Á}€<ß3::zä°ť*©łëË @’ź× !†Űíf[Ç3EAˇP€(ŠHĄ’0ý}1«ŕ<Ú,Ľ,ËFŁŘŰŰcű u…˘(X__Ç˙üĎ˙ \.cddĂĂĂş…Z„ö˝…w@m±ŚD"lźP î@’$|őŐWX^^>V[ڬ›iuvýi°M†‚ŔîG IRsKÉJUBĐ©řą`>½đŮö™ńńqüőŻĺî3DÔvĹbwďŢĹîî®nÚb´ í z ďŔţö™……üůĎćÚŔŕŢç‰nßľŤ\.‡‰‰ Á—ÎÜŞŔoqŕa\]xęr AÂđů|ş}é5Š˘ ›ÍBcČd˛°€sAµŢw„Ív2™ ¶¶¶`2™pőęUŚŹŹwľh";;;¸sçęő:&''uŃÓ ‡ĐŢ ×đŢhźŮŢކŰíƵk× µ.‹:Á˝O)Š‚GŹá믿†ÝnÇôôô ·dT ’SŰa6Ó€Áh@ „ śĺmŁJĄ˘.fŤÇQ«×1ćVOf=ëŚ/x=%I677‘ÍfqéŇ%üéOâ‹(":1Y–ńý÷ßă§ź~‚ÇăÁÔÔ”®fkőÚô޵¶ŤŤ ”ËeĽ˙ţű8ţ<Ű+ű{ŞV«řâ‹/°±±A0>>~hČ«ÖŐľő%Č”‡ÝÖ\lj2ťŕP:Y–‘JĄcČŠpZÔřWB€ó›˘(ŘŰŰC$Áđđ0>řŕťfKD-źĎăóĎ?G,Ă™3g022˘«§ÇĐŢ çđ.Ë2vvv Š"¦§§ńď˙ţďlkíC î}&‹áöíŰ(•Jśś„ßďoůqń˘:»ľ’dđů}„0\.—®đAP,!Š"’ÉYÁ´_í…qµ^ĚšËĺ°ąą Á€+W®ŕěŮłÝ/šzŇÖÖţůĎBQLOOëîĹżžC{žĂ;¤R)lmmÁápŕÚµk‡ĂZ—DmÄŕŢ'EÁđÍ7ßŔétbzzúŔ⢺¬îąľ$±`µÂ…BşM­Vk.f-WŞđŮŐ?¬¦»ąą‰L&‹/âťwŢá":T˝^Ç·ß~‹ŔëőbjjJw[řöBhoĐ{xŻT*ŘŘŘ@±XĻヒ‹/rR®O0¸÷z˝Ž»wďb}}ápcccűZcrŕQ\}«ÔŹŰŤ ŔçóńY‡EA.—(ŠČ¤Ó0Őđľ(ÇţŹ‹ĹbŘÝÝE8ĆǬ›ť H?*• >ýôSÄb1ŚŤŤ!ëněďĄĐŢ ÷đ.Ë2vww‹Ĺ033+W®p‚§0¸÷¸jµŠüăFŁššj¶Ć( °ťUŰažd“É`0A^¸H•ôĄZ­"Ź#.Šj5 »Ô?íLżż6ËçóX[[ŰíĆőë×yš5ĺóyÜĽyłyâ¦ŢZc€Ţ í zď€Ú:łąą‰ááa|ôŃGě{ďq î=¬X,âÖ­[H§Óťť…ŰíFą<Ž«í0ů*ŕt8 „Ăđűý|ĄÝĂEA:ť†‹!—ĎĂn·€óಥR «««°X,¸qă|>źÖ%‘ĆR©nŢĽ I’0??ŻËI›^í ˝ŢsąÖÖÖŕóůđÉ'źp·¸ĆŕŢŁ˛Ů,ţö·żˇR©`vv8±ÖR`€ĎďG8†ÓéÔÝ#Q:ťR©¤.fM$P—eLzŐ-%[kk«eź|ň $ °h4Š[·nÁd2annN—ł¬ýÚz!Ľ‹E¬®®Ân·ăĆŤđxűě38ĚÎÎęň~ĐOˇ˝ˇÂ{ĄRÁęę*ŕúőë…BWDÇĹŕŢcvwwń?˝‹¸a˘€TĽ^! ŹÇĂŮő¤( …D1†T*#Áś…_ÚĹőżľ……­K$˘.Y^^Ć_|Ż×‹ééi]ÔÖŹˇ˝ˇ»$IX[[CĄRÁG}„±±1­K˘c`pď!_üđűń)˛Šfł ˇ€P(ÄťD¨I’$Äăq$â"*U Nńď nüŻżľˇuiDÔa?˙ü3ľůćALNNęr"§źC{C/„÷z˝Žőőuäóy\˝z333Z—DGÄŕŢ#V×·đnÇ`u81<<żßŻË™ŇEQÉd‹F‘Ëçđżß˛ă˙yóU­Ë"˘YZZÂW_}…‘‘ŚŽŽ2´k¬»,ËŘÜÜD:ťĆG}ÄÖĘÁäעŃ(ţżĎDFĚÎÎ! 2´Ó  ř|>ĚÍĎĂd4áÖ÷[X__׺,"ę€őőu|őŐW‡Ă í:a·Ű±pî 53ţk(IZWtŃhÄôô4Ľ^/>űě3DŁQ­K˘#`úÓ9u;Ż[ Ăđy˝l‹ˇc1Ť†BH¸ýů]D"­K"˘6ŠD"¸sçĆÇÇÚu¤»Á`Ŕôô4nÝş…T*ĄuIô î:Ö88Łhpˇ Ű­K˘$$Ţm˙řÇ?ŹÇµ.‰Ú ŹăÓO?…ËĺbO»NőBx7Ťťť…ÉdjÖEúĹŕ®SĺrąypFŢyv›•{®Ň‰ŘívxÜnÄŤ#°Z­¸yó&˛Ů¬ÖeŃ)dłYÜĽy6› 333şlźôĐŢĐ áÝl6cnn’$áćÍ›¨T*Z—D‡Đßo:ˇV«áÓO?E>źÇÄô<63&„„°.gS¨7á0Ä"ŕťüýďG±XÔ¸*":‰b±ż˙ýďĐś)Ő†öýz!Ľ[­VĚĎĎ#źĎăÓO?E­VÓş$jÁ]gdYĆíŰ·ŹÇ177‡ÍĽ€Á`PëҨ‡y˝^X-f,§,››Cą\Ć­[·P­Vµ.ŤŽˇZ­âÖ­[(—Ë››Óe fho­»ÝnÇÜÜDQÄíŰ·!˲Ö%ŃsÜuć›oľÁöö6fffŕpáˇř]ž|G˝Ă`0 $„±’`˛annétwďŢw„%ę Š˘ŕÎť;H§Ó››Óĺf í/Ö á}hh333ŘŢŢĆ7ß|Łu9ôwŮÚÚÂ066Ż×‹ť,ŻŞ‹ ‰N+ A–•$ŕt:155…­­-,--i]ÁŻżţŠ'Ož`jj N§Sër`h?š^ď^Żcccxđŕ¶¶¶´.‡žÁŕ®ů|wďŢ…ĎçC8,Ĺ€!§CCCWGýŔb±Ŕç÷c)( š?k÷îÝ(ŠZ—GD/ Š"îÝ»‡p8 źĎ§u90´O/„÷p8 Ż×‹»wďr§ap×Y–ńůçź@sKŻlŘÎ!!¬quÔOA@¦DręźÇĆĆŕp8đŮgź±ßťH§ŞŐ*>űě38ťNŚŤŤi]Î í'Ł÷đn0055řüóĎŮď® î:đý÷ß#‹azzşŮËţHĚ&#€ĆŐQ?qą\pŘmXú}‚˝qr^©TÂżţő/ö»錢(ř׿ţ…R©„ééiÝműČĐ~:zďfłÓÓÓĹbřţűďµ.‡ŔஹťťüôÓO…ËĺÔdŕ·8†t7HSok,RÝJ«ë'Ŕfłarrëëëří·ß´-öyôčÖ××199©»Ĺ¨ ííˇ÷đîrąpćĚüôÓOŘŮŮŃşśÇT¨ˇb±;wîŔăń`xx¸ůţőP©sQ*uF0„ŃhŔoĎ ę÷ű …đő×_#‘HhW5% |ýő×~ż_ëröaho/˝‡÷‘‘x<Üąs‡g€hŚÁ]#Ťľöz˝Ž©©©}‡+-‰€Çă†Ýn×°BęW&“ `ŹD@~¦3fbb6› ·o߆$éě®A4`$IÂíŰ·ałŮ0>>®u9ű0´w†žĂ{Łß˝^ŻăÎť;ěw×»F>|§Oźbjjjß 'Ô7‹R©A@©l¦˙x_Łß=—Ëá»ďľÓ®8"Âwß}‡\.‡™™]µL2´w–žĂ»ĹbÁÔÔ"‘>|¨u9K?ŁÁ)‹řî»ď …ŕńxö]{(V‹^ŻWŁęh8¸\CXŠíżÝnÇ™3g°´´„d2©MqD.‘Hŕ×_Ĺ™3gtő䕡˝;ôŢ=Bˇľűî;”J%­ËH îřöŰoˇ(Ęm˝*5`5 „a_ë Q'BOó@ęą±7Ăfłáż˙űżąË Q—)Š‚/żü‡Ły¦‡0´w—žĂűŘŘEᩪapﲽ˝=,//ctt´ąőcĂrˇžpIÔi>źł ź;{Éh4bbbŃh«««ÚG4 VVVŤF1>>®›†vmč5Ľ›ÍfŚŽŽbyyŃhTërŽ>F…!Ë2ľüňK 犢.Jőůü©+ŚF#‚!Ź€TßÍăńŔď÷ăŢ˝{<‰¨KŞŐ*îÝ»żß ŤR+ íÚŇkx…Bp:ťřňË/ąPµËÜ»čŃŁGH&“8Đ ł›˛nIÝ%j2°Ň˘ť}||•J…‡nuÉ÷ߏjµŞ›]dÚőAŹáÝ`0ŕěŮłH$xôč‘Öĺ ÷.)•JřöŰo …044tŕúCpŘíÍCşÁjµÂçőbITźú<Ť U‰ş#‘H`ii gÎśŐjŐş†vťŃcxotpˇjw1¸wÉ7ß|ÓrA* ž`ą™„p‹R©ë„p©-ĽĆ…ŞDť×XjłŮt± •ˇ]źôŢÇĆĆ Ë2ľýö[­K î]‹Ĺ] żĹ“Ń€@  Au4čÜn7ě6+–Äמ]¨ş¶¶ÖýâŔÚÚ˘Ń(&&&4_ĘĐ®oz ďŤ…ŞŹ?F,{ů'Đ©1¸wÁŹ?ţ»ÝŢr·ş <@0“ɤAu4č BB©Ö7ŹÇŻ×‹ü‘łîDm¦( ~üńGx˝^ͤ2´÷˝…÷P(»ÝŽüQŰB{‡%“I22QńôéÓîFÔ§"‘DQÔt¶ťˇ˝·é%ĽŤF cmm ŮlV›"{ýüóϰX,‡ž„úP,f|>_—+#:hhhCNgËEŞ€Úëît:q˙ţýîFÔ§îßż§Ó©Yo;C{ĐKx…Ôµz?˙üł6 ÷)‹xüř1AhąK@µ,'€`¨őu"-á0v˛@¦|đZŁŹqww˘xHş'˘#E‘HäĐ'˛ťĆĐŢ_ôŢŤF#Âá0?~Śb±Řýc‡_ËŮtYQ÷n÷-­é…Á`@0$`- ”é†ńűýŘŢŢFąÜbďH": \.cgg§kłí íhŢ ü~?VVV Ë-v: cpo٧Oź˘T*:›ţ$$ ć˘TŇżP(ęy­(Š‚őőő®ÖEÔ«Ö×ס(JW¶€dh§giŢÁ JĄOŰn3÷6ZYYÝn‡Óélyýˇ 9˝N¤'‹~żK˘ş…i«ën·›ŹB‰Žheeʧă!šˇťZévxw:ť°ŰíĽG´{›Ôj5¬ŻŻĂď÷·l“É”ť,·€¤Ţ"aä*Ŕn®őő@ €h4Š\î "@.—C4ířl;C;˝H7Ă{Ł]f}}ť;µ{›lmm˝p§€‡"`659%Źč¤†††ŕtرk}ÝçóÁh4buuµ»…őŐŐUL&ř|ľŽ} †v:Šn†÷@ €Z­ĆČÚGĂ§Ő IDATÁ˝MVVVÝ) &Ź@0$tuß^˘Ó2  ale€|őŕőFáŁP˘[YY×ë…ÉdęČßĎĐNÇŃ­đŢŘlyyą3_`1E¶,ËŘÝÝ=t&e- TëꉔD˝&Ŕd4âŃ![Cú|>¤ÓiäóůîFÔ#ňů<ŇétÇfŰÚé$şŢ}>"‘w—i÷6EőzýĐ“P—DŔëńŔfłuą2˘Ó3™Lxę-ĆÝĆĎ=w j-‰@GNËfh§ÓčFxw»Ý¨ŐjĹCfčXÜŰ ‰Ŕd2µÜ-&VâE ÄŮvęa‚  \SOý}žŮl†Óél†"Ú/‰Ŕét¶ýü†vj‡N‡w§Ó “ÉÄÉť6apoH$—ËŐr7™‡"`łZŕőz5¨Ś¨=Ü.–™0qą\ŘÝÝínQD=˘qŹh'†vj§N†wÁ—ËĹÉť6ap?Ąz˝Ž˝˝˝–rą¦ö·‡„pËPOÔK„pŃ<,ĽćrąĎçŮçNôś\.‡|>ßÖ6†vę„N†w—Ë…˝˝=öą·ű)˝¨ż}9ČŔˇ'©őźĎ‹ŮÜrkČĆĎ?gTök´´kĆťˇť:©Sáť}îíĂŕ~JOź>mŮß®(ę˘TżßĎ•ú‚ş5¤€•ßwIzű܉Zkg;C;uC'Â{ŁĎť÷Ócp?ĄĂúŰw˛@®Â“R©ż„B!Ôe`%qđ{‰jW;C;uS»Ă;űÜۇÁý^Ôßľ$N‡zđQż°Z­đú|XŐ§JĎjôąçr9mŠ#Ň™vő·3´“ÚŢŮçŢ î§H$Zö·ç*Ŕ“ ĄRé2đôąu¨Ťßh4ŞAUDúÓř]8ÍŚ;C;i©ťáÝĺrˇ^Ż#Ź·ŻŔÄŕ~ é´ş©µÝnß÷ţßâ€ÉhD Т,˘Žr»Ý°ŰlxřÜ#łŮ ‹Ĺ‚L&ŁMaD:“N§aµZOÜßÎĐNzĐ®đîp8€÷Sbp?…L&«Ő “ÉÔ|_]Ĺ@0¸ďýDýÂ`0@‡±‘ŠĎ ŕv»˝ů‚–hĐe2™źÍĐNzŇŽđn2™`µZÜO‰ÁýZ Ęiu˙v'ĄR 0 říą'ž6›ŤÁťčwétúDÁťˇťô¨áÝfł1¸źű)´”—DŔív5 ő#łŮŚ@ ‡" ?łHµ1(+ĎŻ\%0Š˘śhĆťˇťôě´áť“;§Çŕ~BŠ˘ ›ÍîëoOhž[@Ň`E Řzf ¶Űí¨Őj(•ZŻJ4@JĄjµÚ5P/ÂĐN˝ŕ4áť“;§Çŕ~BĹbµZmßlĘC°XĚđů|VFÔN§®!'–žY¤Úř}ŕŁPt‡m^pčÇ3´S9ixçäÎé1¸źP#4ĺjXIˇŔ- i`„„0"95t îD Ťß«ŐúŇŹeh§^t’đ޸G°]ćäÜOčůAy%ˇî( …´,‹¨«ü~?ĚfSskHŁŃČĹGDPďv»Fă‹oł íÔËŽŢ9ąsz î'ôě ¬(ę˘TŻĎw¤Ů˘~a4 †đ8Huő}\|DôÇvÁ/ÂĐNýŕ8áÝh4Ân·3¸źű ĺóůć ű4ŻŔÜ’‘ ęŔZJýłŐjE>źń'őą\.÷ÂŕÎĐNýä8áÝb± P(tݏ>Ăŕ~B’$5Xz(v›­yä;Ń ±Ůlđz=XŠŠ˘˛!I§8›¨<{ŹxC;őŁŁ†wŁŃjµÚÝâúű U«UŤF%`#á0ĄŇŔ„0%@,Ş2; :I’Zö·3´S?;JxçäÎé0¸źPc6ĺ·8`0´.‰H3Ź6«K1ĘDP«Ő̸3´Ó xYxçŚűé0¸ź$I€Á‡"a6›µ.‰H3!!ڵ )&Ôj5°AKQÔjµ}3î í4H^Ţ9ąs: î'$IâŇŠĄŤ­P Ř.:¨3ŽD¨J3î í4 ďl§<÷ŞŐjŘ,Á5ä„ÓéÔş"Í™Ífřü~¬ĺěPĚ4°/ZŤF#C; ´VáÝd2qbçÜO@Qäk&Ä+V„„°Öĺé† (ÖŚČÂĂŕN«Ńż[¨[Úiŕ=ŢŮNy: î' ID0›LđűýZ—C¤CCCp:ěfp§U«ŐP† źď8Ú‰°?Ľ˙wĚ fÎşźű ”Ę$  ˝ô8k˘Ab0†˙ýë®Öĺi"•+á1^Álgh'ú]#Ľç$~ÁëX~"j]RObę$˘Žŕ©DDt(ž}s" î'ŕ°Ű„D<Y–µ.‡H7EA2‡\~uLër4áw;pżA©•±˛ümcDĘĺ2–?†ŰRÇkřóăA­KęI î'`±X @D­^G*•Ňş"Ý( (–Ęc{ ,łŮ ;*ř`ĽÔ* ď4đˇ}Č\Ăż…S° Ć{Ä 1¸ź€Á`€Ë\GČVE\Śi]‘n˘§Y†YĘ4°¬V+`Č$á?ĎáťÚłˇý?‹ˇłŮ [eN„Áý„Ěf3¦śä E‹E­Ë!Ň\­VC*•Ĭ» ŔŕN«q’¶,ËđŮÁđNëůĐî°őzť§Íźű Y,„,8-ę,#Ń ‹Çă0pŞ/d90Ó jĽh­×ëŔđN©UhÔ´śŘ99÷˛X,€"ă‚$“ îGJMQÄĹfý| Jd0`6›÷m^ŔđNä°Đ¨/hÜOŽÁý„, ęő:^ Ь ™Lj]‘f˛Ů,*U ‹aĘD€úÄ©1ăŢŔđNŕEˇPgÜë@čřÜOČjµB–e8-Ŕ´c1ßKKc:Á©Ęl“ˇAg±XZnĚđNýěeˇŕäÎi1¸źPcĆ.@ąRA.—Ó¸*˘î«T*Čd˛XÔó4ęő:gShŕ={ŹxĂ;őŁŁ„v€3î§Ĺŕ~B.—«9Řžq©1©Ň E0P˙\­Várą´-ŠHcn·ŐjőĐë ďÔOŽÚ@’$ uݏ>Ăŕ~B^Żĺr˛,Ă` “Nżp &ę7˛,#‘ă\0˙>šT*ř|>m #Ň×ë}éý€áťúÁqB»,Ë(—Ëđz˝Ý+°Ď0¸źP㇮10Ď“QÝŹhP¤R)Ôju\Ô?˲ŚJĄÂA™Ţł“;/ÂđN˝ě8ˇP'vđq î'Ôřˇ+—Ë« ń¸ČEŞ40âb Łn5|”‰žźÜy†węEÇ íŔ÷>•=9÷r:ť0›ÍÍB@]¤*I5¤Ói +#ęŽb±|ˇEáŹ÷1¸©Á¤1ąóŇŹgx§r’ĐŢř<łŮ ‡ĂŃŮűű  x<ž}rĐ »Ô­ńúť(ŠpZ€Ég&N8(©Ěfó‘;ŔđN˝á¤ˇ@ł•’ôťű)ř|ľ}3H5—ËŁT*iTQçŐj5$“ \ă3ă/e"•Á`€×ë=pŹx†wŇłÓ„v€›´ű)´”§}€ÝĚ­!©ż%“I(˛‚WBűßĎA™č­&wŽôy ď¤C§ í¸yA0¸źBc»ŻgŮ0ó! ™HzřQ/Sb,†i?ŕ|nŕ.—Ë îDż;ÉŚ{Ă;éI;B{˝^GµZep?%÷S8lńŃ+! .ËH&“Z”EÔQą\ĺJĄądC­V$I”‰~çóůP­VQ«ŐNöů ď¤ííš-ÄĽGśű)AL&ärą}ďwŰ€ł^u«`f}ÜŁÎĽskHę'ńx&ŁzRđóňů žü¬Z­†b±ČA™č9ŁŁŁ(‹'îsĂ;uC»C; ŘWŻ×yŹh÷Sˇeź;,Őop"‘č~aDm–N§!ŐjX ĽÖřůç L´ß™3gś®ĎýY ďÔIťí€zŹ0›ÍáĺL/Äŕ~J/ęs·›Ů©Rc1 »€@‹CQýí.—ëŕE˘Ö®>÷g1ĽS't*´ěoo'~Űŕ°>w¸ •Ş„L&ŁAeDíQ*•Ëç±xČdI>źÇŘŘXw‹"ęíęsĂ;µS'C;űŰŰ‹Á˝ FGG[öą@x98ORĄ&Š"ěfődŕ籿ťčĹÚŮçţ,†wj‡N†vŕŹţöFŰť{Ľ¨ĎP©f˛Ůź G¤Ąz˝Žd"ó!ődŕç5~î9(µÖxQŰÎv™†w:ŤN‡v€ýííĆŕŢFŁcccH§Ó-ŻĎţľ ‡ČYwęAÉduYĆůCĆÜt: źĎÇţv˘C¸\.ř|ľCď§ĹđN'эШ÷ŃŃQö·· ż‹m2??ŹBˇ€rą|ŕšŮś ‰¸Y–5¨ŽčdÔ- cô.ëÁëőzétóóóÝ/ލ‡ĚĎĎ#ťNŁ^Żwäďgx§ăčVh/—Ő(:ó{›LNNÂl6#™L¶Ľ~Aju©TŞË•ť\ˇP@±Tną$ Î¤Č˛ŚąąąîFÔcććć ËrÇf݆w:šn…v@}bk6›qöěŮÎ}‘ĂŕŢ&fł333HĄR-w—ńÚŐÓTy’*őQŚÁmĆÜ­Ż'“I Ăí>䀺-äđđpÇ'oŢéEşÚEA*•ÂĚĚ ĚfsçľĐ€apoŁůůy”Ëĺ–»Ëę¬{ˇPDˇPčreDÇ'IR©ő$ŕV׳Ů,ŰdŽh~~Ůl¶ăašáťZéfhÔÝdĘĺ2ďmĆŕŢFgÎśĂá8ô¤Ôł^`ČĘEŞÔâń8ŚPOn%™LÂh4bff¦«uőŞ™™ †®´L2ĽÓłşÚőÔx‡ĂÁÇÚŚÁ˝ŤŚFcsR«vُRÉdŰ÷ó%j'EQ‹ ¨'·’JĄ011»ÝŢÝâz”ÝnÇřřřˇkˇÚŤáťmB{ŁMf~~ž»É´ż›m677×l!hĺ\”Cgĺ‰ô “É R•=)µ±SĎ¡;uĂű`Ó"´@6›E­Vă=˘ÜŰ, Âçó:Łâ´¨§OĆĹXËYy"=ĹBN@j}=™LÂb±p§˘c:{öě w ë†÷Á¤UhÔ6źĎ‡@ Đ˝/: ÜŰĚ`0`aaétúĐÁq1 ”+ŐŽś˘GtZ•JŮlîĐŮvY–‘H$0;;ËťŽÉl6cvv‰D˘«çz0Ľ-C»$IČd2XXX€ˇŐÎt* îpţüyŤFDŁŃ–ׇ‡ż[C’>‰˘«I=ń·•D"jµŠ×^{­»…ő‰×_Őjµ«łîĂű Đ2´@4…ŃhÄůóç»ű…{Řl6,.."Ź·\„j0‹NgP­V5¨¨5Y–‘‹x%¤žřű Ü;ÄétâÜąsĹb-ű­&uěD\ějź#Ń‹±Ć=ęIżĎSŃhccc„Cŕ‰čHAŔčč¨&łîĂ{żŃCh—e±X çÎťÓéě~‚Á˝^ýőćcŁV.€T«#ťNwą2˘ … Ĺ⡋RłŮ,ŠĹ"gۉÚäŇĄK(‹‡nÜi ďýAˇPí«×ëxýő×µ)`@0¸wÇăÁěěěˇ3*0âR·†$Ňš(ОŢÖ×÷öö OÁ#j“ŃŃQ‚€˝˝=Íj`xďmz í˛,#ŤbvvŹG›"{‡]şté…», @._@©TęreD¨ŐjH%“¸ROř}^>źG>źÇĄK—¸˝Q› \şt©ůűĄ†÷ޤ—Шg{T«UĽńĆÚ1 Ü;,ŕěŮłŘŰŰk9ë>ĺf.R%m©'ů*xĺE©{{{đů|śśěj]Dýnrr>źOÓYw€á˝×č)´7Ö?ť={–.u{Ľůć›(—Ë-{ÝMFŕĽ$joQ·)Š‚¸Ă´żőŕźÍf‘Édđć›or¶ť¨Í Ţ|óMd2ÍzÝŢ{žB; ö¶—ËeĽůć›Ú2 Ü» caa‘H¤ĺľîŻ„YVş~är9”+Ő–‹ReYĆöö6FFF0;;ŰýâŔěě,†‡‡±˝˝­ů.c ďú¦·Đ^«Ő‰DpîÜ9„Ăam‹ î]ňî»ďÂ`0`ww÷Ŕ5—ô©[ńi±- 61ߡžčűĽX,†JĄ‚Ë—/s¶ť¨C ._ľŚJĄ‚XLűÍ ŢőIoˇvwwa4ńÎ;ďh]ĘŔ`pď‡ĂwŢyńx…BáŔő P*—5] D§Z­"ťÉ`QPOô}ţÚÓ§O±¸¸ČľE˘ X\\ÄÓ§Ouq˘6Ă»ľč1´ ÄăqĽýöŰp8Z—30Ü»čüůóŘŢŢ>0ł>ć<6.RĄîEf#0ß"—ďěěŔfłá­·Ţę~aDč­·Ţ‚ŐjĹÎÎŽÖĄ`x× =†vEQđäÉAś?^ër {ŤF\ľ|ąů*őYş5d:ťâŕH]!Ë2q炀Ŵ˙Z6›E*•Â{ォժMDĆjµâ˝÷ŢC*•Ň|ˇjĂ»¶ôÚuAj±XÄĺË—a42JvżŰ]622rčBŐ… ú?ä°“V‰Ú)ťNCŞŐqáąE©Ť©ĂĂĂ››Ó¦8˘5??ŹááaěěěhľPµá]z 퍩 ÖşśĂŕ®ĂŞÚĚŔ\‹"©Rljb g\€˙ąÖÄĆ‚Ôű·ă‚T˘.k,T-—ËşX¨ÚŔđŢ]z íŔ Rß}÷]­KH îp8xűí·ŹÇ<] UIB&“Ѩ:ĄR ů|‹ĎíŢU.—ą •HcĎ.T-—ËZ—ÓÄđŢzíŮlńxo˝ő¤j„Á]#.\Ŕčč(677÷ ~!' ©łˇDť"Š"főäŢY–±±±·ŰŤ·ß~[»âożý6Ün7Ö××uÓ20ĽwšžC»$IŘÜÜÄčč(.\¸ u9‹Á]#FŁWŻ^…ÉdÂćććľÖEČfsşšiˇţQŻ×‘LÄq^ŚĎtÂlooŁR©ŕÚµk°Xtt· @‹×®]CĄRŃÍ.3 çĐ®( 677a2™pőęU.HŐżór:ť¸ző*˛Ů,˘Ńhóý3~ŔfâÖÔ‰D˛¬ŕ•ĐďKĄRÇăx˙ý÷ µ+Žš‚Á Ţ˙}˘T*Ąu9ű0Ľ·—žC;ěíí!›ÍâęŐ«p:ťZ—3ĐÜ56>>Ž7Ţx‘H¤yř’ŮĽ’‰¸®‘RďSq1†Iźzb/T*lmmaffŻĽňжŃ>çĎźÇĚĚ ¶¶¶P©T´.g†÷öĐ{hĎçóxúô)Ţxă ŚŹŹk]ÎŔcp×·Ţz ápÍ-"Ď @­.#™Lj\ő“|>ŹRą‚Ĺß·€lôµ;ťNüĺ/á.2D:c0đ—żü‡ş›Ěax?˝‡öZ­†ŤŤ „ĂaƧ î:`4ńÁ@łßÝc&<@ś‹T©ŤDQ„׌şŐ?ďîî˘T*áÚµküđC‹ĹŰëĂűÉč=´7úÚ >řŕöµë˙/č„Ëĺ•+WÉdš{÷.†B±„Bˇ quÔ$IB:•ÂbX=©7ťN#‹á˝÷Ţ /˙ H3‚ ŕ˝÷ŢC,C:ťÖşśŢŹGďˇPĎôČd2¸rĺ \.—ÖĺĐďÜudrr/^Äîî.2™ Ć=j2©R;ÄăqŤŔ|(‹ŘÜÜÄää$µ.ŤŽŕŐW_Ĺää$677Q,µ.ç†÷Łé…ĐžÉd°»»‹‹/âěŮłZ—CĎ`p×™wß}X__G©XŔH%“ÍŢw˘“h,Jť¨W°şş źĎ‡+W®°Żť¨G \ąr>ź«««ş[¬ 0ĽżL/„ö|>ŹőőuLLLđtTbpףŃk×®A¬®®bĘU  ‘Hh]ő°L&ŞTĂ‚_Âęę*ěv;®_żÎľv˘cµZńÉ'źŔn·cuuU—Áή^íĄR kkk×®]c_»ń˙™Íf|ôŃGpą\ŘŢXÁ”·Ž¸ŰwHŃq±'ެnܸÁ㪉z”ÓéÄŤ7kkk¨×ëWtĂű~˝Ú«Ő*VWWárąđńÇĂl6k]µŔŕ®SŤQ‹ĹWń Ę•*˛Ů¬ÖeQ*—ËČćrÉ{¨V«¸~ý:<ŹÖeŃ)x<\ż~•JëëëşŰ&`xoč…Đ^«Ő°şş ‹Ĺ‚7nŔfłi]‚Á]Ç\.®_ż§’DZ‚8©Ň ˘‹A†ł˛‡Ź>úˇPčĺźDDş …đńÇ#źĎ7·Ö›Aď˝ÚeYn>ąąqㆆ†´.‰^€Á]çü~?®_˙‚E:“Ńĺb$Ň/Y–‘ÇPb¸öÁŚŽŽj]µŃčč(®^˝ŠT*…ťť†wé…Đ®( 666P*•pýúuř|>­K˘—`pďĂĂĂř?x&ČX[[E"‘ĐĺcQŇEQN§±˛˛‚ş\Ç'oMbffF벨fffpůňeÄb1D"†wč…ĐŢ89;“ÉŕĂ?D8Öş$:˘Çßpjé‹ăo?>EVqĂl6! Aö˘Q“$IÇăHÄETކPÄ_Üř_}CëҨĂ~ůĺÜ»wÁ`“““şÜę5]ţë1ł ó ç`±č0ŃžR/„öz˝Žőőuäóy\˝z•;=„Á˝Çěîîâ˙~z Ă0bJRđz=„0<Ź.ję,EQP(~?Q1#€°9 ź´‹ë} Z—HD]˛ĽĽŚ/ľřŹ333şÜÎŻźĂ{/„vI’°¶¶†JĄ‚Ź>úcccZ—DÇŔŕŢâń8nŢĽ‰şb€14ŹÇ) EŔfµ $„ űj ¤Öęő:’É$D1†R© Ź x%X‡9łŽZą€?ü'Ţ  'OžŕłĎ>ĂáŔěě¬.·őëÇđŢ ˇ˝RQŕ€ëׯsł‚ÄŕŢŁ˛Ů,ţö·żˇR©`vv8±$kI@ŕ÷ †††8 ßgJĄDQD2‘@]–1é@°U±¶¶ Y–ńÉ'ź°_‘h€EŁQÜşu &“ sssşÓéÔş$:!÷W­VńŹüŃhSSSđűýEv˛j€’L&cs1«Ýn׸j:ŞjµŠx<ޏ(BŞŐ0âRg×§|€é÷ÖŐ|>ʵµ5¸Ýn\ż~ť{đQS>źÇÍ›7‘Ďç1;; —ËĄuIôrxď…ĐžJĄ°ąą‰‘‘üÇü‡.źľĐŃ1¸÷z˝Ž»wďb}}ápcccű$ĺ*ŔُúV©· !! źĎÇ6Rą\˘("“NĂd‚Ŕ8ö\,Ăîî.Âá0>ţřcî0DDT*|úé§ĹbC8ÖÝŘß‹á]ďˇ]–eěîî"‹affW®\á“÷>ŔŕŢ'EÁŻżţŠ{÷îÁétbzzú@«ËŔFř5Ä €ŐbF0$@„ž$ű]­VC"‘@\ڎ\©ÂoĂŔ\°š~ěćć&2™ ^{í5ĽýöۉčPőzß~ű-B.—‹żÜ]V,›‹M(ń©łë#. Ő˙Š\.‡ÍÍM \ąr…;ÇŃ‘=yňwďŢ…˘(žžÖ]ëL/„w˝‡öT*…­­-8|řá‡Aë’¨ŤÜűPµZĹ_|ŤŤ ‚€ńńńC÷ň­Öĺ„Ú ź)»­ąźmç3 5IDATĄ$gp;G–e¤R)ÄĹň…"†,ęBÓWB€ó›€˘(ŘŰŰC$Áđđ0>řŕÝÝt‰H˙ňů<>˙üsÄb1ś9s###şš°Ńsx×sh—e;;;E333řË_ţÂ~ö>ÄŕާEÁŁGŹđő×_Ăn·czzú…‹Rxš–bŔf0 đ‚«ĎۨR©@E$âqÔęuŚyÔŦg˝€ń÷MI’°ąą‰l6‹K—.áOú“.V!˘Ţ Ë2~řáÜżŹSSSş Čz ďzíĺr(—Ëx˙ý÷qţüy]˝Łöapďs‰D·oßF.—ĂÄÄ‚ÁŕK™ Uŕ·8đ0”$Ŕ54!¬.feX<>EQÍf!ĆbČdł°š€sż/6őaźL&­­-L&|đÁ<ĺŽÚfggwîÜA˝^Çää$Ľ^ŻÖ%5é)Ľë5´+Š‚D"íím¸Ýn\»v Á`P벨Ü€$Iřꫯ°ĽĽ —Ë…‰‰‰#͢ˊ:űľ$Os€ĹlB0$  q÷’#$©ąŘ´R•tŻ Ŕl0áőOĄRÁÎÎŇé4ĆÇÇń׿ţ•O?¨íŠĹ"ţůĎbgg>źăăăşăőŢőÚ‹Ĺ"¶··‘Ďç±°°€?˙ůĎşx2AťĹŕ>@"‘ľüňK¤Ói‚€ŃŃŃ#ď**©3đËq@’ź×‹ ŔăńđqÜ3EAˇP€(ŠHĄ’0@Ýやʏ˝ş,ËŘŰŰC4ý˙Ű»·§8ŞŽăżąŇĚ…ą30Y’%čFőÁR˙|ËňAEd5PY‡Ë ÍĚ0—žľîĂ„ÖŤÄ $Ŕ´ů~ަň EQ©sľś>ç´ ĂЧź~Şĺĺe~Î.MÚŮŮŃ—_~)˲´°° z˝>OYŻ3ާ1Ú]×UłŮT«ŐR±XÔçź®FŁqÝß®áţ–ń}_?üđľţúkĹb15ŤWÚ>sĘń¤-s˛ oŽ$c&fť¶«Ĺ®’çy2MSíÖˇ†#Kąôdďú;UÉ8ÇŹĄŰíjwwW¶mëÁúđĂYApeÇŃ·ß~«ÇŹ+ťNkiii*¶Ď\GĽO[´źn‹i6› ‚@ü±Ţ˙ý©řĺ W‡pK }őŐWzöěŮą¶Ďś ‚É]đ-iűX’b*•ËŞŐjoŐ›;-Ëš6=jËó|Ý,L‚ýsg_ĺř2ăńX»»»ęv»şqă†>űě3‹ĹËűĆŕ/t:}ńĹj6›Sł}ć*ă}Ú˘ýŹŰbîÜąŁO>ůä­škń;Âý-÷âö™………s_5r¤źž_)9°ĄlfVŐÚĽĘĺňßr% u:µZ‡:9ék&)ý«:ůäĎ9Żą®«ĂĂC¶Ĺ:/nź©×ëšźźżÖ§«WďÓí¶mkźm1î·Ď|óÍ7r]W•JEőzý/ŻŹ<óëŇz“+%w{R2WąRU­V;÷ךF¶m«Ýnë¨Ý’í¸šĎJďĎKËE)qÎßOÇŃÁÁÚí¶‚ Đýű÷Ů`*ťnźY__W,SµZU˝^ż¶ńę2ă}Z˘Ý˛,čččHÉdR}ôŰb ‰pÇض­'OžčńăDz,KĄRI şÉ¤7–ţÝš\+9ö¤ąąĽjµy …H­&A ~żŻVëPťăŽqiőůaÓĘ.xŹÇÚßß—išŠÇăzď˝÷t˙ţ}n‹0ő†ĂˇÖ××µ±±!ß÷ĂEžëŘBsń> Ń>µżżŻăăc†ˇčŢ˝{ĽH !Ââş®ž>}ŞďľűNý~_…BA zK§ëOöŔo´¤Ö@J§RŞÖ&WJNóę˛çyáUŽ#k¬‚1Ů»~·"Ą/đBŮŃhĆét:ŚŻ{Ď(ś×x<ÖĆƆÖ××eŰv¸Č3;;{ĄßÇ›Ś÷ëŽö““¨Űí*—ËéáÇş{÷î[}éÎF¸ăĄ|ß׳gĎ´¶¶¦N§Ł\.§z˝~áUóÖ@zŇšÜJăK*KŞŐjĘĺrSł ?'W9šGňý@˙,M‚}1wľĂ¦Ňď«ő§q6›Ő| wß}—Á@äą®«üQß˙˝ …‚ęőú•Žéo"ŢŻ+Ú P·ŰŐÁÁúýľJĄ’>|¨;wî°%/E¸ă˙ ‚@żüň‹ÖÖÖÔjµ”JĄT*•T.—•ÉdÎ=@Ź]ééóì˝±4;k¨öü0k"qĺě×äűţä°éáˇúfSŇ˝ŞônUĘ^ŕéäh4’iš:>>ÖxźĺÇŠÁŕůaSSR ŰĎ›Îg˙˙aÓ—…z:ťÖâ⢍†–——/tŰĽŤúý~8Gěííɶí7ňďo2ÚĎ ő 4;;«FŁÎ‡÷`zî¸4§'ć÷ööÔl6őŰożÉ˛,Ĺb1ełYe2†ˇ™™†ˇT*ufŰŢä&šŤCéŘ’Ś™´ŞµyU*•3W/|ß—išj·5Ž”KOî]§rö \וeYŹÇ˛,KĂá0 őT*ÂŤFCĺr™ýđš‚ išáBOłŮ”ă8aČż8G$“ÉW{ĎŠ÷‹F{rçćÁ`†şaşqㆍ†#÷ľD áŽ+sň§t»ÝÖÉɉN˙ Ćăq†ˇt:-Ă0Â;™L*‘H(‹«5ŠëI+¦ťŽ$ĹT*—5??ŻL&#˲Ôjµdµĺzľ–ć¤{µ@7ňß“ďűr]7x-Ë’m۲,KžçIRřKEĄR árąĚ^D¸d§‹.§‹=GGGę÷űáß'‰—Îńxüů< ŁůŹńľtó–v¶·˙íAČ÷}ůľ/Ďó^:Gřľ/i2GäóyU«Őp1‡PÇU"Üq­|ß×ÉɉşÝnřét:ęt:áţŔ% yńµ‚˛ĽŠĆAR3é”ƶŁdĚW=aj>ÖVĘ˙=Č_d†ŠĹ˘ŠĹ˘ …Bř™››»–+)ćyžz˝^87üńO˲Îü7‰D"üX2ô˝uKNP&nëń‹ľ†úËćL&sć‘ĎçYČÁµ"Ü1µ\×U·ŰŐx<–ă8g~ƶŁ_»v{ Őłžn%c&ĄTęĎźt:­t:­ąą9^ g۶z˝žlŰ–mŰ/ť'Žž~:NéAŐQ~6yćüpú™™™QˇPŕ)¦áDĎ{€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ Ü€ř/ýĚŮpUq–ĚIEND®B`‚Shapely-1.3.0/docs/index.txt000066400000000000000000000004001226057120100157060ustar00rootroot00000000000000======= Shapely ======= Documentation Contents ====================== .. toctree:: :maxdepth: 2 The Project User Manual API Documentation Indices and tables ================== * :ref:`genindex` * :ref:`search` Shapely-1.3.0/docs/manual.txt000066400000000000000000002114501226057120100160650ustar00rootroot00000000000000.. _manual: ======================= The Shapely User Manual ======================= :Author: Sean Gillies, :Version: 1.2 and 1.3 :Date: |today| :Copyright: This work is licensed under a `Creative Commons Attribution 3.0 United States License`__. .. __: http://creativecommons.org/licenses/by/3.0/us/ :Abstract: This document explains how to use the Shapely Python package for computational geometry. .. _intro: Introduction ============ Deterministic spatial analysis is an important component of computational approaches to problems in agriculture, ecology, epidemiology, sociology, and many other fields. What is the surveyed perimeter/area ratio of these patches of animal habitat? Which properties in this town intersect with the 50-year flood contour from this new flooding model? What are the extents of findspots for ancient ceramic wares with maker's marks "A" and "B", and where do the extents overlap? What's the path from home to office that best skirts identified zones of location based spam? These are just a few of the possible questions addressable using non-statistical spatial analysis, and more specifically, computational geometry. Shapely is a Python package for set-theoretic analysis and manipulation of planar features using (via Python's :mod:`ctypes` module) functions from the well known and widely deployed GEOS_ library. GEOS, a port of the `Java Topology Suite`_ (JTS), is the geometry engine of the PostGIS_ spatial extension for the PostgreSQL RDBMS. The designs of JTS and GEOS are largely guided by the `Open Geospatial Consortium`_'s Simple Features Access Specification [1]_ and Shapely adheres mainly to the same set of standard classes and operations. Shapely is thereby deeply rooted in the conventions of the geographic information systems (GIS) world, but aspires to be equally useful to programmers working on non-conventional problems. The first premise of Shapely is that Python programmers should be able to perform PostGIS type geometry operations outside of an RDBMS. Not all geographic data originate or reside in a RDBMS or are best processed using SQL. We can load data into a spatial RDBMS to do work, but if there's no mandate to manage (the "M" in "RDBMS") the data over time in the database we're using the wrong tool for the job. The second premise is that the persistence, serialization, and map projection of features are significant, but orthogonal problems. You may not need a hundred GIS format readers and writers or the multitude of State Plane projections, and Shapely doesn't burden you with them. The third premise is that Python idioms trump GIS (or Java, in this case, since the GEOS library is derived from JTS, a Java project) idioms. If you enjoy and profit from idiomatic Python, appreciate packages that do one thing well, and agree that a spatially enabled RDBMS is often enough the wrong tool for your computational geometry job, Shapely might be for you. .. _intro-spatial-data-model: Spatial Data Model ------------------ The fundamental types of geometric objects implemented by Shapely are points, curves, and surfaces. Each is associated with three sets of (possibly infinite) points in the plane. The `interior`, `boundary`, and `exterior` sets of a feature are mutually exclusive and their union coincides with the entire plane [2]_. * A `Point` has an `interior` set of exactly one point, a `boundary` set of exactly no points, and an `exterior` set of all other points. A `Point` has a topological dimension of 0. * A `Curve` has an `interior` set consisting of the infinitely many points along its length (imagine a `Point` dragged in space), a `boundary` set consisting of its two end points, and an `exterior` set of all other points. A `Curve` has a topological dimension of 1. * A `Surface` has an `interior` set consisting of the infinitely many points within (imagine a `Curve` dragged in space to cover an area), a `boundary` set consisting of one or more `Curves`, and an `exterior` set of all other points including those within holes that might exist in the surface. A `Surface` has a topological dimension of 2. That may seem a bit esoteric, but will help clarify the meanings of Shapely's spatial predicates, and it's as deep into theory as this manual will go. Consequences of point-set theory, including some that manifest themselves as "gotchas", for different classes will be discussed later in this manual. The point type is implemented by a `Point` class; curve by the `LineString` and `LinearRing` classes; and surface by a `Polygon` class. Shapely implements no smooth (`i.e.` having continuous tangents) curves. All curves must be approximated by linear splines. All rounded patches must be approximated by regions bounded by linear splines. Collections of points are implemented by a `MultiPoint` class, collections of curves by a `MultiLineString` class, and collections of surfaces by a `MultiPolygon` class. These collections aren't computationally significant, but are useful for modeling certain kinds of features. A Y-shaped line feature, for example, is well modeled as a whole by a `MultiLineString`. The standard data model has additional constraints specific to certain types of geometric objects that will be discussed in following sections of this manual. See also http://www.vividsolutions.com/jts/discussion.htm#spatialDataModel for more illustrations of this data model. .. _intro-relationships: Relationships ------------- The spatial data model is accompanied by a group of natural language relationships between geometric objects – `contains`, `intersects`, `overlaps`, `touches`, etc. – and a theoretical framework for understanding them using the 3x3 matrix of the mutual intersections of their component point sets [2]_: the DE-9IM. A comprehensive review of the relationships in terms of the DE-9IM is found in [4]_ and will not be reiterated in this manual. .. _intro-operations: Operations ---------- Following the JTS technical specs [5]_, this manual will make a distinction between constructive (`buffer`, `convex hull`) and set-theoretic operations (`intersection`, `union`, etc.). The individual operations will be fully described in a following section of the manual. .. _intro-coordinate-systems: Coordinate Systems ------------------ Even though the Earth is not flat – and for that matter not exactly spherical – there are many analytic problems that can be approached by transforming Earth features to a Cartesian plane, applying tried and true algorithms, and then transforming the results back to geographic coordinates. This practice is as old as the tradition of accurate paper maps. Shapely does not support coordinate system transformations. All operations on two or more features presume that the features exist in the same Cartesian plane. .. _objects: Geometric Objects ================= Geometric objects are created in the typical Python fashion, using the classes themselves as instance factories. A few of their intrinsic properties will be discussed in this sections, others in the following sections on operations and serializations. Instances of `Point`, `LineString`, and `LinearRing` have as their most important attribute a finite sequence of coordinates that determines their interior, boundary, and exterior point sets. A line string can be determined by as few as 2 points, but contains an infinite number of points. Coordinate sequences are immutable. A third `z` coordinate value may be used when constructing instances, but has no effect on geometric analysis. All operations are performed in the `x-y` plane. In all constructors, numeric values are converted to type ``float``. In other words, ``Point(0, 0)`` and ``Point(0.0, 0.0)`` produce geometrically equivalent instances. Shapely does not check the topological simplicity or validity of instances when they are constructed as the cost is unwarranted in most cases. Validating factories are trivially implemented, using the :attr:`is_valid` predicate, by users that require them. General Attributes and Methods ------------------------------ .. attribute:: object.area Returns the area (``float``) of the object. .. attribute:: object.bounds Returns a ``(minx, miny, maxx, maxy)`` tuple (``float`` values) that bounds the object. .. attribute:: object.length Returns the length (``float``) of the object. .. attribute:: object.geom_type Returns a string specifying the `Geometry Type` of the object in accordance with [1]_. .. sourcecode:: pycon >>> print Point(0, 0).geom_type Point .. method:: object.distance(other) Returns the minimum distance (``float``) to the `other` geometric object. .. sourcecode:: pycon >>> Point(0,0).distance(Point(1,1)) 1.4142135623730951 .. method:: object.representative_point() Returns a cheaply computed point that is guaranteed to be within the geometric object. .. note:: This is not in general the same as the centroid. .. sourcecode:: pycon >>> donut = Point(0, 0).buffer(2.0).difference(Point(0, 0).buffer(1.0)) >>> donut.centroid.wkt 'POINT (-0.0000000000000001 -0.0000000000000000)' >>> donut.representative_point().wkt 'POINT (-1.5000000000000000 0.0000000000000000)' .. _points: Points ------ .. class:: Point(coordinates) The `Point` constructor takes positional coordinate values or point tuple parameters. .. sourcecode:: pycon >>> from shapely.geometry import Point >>> point = Point(0.0, 0.0) >>> q = Point((0.0, 0.0)) A `Point` has zero area and zero length. .. sourcecode:: pycon >>> point.area 0.0 >>> point.length 0.0 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> point.bounds (0.0, 0.0, 0.0, 0.0) Coordinate values are accessed via `coords`, `x`, `y`, and `z` properties. .. sourcecode:: pycon >>> list(point.coords) [(0.0, 0.0)] >>> point.x 0.0 >>> point.y 0.0 Coordinates may also be sliced. `New in version 1.2.14`. .. sourcecode:: pycon >>> point.coords[:] [(0.0, 0.0)] The `Point` constructor also accepts another `Point` instance, thereby making a copy. .. sourcecode:: pycon >>> Point(point) .. _linestrings: LineStrings ----------- .. class:: LineString(coordinates) The `LineString` constructor takes an ordered sequence of 2 or more ``(x, y[, z])`` point tuples. The constructed `LineString` object represents one or more connected linear splines between the points. Repeated points in the ordered sequence are allowed, but may incur performance penalties and should be avoided. A `LineString` may cross itself (*i.e.* be `complex` and not `simple`). .. plot:: code/linestring.py Figure 1. A simple `LineString` on the left, a complex `LineString` on the right. The (`MultiPoint`) boundary of each is shown in black, the other points that describe the lines are shown in grey. A `LineString` has zero area and non-zero length. .. sourcecode:: pycon >>> from shapely.geometry import LineString >>> line = LineString([(0, 0), (1, 1)]) >>> line.area 0.0 >>> line.length 1.4142135623730951 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> line.bounds (0.0, 0.0, 1.0, 1.0) The defining coordinate values are accessed via the `coords` property. .. sourcecode:: pycon >>> len(line.coords) 2 >>> list(line.coords) [(0.0, 0.0), (1.0, 1.0)] Coordinates may also be sliced. `New in version 1.2.14`. .. sourcecode:: pycon >>> point.coords[:] [(0.0, 0.0), (1.0, 1.0)] >>> point.coords[1:] [(1.0, 1.0)] The constructor also accepts another `LineString` instance, thereby making a copy. .. sourcecode:: pycon >>> LineString(line) A sequence of `Point` instances is not a valid constructor parameter. A `LineString` is described by points, but is not composed of `Point` instances. .. _linearrings: LinearRings ----------- .. class:: LinearRing(coordinates) The `LinearRing` constructor takes an ordered sequence of ``(x, y[, z])`` point tuples. The sequence may be explicitly closed by passing identical values in the first and last indices. Otherwise, the sequence will be implicitly closed by copying the first tuple to the last index. As with a `LineString`, repeated points in the ordered sequence are allowed, but may incur performance penalties and should be avoided. A `LinearRing` may not cross itself, and may not touch itself at a single point. .. plot:: code/linearring.py Figure 2. A valid `LinearRing` on the left, an invalid self-touching `LinearRing` on the right. The points that describe the rings are shown in grey. A ring's boundary is `empty`. .. note:: Shapely will not prevent the creation of such rings, but exceptions will be raised when they are operated on. A `LinearRing` has zero area and non-zero length. .. sourcecode:: pycon >>> from shapely.geometry.polygon import LinearRing >>> ring = LinearRing([(0, 0), (1, 1), (1, 0)]) >>> ring.area 0.0 >>> ring.length 3.4142135623730949 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> ring.bounds (0.0, 0.0, 1.0, 1.0) Defining coordinate values are accessed via the `coords` property. .. sourcecode:: pycon >>> len(ring.coords) 4 >>> list(ring.coords) [(0.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)] The `LinearRing` constructor also accepts another `LineString` or `LinearRing` instance, thereby making a copy. .. sourcecode:: pycon >>> LinearRring(ring) As with `LineString`, a sequence of `Point` instances is not a valid constructor parameter. .. _polygons: Polygons -------- .. class:: Polygon(exterior [,interiors=None]) The `Polygon` constructor takes two positional parameters. The first is an ordered sequence of ``(x, y[, z])`` point tuples and is treated exactly as in the `LinearRing` case. The second is an optional unordered sequence of ring-like sequences specifying the interior boundaries or "holes" of the feature. Rings of a `valid` `Polygon` may not cross each other, but may touch at a single point only. Again, Shapely will not prevent the creation of invalid features, but exceptions will be raised when they are operated on. .. plot:: code/polygon.py Figure 3. On the left, a valid `Polygon` with one interior ring that touches the exterior ring at one point, and on the right a `Polygon` that is `invalid` because its interior ring touches the exterior ring at more than one point. The points that describe the rings are shown in grey. .. plot:: code/polygon2.py Figure 4. On the left, a `Polygon` that is `invalid` because its exterior and interior rings touch along a line, and on the right, a `Polygon` that is `invalid` because its interior rings touch along a line. A `Polygon` has non-zero area and non-zero length. .. sourcecode:: pycon >>> from shapely.geometry import Polygon >>> polygon = Polygon([(0, 0), (1, 1), (1, 0)]) >>> polygon.area 0.5 >>> polygon.length 3.4142135623730949 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> polygon.bounds (0.0, 0.0, 1.0, 1.0) Component rings are accessed via `exterior` and `interiors` properties. .. sourcecode:: pycon >>> list(polygon.exterior.coords) [(0.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)] >>> list(polygon.interiors) [] The `Polygon` constructor also accepts instances of `LineString` and `LinearRing`. .. sourcecode:: pycon >>> coords = [(0, 0), (1, 1), (1, 0)] >>> r = LinearRing(coords) >>> s = Polygon(r) >>> s.area 0.5 >>> t = Polygon(s.buffer(1.0).exterior, [r]) >>> t.area 6.5507620529190334 Rectangular polygons occur commonly, and can be conveniently constructed using the :func:`shapely.geometry.box()` function. .. function:: shapely.geometry.box(minx, miny, maxx, maxy, ccw=True) Makes a rectangular polygon from the provided bounding box values, with counter-clockwise order by default. `New in version 1.2.9`. For example: .. sourcecode:: pycon >>> from shapely.geometry import box >>> b = box(0.0, 0.0, 1.0, 1.0) >>> b >>> list(b.exterior.coords) [(1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0), (1.0, 0.0)] This is the first appearance of an explicit polygon handedness in Shapely. To obtain a polygon with a known orientation, use :func:`shapely.geometry.polygon.orient()`: .. function:: shapely.geometry.polygon.orient(polygon, sign=1.0) Returns a properly oriented copy of the given polygon. The signed area of the result will have the given sign. A sign of 1.0 means that the coordinates of the product's exterior ring will be oriented counter-clockwise. `New in version 1.2.10`. .. _collections: Collections ----------- Heterogeneous collections of geometric objects may result from some Shapely operations. For example, two `LineStrings` may intersect along a line and at a point. To represent these kind of results, Shapely provides frozenset_-like, immutable collections of geometric objects. The collections may be homogeneous (`MultiPoint` etc.) or heterogeneous. .. sourcecode:: python >>> a = LineString([(0, 0), (1, 1), (1,2), (2,2)]) >>> b = LineString([(0, 0), (1, 1), (2,1), (2,2)]) >>> x = a.intersection(b) >>> x >>> from pprint import pprint >>> pprint(list(x)) [, ] .. plot:: code/geometrycollection.py :class: figure Figure 5. a) a green and a yellow line that intersect along a line and at a single point; b) the intersection (in blue) is a collection containing one `LineString` and one `Point`. Members of a `GeometryCollection` are accessed via the `geoms` property or via the iterator protocol using ``in`` or ``list()``. .. sourcecode:: pycon >>> pprint(list(x.geoms)) [, ] >>> pprint(list(x)) [, ] Homogeneous collections can also be sliced, resulting in a new object of the same type. .. sourcecode:: pycon >>> from shapely.geometry import MultiPoint >>> m = MultiPoint([(0, 0), (1, 1), (1,2), (2,2)]) >>> m[:1].wkt 'MULTIPOINT (0.0000000000000000 0.0000000000000000)' >>> m[3:].wkt 'MULTIPOINT (2.0000000000000000 2.0000000000000000)' >>> m[4:].wkt 'GEOMETRYCOLLECTION EMPTY' `New in version 1.2.14`. .. note:: When possible, it is better to use one of the homogeneous collection types described below. .. _multipoints: Collections of Points --------------------- .. class:: MultiPoint(points) The `MultiPoint` constructor takes a sequence of ``(x, y[, z ])`` point tuples. A `MultiPoint` has zero area and zero length. .. sourcecode:: pycon >>> from shapely.geometry import MultiPoint >>> points = MultiPoint([(0.0, 0.0), (1.0, 1.0)]) >>> points.area 0.0 >>> points.length 0.0 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> points.bounds (0.0, 0.0, 1.0, 1.0) Members of a multi-point collection are accessed via the ``geoms`` property or via the iterator protocol using ``in`` or :func:`list`. .. sourcecode:: pycon >>> import pprint >>> pprint.pprint(list(points.geoms)) [, ] >>> pprint.pprint(list(points)) [, ] The constructor also accepts another `MultiPoint` instance or an unordered sequence of `Point` instances, thereby making copies. .. sourcecode:: pycon >>> MultiPoint([Point(0, 0), Point(1, 1)]) .. _multilinestrings: Collections of Lines -------------------- .. class:: MultiLineString(lines) The `MultiLineString` constructor takes a sequence of line-like sequences or objects. .. plot:: code/multilinestring.py Figure 6. On the left, a `simple`, disconnected `MultiLineString`, and on the right, a non-simple `MultiLineString`. The points defining the objects are shown in gray, the boundaries of the objects in black. A `MultiLineString` has zero area and non-zero length. .. sourcecode:: pycon >>> from shapely.geometry import MultiLineString >>> coords = [((0, 0), (1, 1)), ((-1, 0), (1, 0))] >>> lines = MultiLineString(coords) >>> lines.area 0.0 >>> lines.length 3.4142135623730949 Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> lines.bounds (-1.0, 0.0, 1.0, 1.0) Its members are instances of `LineString` and are accessed via the ``geoms`` property or via the iterator protocol using ``in`` or ``list()``. .. sourcecode:: pycon >>> len(lines.geoms) 2 >>> pprint.pprint(list(lines.geoms)) [, ] >>> pprint.pprint(list(lines)) [, ] The constructor also accepts another instance of `MultiLineString` or an unordered sequence of `LineString` instances, thereby making copies. .. sourcecode:: pycon >>> MultiLineString(lines) >>> MultiLineString(lines.geoms) .. _multipolygons: Collections of Polygons ----------------------- .. class:: MultiPolygon(polygons) The `MultiPolygon` constructor takes a sequence of exterior ring and hole list tuples: [((a1, ..., aM), [(b1, ..., bN), ...]), ...]. More clearly, the constructor also accepts an unordered sequence of `Polygon` instances, thereby making copies. .. sourcecode:: pycon >>> polygons = MultiPolygon([polygon, s, t]) >>> len(polygons.geoms) 3 .. plot:: code/multipolygon.py Figure 7. On the right, a `valid` `MultiPolygon` with 2 members, and on the right, a `MultiPolygon` that is invalid because its members touch at an infinite number of points (along a line). Its `x-y` bounding box is a ``(minx, miny, maxx, maxy)`` tuple. .. sourcecode:: pycon >>> polygons.bounds (-1.0, -1.0, 2.0, 2.0) Its members are instances of `Polygon` and are accessed via the ``geoms`` property or via the iterator protocol using ``in`` or ``list()``. .. sourcecode:: pycon >>> len(polygons.geoms) 3 >>> len(polygons) 3 .. _empties: Empty features -------------- An "empty" feature is one with a point set that coincides with the empty set; not ``None``, but like ``set([])``. Empty features can be created by calling the various constructors with no arguments. Almost no operations are supported by empty features. .. sourcecode:: pycon >>> line = LineString() >>> line.is_empty True >>> line.length 0.0 >>> line.bounds () >>> line.coords [] The coordinates of a empty feature can be set, after which the geometry is no longer empty. .. sourcecode:: pycon >>> line.coords = [(0, 0), (1, 1)] >>> line.is_empty False >>> line.length 1.4142135623730951 >>> line.bounds (0.0, 0.0, 1.0, 1.0) Linear Referencing Methods -------------------------- It can be useful to specify position along linear features such as `LineStrings` and `MultiLineStrings` with a 1-dimensional referencing system. Shapely supports linear referencing based on length or distance, evaluating the distance along a geometric object to the projection of a given point, or the point at a given distance along the object. .. note:: Linear referencing methods require GEOS 3.2.0 or later. .. method:: object.interpolate(distance[, normalized=False]) Return a point at the specified distance along a linear geometric object. If the `normalized` arg is ``True``, the distance will be interpreted as a fraction of the geometric object's length. .. sourcecode:: pycon >>> ip = LineString([(0, 0), (0, 1), (1, 1)]).interpolate(1.5) >>> ip >>> ip.wkt 'POINT (0.5000000000000000 1.0000000000000000)' >>> LineString([(0, 0), (0, 1), (1, 1)]).interpolate(0.75, normalized=True).wkt 'POINT (0.5000000000000000 1.0000000000000000)' .. method:: object.project(other[, normalized=False]) Returns the distance along this geometric object to a point nearest the `other` object. If the `normalized` arg is ``True``, return the distance normalized to the length of the object. The :meth:`project` method is the inverse of :meth:`interpolate`. .. sourcecode:: pycon >>> LineString([(0, 0), (0, 1), (1, 1)]).project(ip) 1.5 >>> LineString([(0, 0), (0, 1), (1, 1)]).project(ip, normalized=True) 0.75 For example, the linear referencing methods might be used to cut lines at a specified distance. .. sourcecode:: python def cut(line, distance): # Cuts a line in two at a distance from its starting point if distance <= 0.0 or distance >= line.length: return [LineString(line)] coords = list(line.coords) for i, p in enumerate(coords): pd = line.project(Point(p)) if pd == distance: return [ LineString(coords[:i+1]), LineString(coords[i:])] if pd > distance: cp = line.interpolate(distance) return [ LineString(coords[:i] + [(cp.x, cp.y)]), LineString([(cp.x, cp.y)] + coords[i:])] .. sourcecode:: pycon >>> line = LineString([(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0)]) >>> pprint([list(x.coords) for x in cut(line, 1.0)]) [[(0.0, 0.0), (1.0, 0.0)], [(1.0, 0.0), (2.0, 0.0), (3.0, 0.0), (4.0, 0.0), (5.0, 0.0)]] >>> pprint([list(x.coords) for x in cut(line, 2.5)]) [[(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (2.5, 0.0)], [(2.5, 0.0), (3.0, 0.0), (4.0, 0.0), (5.0, 0.0)]] .. _predicates: Predicates and Relationships ============================ Objects of the types explained in :ref:`objects` provide standard [1]_ predicates as attributes (for unary predicates) and methods (for binary predicates). Whether unary or binary, all return ``True`` or ``False``. .. _unary-predicates: Unary Predicates ---------------- Standard unary predicates are implemented as read-only property attributes. An example will be shown for each. .. attribute:: object.has_z Returns ``True`` if the feature has not only `x` and `y`, but also `z` coordinates for 3D (or so-called, 2.5D) geometries. .. sourcecode:: pycon >>> Point(0, 0).has_z False >>> Point(0, 0, 0).has_z True .. attribute:: object.is_ccw Returns ``True`` if coordinates are in counter-clockwise order (bounding a region with positive signed area). This method applies to `LinearRing` objects only. `New in version 1.2.10`. .. sourcecode:: pycon >>> LinearRing([(1,0), (1,1), (0,0)]).is_ccw True A ring with an undesired orientation can be reversed like this: .. sourcecode:: pycon >>> ring = LinearRing([(0,0), (1,1), (1,0)]) >>> ring.is_ccw False >>> ring.coords = list(ring.coords)[::-1] >>> ring.is_ccw True .. attribute:: object.is_empty Returns ``True`` if the feature's `interior` and `boundary` (in point set terms) coincide with the empty set. .. sourcecode:: pycon >>> Point().is_empty True >>> Point(0, 0).is_empty False .. note:: With the help of the :mod:`operator` module's :func:`attrgetter` function, unary predicates such as ``is_empty`` can be easily used as predicates for the built in :func:`filter` or :func:`itertools.ifilter`. .. sourcecode:: pycon >>> from operator import attrgetter >>> empties = filter(attrgetter('is_empty'), [Point(), Point(0, 0)]) >>> len(empties) 1 .. attribute:: object.is_ring Returns ``True`` if the feature is closed. A closed feature's `boundary` coincides with the empty set. .. sourcecode:: pycon >>> LineString([(0, 0), (1, 1), (1, -1)]).is_ring False >>> LinearRing([(0, 0), (1, 1), (1, -1)]).is_ring True This property is applicable to `LineString` and `LinearRing` instances, but meaningless for others. .. attribute:: object.is_simple Returns ``True`` if the feature does not cross itself. .. note:: The simplicity test is meaningful only for `LineStrings` and `LinearRings`. .. sourcecode:: pycon >>> LineString([(0, 0), (1, 1), (1, -1), (0, 1)]).is_simple False Operations on non-simple `LineStrings` are fully supported by Shapely. .. attribute:: object.is_valid Returns ``True`` if a feature is "valid" in the sense of [1]_. A valid `LinearRing` may not cross itself or touch itself at a single point. A valid `Polygon` may not possess any overlapping exterior or interior rings. A valid `MultiPolygon` may not collect any overlapping polygons. Operations on invalid features may fail. .. sourcecode:: pycon >>> MultiPolygon([Point(0, 0).buffer(2.0), Point(1, 1).buffer(2.0)]).is_valid False The two points above are close enough that the polygons resulting from the buffer operations (explained in a following section) overlap. .. note:: The ``is_valid`` predicate can be used to write a validating decorator that could ensure that only valid objects are returned from a constructor function. .. sourcecode:: python from functools import wraps def validate(func): @wraps(func) def wrapper(*args, **kwargs): ob = func(*args, **kwargs) if not ob.is_valid: raise TopologicalError( "Given arguments do not determine a valid geometric object") return ob return wrapper .. sourcecode:: pycon >>> @validate ... def ring(coordinates): ... return LinearRing(coordinates) ... >>> coords = [(0, 0), (1, 1), (1, -1), (0, 1)] >>> ring(coords) Traceback (most recent call last): File "", line 1, in File "", line 7, in wrapper shapely.geos.TopologicalError: Given arguments do not determine a valid geometric object .. _binary-predicates: Binary Predicates ----------------- Standard binary predicates are implemented as methods. These predicates evaluate topological, set-theoretic relationships. In a few cases the results may not be what one might expect starting from different assumptions. All take another geometric object as argument and return ``True`` or ``False``. .. method:: object.almost_equals(other[, decimal=6]) Returns ``True`` if the object is approximately equal to the `other` at all points to specified `decimal` place precision. See also :meth:`equals`. .. method:: object.contains(other) Returns ``True`` if the object's `interior` contains the `boundary` and `interior` of the other object and their boundaries do not touch at all. This predicate applies to all types, and is inverse to :meth:`within`. The expression ``a.contains(b) == b.within(a)`` always evaluates to ``True``. .. sourcecode:: pycon >>> coords = [(0, 0), (1, 1)] >>> LineString(coords).contains(Point(0.5, 0.5)) True >>> Point(0.5, 0.5).within(LineString(coords)) True A line's endpoints are part of its `boundary` and are therefore not contained. .. sourcecode:: pycon >>> LineString(coords).contains(Point(1.0, 1.0)) False .. note:: Binary predicates can be used directly as predicates for ``filter()`` or ``itertools.ifilter()``. .. sourcecode:: pycon >>> line = LineString(coords) >>> contained = filter(line.contains, [Point(), Point(0.5, 0.5)]) >>> len(contained) 1 >>> [p.wkt for p in contained] ['POINT (0.5000000000000000 0.5000000000000000)'] .. method:: object.crosses(other) Returns ``True`` if the `interior` of the object intersects the `interior` of the other but does not contain it, and the dimension of the intersection is less than the dimension of the one or the other. .. sourcecode:: pycon >>> LineString(coords).crosses(LineString([(0, 1), (1, 0)])) True A line does not cross a point that it contains. .. sourcecode:: pycon >>> LineString(coords).crosses(Point(0.5, 0.5)) False .. method:: object.disjoint(other) Returns ``True`` if the `boundary` and `interior` of the object do not intersect at all with those of the other. .. sourcecode:: pycon >>> Point(0, 0).disjoint(Point(1, 1)) True This predicate applies to all types and is the inverse of :meth:`intersects`. .. method:: object.equals(other) Returns ``True`` if the set-theoretic `boundary`, `interior`, and `exterior` of the object coincide with those of the other. The coordinates passed to the object constructors are of these sets, and determine them, but are not the entirety of the sets. This is a potential "gotcha" for new users. Equivalent lines, for example, can be constructed differently. .. sourcecode:: pycon >>> a = LineString([(0, 0), (1, 1)]) >>> b = LineString([(0, 0), (0.5, 0.5), (1, 1)]) >>> c = LineString([(0, 0), (0, 0), (1, 1)]) >>> a.equals(b) True >>> b.equals(c) True This predicate should not be mistaken for Python's ``==`` or ``is`` constructions. .. method:: object.intersects(other) Returns ``True`` if the `boundary` and `interior` of the object intersect in any way with those of the other. This predicate is equivalent to the OR-ing of :meth:`contains`, :meth:`crosses`, :meth:`equals`, :meth:`touches`, and :meth:`within`. .. method:: object.touches(other) Returns ``True`` if the objects have at least one point in common and their interiors do not intersect with any part of the other. Overlapping features do not therefore `touch`, another potential "gotcha". For example, the following lines touch at ``(1, 1)``, but do not overlap. .. sourcecode:: pycon >>> a = LineString([(0, 0), (1, 1)]) >>> b = LineString([(1, 1), (2, 2)]) >>> a.touches(b) True .. method:: object.within(other) Returns ``True`` if the object's `boundary` and `interior` intersect only with the `interior` of the other (not its `boundary` or `exterior`). This applies to all types and is the inverse of :meth:`contains`. Used in a ``sorted()`` `key`, :meth:`within` makes it easy to spatially sort objects. Let's say we have 4 stereotypic features: a point that is contained by a polygon which is itself contained by another polygon, and a free spirited point contained by none .. sourcecode:: pycon >>> a = Point(2, 2) >>> b = Polygon([[1, 1], [1, 3], [3, 3], [3, 1]]) >>> c = Polygon([[0, 0], [0, 4], [4, 4], [4, 0]]) >>> d = Point(-1, -1) and that copies of these are collected into a list .. sourcecode:: pycon >>> features = [c, a, d, b, c] that we'd prefer to have ordered as ``[d, c, c, b, a]`` in reverse containment order. As explained in the Python `Sorting HowTo`_, we can define a key function that operates on each list element and returns a value for comparison. Our key function will be a wrapper class that implements ``__lt__()`` using Shapely's binary :meth:`within` predicate. .. sourcecode:: python from shapely.geometry import asShape class Within(object): def __init__(self, o): self.o = o def __lt__(self, other): return self.o.within(other.o) As the howto says, the `less than` comparison is guaranteed to be used in sorting. That's what we'll rely on to spatially sort, and the reason why we use :meth:`within` in reverse instead of :meth:`contains`. Trying it out on features `d` and `c`, we see that it works. .. sourcecode:: pycon >>> d < c True >>> Within(d) < Within(c) False It also works on the list of features, producing the order we want. .. sourcecode:: pycon >>> [d, c, c, b, a] == sorted(features, key=Within, reverse=True) True DE-9IM Relationships -------------------- The :meth:`relate` method tests all the DE-9IM [4]_ relationships between objects, of which the named relationship predicates above are a subset. .. method:: object.relate(other) Returns a string representation of the DE-9IM matrix of relationships between an object's `interior`, `boundary`, `exterior` and those of another geometric object. The named relationship predicates (:meth:`contains`, etc.) are typically implemented as wrappers around :meth:`relate`. Two different points have mainly ``F`` (false) values in their matrix; the intersection of their `external` sets (the 9th element) is a ``2`` dimensional object (the rest of the plane). The intersection of the `interior` of one with the `exterior` of the other is a ``0`` dimensional object (3rd and 7th elements of the matrix). .. sourcecode:: pycon >>> Point(0, 0).relate(Point(1, 1)) 'FF0FFF0F2' The matrix for a line and a point on the line has more "true" (not ``F``) elements. .. sourcecode:: pycon >>> Point(0, 0).relate(LineString([(0, 0), (1, 1)])) 'F0FFFF102' Further discussion of the DE-9IM matrix is beyond the scope of this manual. See [4]_ and http://pypi.python.org/pypi/de9im. .. _analysis-methods: Spatial Analysis Methods ======================== As well as boolean attributes and methods, Shapely provides analysis methods that return new geometric objects. .. _set-theoretic-methods: Set-theoretic Methods --------------------- Almost every binary predicate method has a counterpart that returns a new geometric object. In addition, the set-theoretic `boundary` of an object is available as a read-only attribute. .. attribute:: object.boundary Returns a lower dimensional object representing the object's set-theoretic `boundary`. The boundary of a polygon is a line, the boundary of a line is a collection of points. The boundary of a point is an empty (null) collection. .. sourcecode:: pycon >> coords = [((0, 0), (1, 1)), ((-1, 0), (1, 0))] >>> lines = MultiLineString(coords) >>> lines.boundary >>> pprint(list(lines.boundary)) [, , , ] >>> lines.boundary.boundary >>> lines.boundary.boundary.is_empty True See the figures in :ref:`linestrings` and :ref:`multilinestrings` for the illustration of lines and their boundaries. .. attribute:: object.centroid Returns a representation of the object's geometric centroid (point). .. sourcecode:: pycon >>> LineString([(0, 0), (1, 1)]).centroid >>> LineString([(0, 0), (1, 1)]).centroid.wkt 'POINT (0.5000000000000000 0.5000000000000000)' .. note:: The centroid of an object might be one of its points, but this is not guaranteed. .. method:: object.difference(other) Returns a representation of the points making up this geometric object that do not make up the *other* object. .. sourcecode:: pycon >>> a = Point(1, 1).buffer(1.5) >>> b = Point(2, 1).buffer(1.5) >>> a.difference(b) .. note:: The :meth:`buffer` method is used to produce approximately circular polygons in the examples of this section; it will be explained in detail later in this manual. .. plot:: code/difference.py Figure 8. Differences between two approximately circular polygons. .. note:: Shapely can not represent the difference between an object and a lower dimensional object (such as the difference between a polygon and a line or point) as a single object, and in these cases the difference method returns a copy of the object named ``self``. .. method:: object.intersection(other) Returns a representation of the intersection of this object with the `other` geometric object. .. sourcecode:: pycon >>> a = Point(1, 1).buffer(1.5) >>> b = Point(2, 1).buffer(1.5) >>> a.intersection(b) See the figure under :meth:`symmetric_difference` below. .. method:: object.symmetric_difference(other) Returns a representation of the points in this object not in the `other` geometric object, and the points in the `other` not in this geometric object. .. sourcecode:: pycon >>> a = Point(1, 1).buffer(1.5) >>> b = Point(2, 1).buffer(1.5) >>> a.symmetric_difference(b) .. plot:: code/intersection-sym-difference.py .. method:: object.union(other) Returns a representation of the union of points from this object and the `other` geometric object. The type of object returned depends on the relationship between the operands. The union of polygons (for example) will be a polygon or a multi-polygon depending on whether they intersect or not. .. sourcecode:: pycon >>> a = Point(1, 1).buffer(1.5) >>> b = Point(2, 1).buffer(1.5) >>> a.union(b) The semantics of these operations vary with type of geometric object. For example, compare the boundary of the union of polygons to the union of their boundaries. .. sourcecode:: pycon >>> a.union(b).boundary >>> a.boundary.union(b.boundary) .. plot:: code/union.py .. note:: :meth:`union` is an expensive way to find the cumulative union of many objects. See :func:`shapely.ops.cascaded_union` for a more effective method. Constructive Methods -------------------- Shapely geometric object have several methods that yield new objects not derived from set-theoretic analysis. .. method:: object.buffer(distance, resolution=16, cap_style=1, join_style=1, mitre_limit=1.0) Returns an approximate representation of all points within a given `distance` of the this geometric object. The styles of caps are specified by integer values: 1 (round), 2 (flat), 3 (square). These values are also enumerated by the object :class:`shapely.geometry.CAP_STYLE` (see below). The styles of joins between offset segments are specified by integer values: 1 (round), 2 (mitre), and 3 (bevel). These values are also enumerated by the object :class:`shapely.geometry.JOIN_STYLE` (see below). .. data:: shapely.geometry.CAP_STYLE ========= ===== Attribute Value ========= ===== round 1 flat 2 square 3 ========= ===== .. data:: shapely.geometry.JOIN_STYLE ========= ===== Attribute Value ========= ===== round 1 mitre 2 bevel 3 ========= ===== .. sourcecode:: pycon >>> from shapely.geometry import CAP_STYLE, JOIN_STYLE >>> CAP_STYLE.flat 2 >>> JOIN_STYLE.bevel 3 A positive distance has an effect of dilation; a negative distance, erosion. The optional `resolution` argument determines the number of segments used to approximate a quarter circle around a point. .. sourcecode:: pycon >>> line = LineString([(0, 0), (1, 1), (0, 2), (2, 2), (3, 1), (1, 0)]) >>> dilated = line.buffer(0.5) >>> eroded = dilated.buffer(-0.3) .. plot:: code/buffer.py Figure 9. Dilation of a line (left) and erosion of a polygon (right). New object is shown in blue. The default (`resolution` of 16) buffer of a point is a polygonal patch with 99.8% of the area of the circular disk it approximates. .. sourcecode:: pycon >>> p = Point(0, 0).buffer(10.0) >>> len(p.exterior.coords) 66 >>> p.area 313.65484905459385 With a `resolution` of 1, the buffer is a square patch. .. sourcecode:: pycon >>> q = Point(0, 0).buffer(10.0, 1) >>> len(q.exterior.coords) 5 >>> q.area 200.0 Passed a `distance` of 0, :meth:`buffer` can be used to "clean" self-touching or self-crossing polygons such as the classic "bowtie". .. sourcecode:: pycon >>> coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)] >>> bowtie = Polygon(coords) >>> bowtie.is_valid False >>> clean = bowtie.buffer(0) >>> clean.is_valid True >>> clean >>> len(clean) 2 >>> list(clean[0].exterior.coords) [(0.0, 0.0), (0.0, 2.0), (1.0, 1.0), (0.0, 0.0)] >>> list(clean[1].exterior.coords) [(1.0, 1.0), (2.0, 2.0), (2.0, 0.0), (1.0, 1.0)] Buffering splits the polygon in two at the point where they touch. .. attribute:: object.convex_hull Returns a representation of the smallest convex `Polygon` containing all the points in the object unless the number of points in the object is less than three. For two points, the convex hull collapses to a `LineString`; for 1, a `Point`. .. sourcecode:: pycon >>> Point(0, 0).convex_hull >>> MultiPoint([(0, 0), (1, 1)]).convex_hull >>> MultiPoint([(0, 0), (1, 1), (1, -1)]).convex_hull .. plot:: code/convex_hull.py Figure 10. Convex hull (blue) of 2 points (left) and of 6 points (right). .. attribute:: object.envelope Returns a representation of the point or smallest rectangular polygon (with sides parallel to the coordinate axes) that contains the object. .. sourcecode:: pycon >>> Point(0, 0).envelope >>> MultiPoint([(0, 0), (1, 1)]).envelope .. method:: object.parallel_offset(distance, side, resolution=16, join_style=1, mitre_limit=1.0) Returns a LineString or MultiLineString geometry at a distance from the object on its right or its left side. Distance must be a positive float value. The side parameter may be 'left' or 'right'. The resolution of the offset around each vertex of the object is parameterized as in the buffer method. The join style is for outside corners between line segments. Accepted integer values are 1 (round), 2 (mitre), and 3 (bevel). See also :data:`shapely.geometry.JOIN_STYLE`. Severely mitered corners can be controlled by the mitre_limit parameter (spelled in British English, en-gb). The ratio of the distance from the corner to the end of the mitred offset corner is the miter ratio. Corners with a ratio which exceed the limit will be beveled. .. note:: This method is only available for `LinearRing` and `LineString` objects. .. plot:: code/parallel_offset.py Figure 11. Three styles of parallel offset lines on the left side of a simple line string (its starting point shown as a circle) and one offset on the right side, a multipart. The effect of the `mitre_limit` parameter is shown below. .. plot:: code/parallel_offset_mitre.py Figure 12. Large and small mitre_limit values for left and right offsets. .. method:: object.simplify(tolerance, preserve_topology=True) Returns a simplified representation of the geometric object. All points in the simplified object will be within the `tolerance` distance of the original geometry. By default a slower algorithm is used that preserves topology. If preserve topology is set to ``False`` the much quicker Douglas-Peucker algorithm [6]_ is used. .. sourcecode:: pycon >>> p = Point(0.0, 0.0) >>> x = p.buffer(1.0) >>> x.area 3.1365484905459389 >>> len(x.exterior.coords) 66 >>> s = x.simplify(0.05, preserve_topology=False) >>> s.area 3.0614674589207187 >>> len(s.exterior.coords) 17 .. plot:: code/simplify.py Figure 13. Simplification of a nearly circular polygon using a tolerance of 0.2 (left) and 0.5 (right). .. note:: `Invalid` geometric objects may result from simplification that does not preserve topology. Affine Transformations ====================== A collection of affine transform functions are in the :mod:`shapely.affinity` module, which return transformed geometries by either directly supplying coefficients to an affine transformation matrix, or by using a specific, named transform (`rotate`, `scale`, etc.). The functions can be used with all geometry types (except `GeometryCollection`), and 3D types are either preserved or supported by 3D affine transformations. `New in version 1.2.17`. .. function:: shapely.affinity.affine_transform(geom, matrix) Returns a transformed geometry using an affine transformation matrix. The coefficient ``matrix`` is provided as a list or tuple with 6 or 12 items for 2D or 3D transformations, respectively. For 2D affine transformations, the 6 parameter ``matrix`` is: ``[a, b, d, e, xoff, yoff]`` which represents the augmented matrix: .. math:: \begin{bmatrix} x' & y' & 1 \end{bmatrix} = \begin{bmatrix} x & y & 1 \end{bmatrix} \begin{bmatrix} a & b & x_\mathrm{off} \\ d & e & y_\mathrm{off} \\ 0 & 0 & 1 \end{bmatrix} or the equations for the transformed coordinates: .. math:: x' &= a x + b y + x_\mathrm{off} \\ y' &= d x + e y + y_\mathrm{off}. For 3D affine transformations, the 12 parameter ``matrix`` is: ``[a, b, c, d, e, f, g, h, i, xoff, yoff, zoff]`` which represents the augmented matrix: .. math:: \begin{bmatrix} x' & y' & z' & 1 \end{bmatrix} = \begin{bmatrix} x & y & z & 1 \end{bmatrix} \begin{bmatrix} a & b & c & x_\mathrm{off} \\ d & e & f & y_\mathrm{off} \\ g & h & i & z_\mathrm{off} \\ 0 & 0 & 0 & 1 \end{bmatrix} or the equations for the transformed coordinates: .. math:: x' &= a x + b y + c z + x_\mathrm{off} \\ y' &= d x + e y + f z + y_\mathrm{off} \\ z' &= g x + h y + i z + z_\mathrm{off}. .. function:: shapely.affinity.rotate(geom, angle, origin='center', use_radians=False) Returns a rotated geometry on a 2D plane. The angle of rotation can be specified in either degrees (default) or radians by setting ``use_radians=True``. Positive angles are counter-clockwise and negative are clockwise rotations. The point of origin can be a keyword ``'center'`` for the bounding box center (default), ``'centroid'`` for the geometry's centroid, a `Point` object or a coordinate tuple ``(x0, y0)``. The affine transformation matrix for 2D rotation with angle :math:`\theta` is: .. math:: \begin{bmatrix} \cos{\theta} & -\sin{\theta} & x_\mathrm{off} \\ \sin{\theta} & \cos{\theta} & y_\mathrm{off} \\ 0 & 0 & 1 \end{bmatrix} where the offsets are calculated from the origin :math:`(x_0, y_0)`: .. math:: x_\mathrm{off} &= x_0 - x_0 \cos{\theta} + y_0 \sin{\theta} \\ y_\mathrm{off} &= y_0 - x_0 \sin{\theta} - y_0 \cos{\theta} .. sourcecode:: pycon >>> from shapely import affinity >>> line = LineString([(1, 3), (1, 1), (4, 1)]) >>> rotated_a = affinity.rotate(line, 90) >>> rotated_b = affinity.rotate(line, 90, origin='centroid') .. plot:: code/rotate.py Figure 14. Rotation of a `LineString` (gray) by an angle of 90° counter-clockwise (blue) using different origins. .. function:: shapely.affinity.scale(geom, xfact=1.0, yfact=1.0, zfact=1.0, origin='center') Returns a scaled geometry, scaled by factors along each dimension. The point of origin can be a keyword ``'center'`` for the 2D bounding box center (default), ``'centroid'`` for the geometry's 2D centroid, a `Point` object or a coordinate tuple ``(x0, y0, z0)``. Negative scale factors will mirror or reflect coordinates. The general 3D affine transformation matrix for scaling is: .. math:: \begin{bmatrix} x_\mathrm{fact} & 0 & 0 & x_\mathrm{off} \\ 0 & y_\mathrm{fact} & 0 & y_\mathrm{off} \\ 0 & 0 & z_\mathrm{fact} & z_\mathrm{off} \\ 0 & 0 & 0 & 1 \end{bmatrix} where the offsets are calculated from the origin :math:`(x_0, y_0, z_0)`: .. math:: x_\mathrm{off} &= x_0 - x_0 x_\mathrm{fact} \\ y_\mathrm{off} &= y_0 - y_0 y_\mathrm{fact} \\ z_\mathrm{off} &= z_0 - z_0 z_\mathrm{fact} .. sourcecode:: pycon >>> triangle = Polygon([(1, 1), (2, 3), (3, 1)]) >>> triangle_a = affinity.scale(triangle, xfact=1.5, yfact=-1) >>> triangle_a.exterior.coords[:] [(0.5, 3.0), (2.0, 1.0), (3.5, 3.0), (0.5, 3.0)] >>> triangle_b = affinity.scale(triangle, xfact=2, origin=(1,1)) >>> triangle_b.exterior.coords[:] [(1.0, 1.0), (3.0, 3.0), (5.0, 1.0), (1.0, 1.0)] .. plot:: code/scale.py Figure 15. Scaling of a gray triangle to blue result: a) by a factor of 1.5 along x-direction, with reflection across y-axis; b) by a factor of 2 along x-direction with custom origin at (1, 1). .. function:: shapely.affinity.skew(geom, xs=0.0, ys=0.0, origin='center', use_radians=False) Returns a skewed geometry, sheared by angles along x and y dimensions. The shear angle can be specified in either degrees (default) or radians by setting ``use_radians=True``. The point of origin can be a keyword ``'center'`` for the bounding box center (default), ``'centroid'`` for the geometry's centroid, a `Point` object or a coordinate tuple ``(x0, y0)``. The general 2D affine transformation matrix for skewing is: .. math:: \begin{bmatrix} 1 & \tan{x_s} & x_\mathrm{off} \\ \tan{y_s} & 1 & y_\mathrm{off} \\ 0 & 0 & 1 \end{bmatrix} where the offsets are calculated from the origin :math:`(x_0, y_0)`: .. math:: x_\mathrm{off} &= -y_0 \tan{x_s} \\ y_\mathrm{off} &= -x_0 \tan{y_s} .. plot:: code/skew.py Figure 16. Skewing of a gray "R" to blue result: a) by a shear angle of 20° along the x-direction and an origin at (1, 1); b) by a shear angle of 30° along the y-direction, using default origin. .. function:: shapely.affinity.translate(geom, xoff=0.0, yoff=0.0, zoff=0.0) Returns a translated geometry shifted by offsets along each dimension. The general 3D affine transformation matrix for translation is: .. math:: \begin{bmatrix} 1 & 0 & 0 & x_\mathrm{off} \\ 0 & 1 & 0 & y_\mathrm{off} \\ 0 & 0 & 1 & z_\mathrm{off} \\ 0 & 0 & 0 & 1 \end{bmatrix} Other Transformations ===================== Shapely supports map projections and other arbitrary transformations of geometric objects. .. function:: shapely.ops.transform(func, geom) Applies `func` to all coordinates of `geom` and returns a new geometry of the same type from the transformed coordinates. `func` maps x, y, and optionally z to output xp, yp, zp. The input parameters may iterable types like lists or arrays or single values. The output shall be of the same type: scalars in, scalars out; lists in, lists out. `New in version 1.2.18`. For example, here is an identity function applicable to both types of input (scalar or array). .. sourcecode:: python def id_func(x, y, z=None): return tuple(filter(None, [x, y, z])) g2 = transform(id_func, g1) A partially applied transform function from pyproj satisfies the requirements for `func`. .. sourcecode:: python from functools import partial import pyproj project = partial( pyproj.transform, pyproj.Proj(init='espg:4326'), pyproj.Proj(init='epsg:26913')) g2 = transform(project, g1) Lambda expressions such as the one in .. sourcecode:: python g2 = transform(lambda x, y, z=None: (x+1.0, y+1.0), g1) also satisfy the requirements for `func`. Other Operations ================ Merging Linear Features ----------------------- Sequences of touching lines can be merged into `MultiLineStrings` or `Polygons` using functions in the :mod:`shapely.ops` module. .. function:: shapely.ops.polygonize(lines) Returns an iterator over polygons constructed from the input `lines`. As with the :class:`MultiLineString` constructor, the input elements may be any line-like object. .. sourcecode:: pycon >>> from shapely.ops import polygonize >>> lines = [ ... ((0, 0), (1, 1)), ... ((0, 0), (0, 1)), ... ((0, 1), (1, 1)), ... ((1, 1), (1, 0)), ... ((1, 0), (0, 0)) ... ] >>> pprint(list(polygonize(lines))) [, ] .. function:: shapely.ops.polygonize_full(lines) Creates polygons from a source of lines, returning the polygons and leftover geometries. The source may be a MultiLineString, a sequence of LineString objects, or a sequence of objects than can be adapted to LineStrings. Returns a tuple of objects: (polygons, dangles, cut edges, invalid ring lines). Each are a geometry collection. Dangles are edges which have one or both ends which are not incident on another edge endpoint. Cut edges are connected at both ends but do not form part of polygon. Invalid ring lines form rings which are invalid (bowties, etc). `New in version 1.2.18.` .. sourcecode:: pycon >>> lines = [ ... ((0, 0), (1, 1)), ... ((0, 0), (0, 1)), ... ((0, 1), (1, 1)), ... ((1, 1), (1, 0)), ... ((1, 0), (0, 0)), ... ((5, 5), (6, 6)), ... ((1, 1), (100, 100)), ... ] >>> result, dangles, cuts, invalids = polygonize_full(lines) >>> len(result) 2 >>> list(result.geoms) [, ] >>> list(cuts.geoms) [, ] .. function:: shapely.ops.linemerge(lines) Returns a `LineString` or `MultiLineString` representing the merger of all contiguous elements of `lines`. As with :func:`shapely.ops.polygonize`, the input elements may be any line-like object. .. sourcecode:: python >>> from shapely.ops import linemerge >>> linemerge(lines) >>> pprint(list(linemerge(lines))) [, , ] Cascading Unions ---------------- The :func:`~shapely.ops.cascaded_union` function in `shapely.ops` is more efficient than accumulating with :meth:`union`. .. plot:: code/cascaded_union.py .. function:: shapely.ops.cascaded_union(geoms) Returns a representation of the union of the given geometric objects. .. sourcecode:: pycon >>> from shapely.ops import cascaded_union >>> polygons = [Point(i, 0).buffer(0.7) for i in range(5)] >>> cascaded_union(polygons) The function is particularly useful in dissolving `MultiPolygons`. .. sourcecode:: pycon >>> m = MultiPolygon(polygons) >>> m.area 7.6845438018375516 >>> cascaded_union(m).area 6.6103013551167971 .. note:: In 1.2.16 :func:`shapely.ops.cascaded_union` is superceded by :func:`shapely.ops.unary_union` if GEOS 3.2+ is used. The unary union function can operate on different geometry types, not only polygons as is the case for the older cascaded unions. .. function:: shapely.ops.unary_union(geoms) Returns a representation of the union of the given geometric objects. Prepared Geometry Operations ---------------------------- Shapely geometries can be processed into a state that supports more efficient batches of operations. .. function:: prepared.prep(ob) Creates and returns a prepared geometric object. To test one polygon containment against a large batch of points, one should first use the :func:`prepared.prep` function. .. sourcecode:: pycon >>> from shapely.geometry import Point >>> from shapely.prepared import prep >>> points = [...] # large list of points >>> polygon = Point(0.0, 0.0).buffer(1.0) >>> prepared_polygon = prep(polygon) >>> prepared_polygon >>> hits = filter(prepared_polygon.contains, points) Prepared geometries instances have the following methods: ``contains``, ``contains_properly``, ``covers``, and ``intersects``. All have exactly the same arguments and usage as their counterparts in non-prepared geometric objects. Diagnostics ----------- .. function:: validation.explain_validity(ob): Returns a string explaining the validity or invalidity of the object. `New in version 1.2.1`. The messages may or may not have a representation of a problem point that can be parsed out. .. sourcecode:: pycon >>> coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)] >>> p = Polygon(coords) >>> from shapely.validation import explain_validity >>> explain_validity(p) 'Ring Self-intersection[1 1]' The Shapely version, GEOS library version, and GEOS C API version are accessible via :attr:`shapely.__version__`, :attr:`shapely.geos.geos_version_string`, and :attr:`shapely.geos.geos_capi_version`. .. sourcecode:: pycon >>> import shapely >>> shapely.__version__ '1.3.0' >>> import shapely.geos >>> shapely.geos.geos_version (3, 3, 0) >>> shapely.geos.geos_version_string '3.3.0-CAPI-1.7.0' Interoperation ============== Shapely provides 4 avenues for interoperation with other software. Well-Known Formats ------------------ A `Well Known Text` (WKT) or `Well Known Binary` (WKB) representation [1]_ of any geometric object can be had via its :attr:`wkt` or :attr:`wkb` attribute. These representations allow interchange with many GIS programs. PostGIS, for example, trades in hex-encoded WKB. .. sourcecode:: pycon >>> Point(0, 0).wkt 'POINT (0.0000000000000000 0.0000000000000000)' >>> Point(0, 0).wkb.encode('hex') '010100000000000000000000000000000000000000' The `shapely.wkt` and `shapely.wkb` modules provide `dumps()` and `loads()` functions that work almost exactly as their `pickle` and `simplejson` module counterparts. To serialize a geometric object to a binary or text string, use ``dumps()``. To deserialize a string and get a new geometric object of the appropriate type, use ``loads()``. .. function:: shapely.wkb.dumps(ob) Returns a WKB representation of `ob`. .. function:: shapely.wkb.loads(wkb) Returns a geometric object from a WKB representation `wkb`. .. sourcecode:: pycon >> from shapely.wkb import dumps, loads >>> wkb = dumps(Point(0, 0)) >>> print wkb.encode('hex') 010100000000000000000000000000000000000000 >>> loads(wkb).wkt 'POINT (0.0000000000000000 0.0000000000000000)' All of Shapely's geometry types are supported by these functions. .. function:: shapely.wkt.dumps(ob) Returns a WKT representation of `ob`. .. function:: shapely.wkt.loads(wkt) Returns a geometric object from a WKT representation `wkt`. .. sourcecode:: pycon >> wkt = dumps(Point(0, 0)) >>> print wkt POINT (0.0000000000000000 0.0000000000000000) >>> loads(wkt).wkt 'POINT (0.0000000000000000 0.0000000000000000)' Numpy and Python Arrays ----------------------- All geometric objects with coordinate sequences (`Point`, `LinearRing`, `LineString`) provide the Numpy array interface and can thereby be converted or adapted to Numpy arrays. .. sourcecode:: pycon >>> from numpy import array >>> array(Point(0, 0)) array([ 0., 0.]) >>> array(LineString([(0, 0), (1, 1)])) array([[ 0., 0.], [ 1., 1.]]) The :func:`numpy.asarray` function does not copy coordinate values – at the price of slower Numpy access to the coordinates of Shapely objects. .. note:: The Numpy array interface is provided without a dependency on Numpy itself. The coordinates of the same types of geometric objects can be had as standard Python arrays of `x` and `y` values via the :attr:`xy` attribute. .. sourcecode:: pycon >>> Point(0, 0).xy (array('d', [0.0]), array('d', [0.0])) >>> LineString([(0, 0), (1, 1)]).xy (array('d', [0.0, 1.0]), array('d', [0.0, 1.0])) The :func:`shapely.geometry.asShape` family of functions can be used to wrap Numpy coordinate arrays so that they can then be analyzed using Shapely while maintaining their original storage. A 1 x 2 array can be adapted to a point .. sourcecode:: pycon >>> from shapely.geometry import asPoint >>> pa = asPoint(array([0.0, 0.0])) >>> pa.wkt 'POINT (0.0000000000000000 0.0000000000000000)' and a N x 2 array can be adapted to a line string .. sourcecode:: pycon >>> from shapely.geometry import asLineString >>> la = asLineString(array([[1.0, 2.0], [3.0, 4.0]])) >>> la.wkt 'LINESTRING (1.0000000000000000 2.0000000000000000, 3.0000000000000000 4.0000000000000000)' There is no Numpy array representation of a polygon. Python Geo Interface -------------------- Any object that provides the GeoJSON-like `Python geo interface`_ can be adapted and used as a Shapely geometry using the :func:`shapely.geometry.asShape` or :func:`shapely.geometry.shape` functions. .. function:: shapely.geometry.asShape(context) Adapts the context to a geometry interface. The coordinates remain stored in the context. .. function:: shapely.geometry.shape(context) Returns a new, independent geometry with coordinates `copied` from the context. For example, a dictionary: .. sourcecode:: pycon >>> from shapely.geometry import asShape >>> d = {"type": "Point", "coordinates": (0.0, 0.0)} >>> shape = asShape(d) >>> shape.geom_type 'Point' >>> list(shape.coords) [(0.0, 0.0)] Or a simple placemark-type object: .. sourcecode:: pycon >>> class GeoThing(object): ... def __init__(self, d): ... self.__geo_interface__ = d >>> thing = GeoThing({"type": "Point", "coordinates": (0.0, 0.0)}) >>> shape = asShape(thing) >>> shape.geom_type 'Point' >>> list(shape.coords) [(0.0, 0.0)] The GeoJSON-like mapping of a geometric object can be obtained using :func:`shapely.geometry.mapping`. .. function:: shapely.geometry.mapping(ob) Returns a new, independent geometry with coordinates `copied` from the context. `New in version 1.2.3`. For example, using the same `GeoThing` class: .. sourcecode:: pycon >>> from shapely.geometry import mapping >>> thing = GeoThing({"type": "Point", "coordinates": (0.0, 0.0)}) >>> m = mapping(thing) >>> m['type'] 'Point' >>> m['coordinates'] (0.0, 0.0)} Performance =========== Shapely uses the GEOS_ library for all operations. GEOS is written in C++ and used in many applications and you can expect that all operations are highly optimized. The creation of new geometries with many coordinates, however, involves some overhead that might slow down your code. .. versionadded:: 1.2.10 The :mod:`shapely.speedups` module contains performance enhancements written in C. They are automaticaly installed when Python has access to a compiler and GEOS development headers during installation. You can check if the speedups are installed with the :attr:`available` attribute. The constructor speedups are disabled by default. To enable the speedups call :func:`enable`. You can revert to the default implementation with :func:`disable`. .. sourcecode:: pycon >>> from shapely import speedups >>> speedups.available True >>> speedups.enable() Conclusion ========== We hope that you will enjoy and profit from using Shapely. Questions and comments are welcome on the GIS-Python email list_. This manual will be updated and improved regularly. Its source is available at http://github.com/Toblerity/Shapely/tree/master/docs/. References ========== .. [1] John R. Herring, Ed., “OpenGIS Implementation Specification for Geographic information - Simple feature access - Part 1: Common architecture,” Oct. 2006. .. [2] M.J. Egenhofer and John R. Herring, Categorizing Binary Topological Relations Between Regions, Lines, and Points in Geographic Databases, Orono, ME: University of Maine, 1991. .. [3] E. Clementini, P. Di Felice, and P. van Oosterom, “A Small Set of Formal Topological Relationships Suitable for End-User Interaction,” Third International Symposium on Large Spatial Databases (SSD). Lecture Notes in Computer Science no. 692, David Abel and Beng Chin Ooi, Eds., Singapore: Springer Verlag, 1993, pp. 277-295. .. [4] C. Strobl, “Dimensionally Extended Nine-Intersection Model (DE-9IM),” Encyclopedia of GIS, S. Shekhar and H. Xiong, Eds., Springer, 2008, pp. 240-245. [|Strobl-PDF|_] .. [5] Martin Davis, “JTS Technical Specifications,” Mar. 2003. [|JTS-PDF|_] .. [6] David H. Douglas and Thomas K. Peucker, “Algorithms for the Reduction of the Number of Points Required to Represent a Digitized Line or its Caricature,” Cartographica: The International Journal for Geographic Information and Geovisualization, vol. 10, Dec. 1973, pp. 112-122. .. _GEOS: http://trac.osgeo.org/geos/ .. _Java Topology Suite: http://www.vividsolutions.com/jts/jtshome.htm .. _JTS: http://www.vividsolutions.com/jts/jtshome.htm .. _PostGIS: http://postgis.refractions.net .. _record: http://pypi.python.org/pypi/Shapely .. _wiki: http://trac.gispython.org/lab/wiki/Shapely .. _Open Geospatial Consortium: http://www.opengeospatial.org/ .. _Davis: http://lin-ear-th-inking.blogspot.com/2007/06/subtleties-of-ogc-covers-spatial.html .. _Understanding spatial relations: http://edndoc.esri.com/arcsde/9.1/general_topics/understand_spatial_relations.htm .. _Strobl-PDF: http://giswiki.hsr.ch/images/3/3d/9dem_springer.pdf .. |Strobl-PDF| replace:: PDF .. _JTS-PDF: http://www.vividsolutions.com/jts/bin/JTS%20Technical%20Specs.pdf .. |JTS-PDF| replace:: PDF .. _frozenset: http://docs.python.org/library/stdtypes.html#frozenset .. _Sorting HowTo: http://wiki.python.org/moin/HowTo/Sorting/ .. _Python geo interface: http://gist.github.com/2217756 .. _list: http://lists.gispython.org/mailman/listinfo/community Shapely-1.3.0/docs/project.txt000066400000000000000000000000711226057120100162510ustar00rootroot00000000000000.. include:: ../README.rst .. include:: ../CHANGES.txt Shapely-1.3.0/docs/sphinxext/000077500000000000000000000000001226057120100160765ustar00rootroot00000000000000Shapely-1.3.0/docs/sphinxext/apigen.py000066400000000000000000000364531226057120100177260ustar00rootroot00000000000000"""Attempt to generate templates for module reference with Sphinx XXX - we exclude extension modules To include extension modules, first identify them as valid in the ``_uri2path`` method, then handle them in the ``_parse_module`` script. We get functions and classes by parsing the text of .py files. Alternatively we could import the modules for discovery, and we'd have to do that for extension modules. This would involve changing the ``_parse_module`` method to work via import and introspection, and might involve changing ``discover_modules`` (which determines which files are modules, and therefore which module URIs will be passed to ``_parse_module``). NOTE: this is a modified version of a script originally shipped with the PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed project.""" # Stdlib imports import os import re # Functions and classes class ApiDocWriter(object): ''' Class for automatic detection and parsing of API docs to Sphinx-parsable reST format''' # only separating first two levels rst_section_levels = ['*', '=', '-', '~', '^'] def __init__(self, package_name, rst_extension='.rst', package_skip_patterns=None, module_skip_patterns=None, ): ''' Initialize package for parsing Parameters ---------- package_name : string Name of the top-level package. *package_name* must be the name of an importable package rst_extension : string, optional Extension for reST files, default '.rst' package_skip_patterns : None or sequence of {strings, regexps} Sequence of strings giving URIs of packages to be excluded Operates on the package path, starting at (including) the first dot in the package path, after *package_name* - so, if *package_name* is ``sphinx``, then ``sphinx.util`` will result in ``.util`` being passed for earching by these regexps. If is None, gives default. Default is: ['\.tests$'] module_skip_patterns : None or sequence Sequence of strings giving URIs of modules to be excluded Operates on the module name including preceding URI path, back to the first dot after *package_name*. For example ``sphinx.util.console`` results in the string to search of ``.util.console`` If is None, gives default. Default is: ['\.setup$', '\._'] ''' if package_skip_patterns is None: package_skip_patterns = ['\\.tests$'] if module_skip_patterns is None: module_skip_patterns = ['\\.setup$', '\\._'] self.package_name = package_name self.rst_extension = rst_extension self.package_skip_patterns = package_skip_patterns self.module_skip_patterns = module_skip_patterns def get_package_name(self): return self._package_name def set_package_name(self, package_name): ''' Set package_name >>> docwriter = ApiDocWriter('sphinx') >>> import sphinx >>> docwriter.root_path == sphinx.__path__[0] True >>> docwriter.package_name = 'docutils' >>> import docutils >>> docwriter.root_path == docutils.__path__[0] True ''' # It's also possible to imagine caching the module parsing here self._package_name = package_name self.root_module = __import__(package_name) self.root_path = self.root_module.__path__[0] self.written_modules = None package_name = property(get_package_name, set_package_name, None, 'get/set package_name') def _get_object_name(self, line): ''' Get second token in line >>> docwriter = ApiDocWriter('sphinx') >>> docwriter._get_object_name(" def func(): ") 'func' >>> docwriter._get_object_name(" class Klass(object): ") 'Klass' >>> docwriter._get_object_name(" class Klass: ") 'Klass' ''' name = line.split()[1].split('(')[0].strip() # in case we have classes which are not derived from object # ie. old style classes return name.rstrip(':') def _uri2path(self, uri): ''' Convert uri to absolute filepath Parameters ---------- uri : string URI of python module to return path for Returns ------- path : None or string Returns None if there is no valid path for this URI Otherwise returns absolute file system path for URI Examples -------- >>> docwriter = ApiDocWriter('sphinx') >>> import sphinx >>> modpath = sphinx.__path__[0] >>> res = docwriter._uri2path('sphinx.builder') >>> res == os.path.join(modpath, 'builder.py') True >>> res = docwriter._uri2path('sphinx') >>> res == os.path.join(modpath, '__init__.py') True >>> docwriter._uri2path('sphinx.does_not_exist') ''' if uri == self.package_name: return os.path.join(self.root_path, '__init__.py') path = uri.replace('.', os.path.sep) path = path.replace(self.package_name + os.path.sep, '') path = os.path.join(self.root_path, path) # XXX maybe check for extensions as well? if os.path.exists(path + '.py'): # file path += '.py' elif os.path.exists(os.path.join(path, '__init__.py')): path = os.path.join(path, '__init__.py') else: return None return path def _path2uri(self, dirpath): ''' Convert directory path to uri ''' relpath = dirpath.replace(self.root_path, self.package_name) if relpath.startswith(os.path.sep): relpath = relpath[1:] return relpath.replace(os.path.sep, '.') def _parse_module(self, uri): ''' Parse module defined in *uri* ''' filename = self._uri2path(uri) if filename is None: # nothing that we could handle here. return ([],[]) f = open(filename, 'rt') functions, classes = self._parse_lines(f) f.close() return functions, classes def _parse_lines(self, linesource): ''' Parse lines of text for functions and classes ''' functions = [] classes = [] for line in linesource: if line.startswith('def ') and line.count('('): # exclude private stuff name = self._get_object_name(line) if not name.startswith('_'): functions.append(name) elif line.startswith('class '): # exclude private stuff name = self._get_object_name(line) if not name.startswith('_'): classes.append(name) else: pass functions.sort() classes.sort() return functions, classes def generate_api_doc(self, uri): '''Make autodoc documentation template string for a module Parameters ---------- uri : string python location of module - e.g 'sphinx.builder' Returns ------- S : string Contents of API doc ''' # get the names of all classes and functions functions, classes = self._parse_module(uri) if not len(functions) and not len(classes): print 'WARNING: Empty -',uri # dbg return '' # Make a shorter version of the uri that omits the package name for # titles uri_short = re.sub(r'^%s\.' % self.package_name,'',uri) ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' chap_title = uri_short ad += (chap_title+'\n'+ self.rst_section_levels[1] * len(chap_title) + '\n\n') # Set the chapter title to read 'module' for all modules except for the # main packages if '.' in uri: title = 'Module: :mod:`' + uri_short + '`' else: title = ':mod:`' + uri_short + '`' ad += title + '\n' + self.rst_section_levels[2] * len(title) if len(classes): ad += '\nInheritance diagram for ``%s``:\n\n' % uri ad += '.. inheritance-diagram:: %s \n' % uri ad += ' :parts: 3\n' ad += '\n.. automodule:: ' + uri + '\n' ad += '\n.. currentmodule:: ' + uri + '\n' multi_class = len(classes) > 1 multi_fx = len(functions) > 1 if multi_class: ad += '\n' + 'Classes' + '\n' + \ self.rst_section_levels[2] * 7 + '\n' elif len(classes) and multi_fx: ad += '\n' + 'Class' + '\n' + \ self.rst_section_levels[2] * 5 + '\n' for c in classes: ad += '\n:class:`' + c + '`\n' \ + self.rst_section_levels[multi_class + 2 ] * \ (len(c)+9) + '\n\n' ad += '\n.. autoclass:: ' + c + '\n' # must NOT exclude from index to keep cross-refs working ad += ' :members:\n' \ ' :undoc-members:\n' \ ' :show-inheritance:\n' \ ' :inherited-members:\n' \ '\n' \ ' .. automethod:: __init__\n' if multi_fx: ad += '\n' + 'Functions' + '\n' + \ self.rst_section_levels[2] * 9 + '\n\n' elif len(functions) and multi_class: ad += '\n' + 'Function' + '\n' + \ self.rst_section_levels[2] * 8 + '\n\n' for f in functions: # must NOT exclude from index to keep cross-refs working ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n' return ad def _survives_exclude(self, matchstr, match_type): ''' Returns True if *matchstr* does not match patterns ``self.package_name`` removed from front of string if present Examples -------- >>> dw = ApiDocWriter('sphinx') >>> dw._survives_exclude('sphinx.okpkg', 'package') True >>> dw.package_skip_patterns.append('^\\.badpkg$') >>> dw._survives_exclude('sphinx.badpkg', 'package') False >>> dw._survives_exclude('sphinx.badpkg', 'module') True >>> dw._survives_exclude('sphinx.badmod', 'module') True >>> dw.module_skip_patterns.append('^\\.badmod$') >>> dw._survives_exclude('sphinx.badmod', 'module') False ''' if match_type == 'module': patterns = self.module_skip_patterns elif match_type == 'package': patterns = self.package_skip_patterns else: raise ValueError('Cannot interpret match type "%s"' % match_type) # Match to URI without package name L = len(self.package_name) if matchstr[:L] == self.package_name: matchstr = matchstr[L:] for pat in patterns: try: pat.search except AttributeError: pat = re.compile(pat) if pat.search(matchstr): return False return True def discover_modules(self): ''' Return module sequence discovered from ``self.package_name`` Parameters ---------- None Returns ------- mods : sequence Sequence of module names within ``self.package_name`` Examples -------- >>> dw = ApiDocWriter('sphinx') >>> mods = dw.discover_modules() >>> 'sphinx.util' in mods True >>> dw.package_skip_patterns.append('\.util$') >>> 'sphinx.util' in dw.discover_modules() False >>> ''' modules = [self.package_name] # raw directory parsing for dirpath, dirnames, filenames in os.walk(self.root_path): # Check directory names for packages root_uri = self._path2uri(os.path.join(self.root_path, dirpath)) for dirname in dirnames[:]: # copy list - we modify inplace package_uri = '.'.join((root_uri, dirname)) if (self._uri2path(package_uri) and self._survives_exclude(package_uri, 'package')): modules.append(package_uri) else: dirnames.remove(dirname) # Check filenames for modules for filename in filenames: module_name = filename[:-3] module_uri = '.'.join((root_uri, module_name)) if (self._uri2path(module_uri) and self._survives_exclude(module_uri, 'module')): modules.append(module_uri) return sorted(modules) def write_modules_api(self, modules,outdir): # write the list written_modules = [] for m in modules: api_str = self.generate_api_doc(m) if not api_str: continue # write out to file outfile = os.path.join(outdir, m + self.rst_extension) fileobj = open(outfile, 'wt') fileobj.write(api_str) fileobj.close() written_modules.append(m) self.written_modules = written_modules def write_api_docs(self, outdir): """Generate API reST files. Parameters ---------- outdir : string Directory name in which to store files We create automatic filenames for each module Returns ------- None Notes ----- Sets self.written_modules to list of written modules """ if not os.path.exists(outdir): os.mkdir(outdir) # compose list of modules modules = self.discover_modules() self.write_modules_api(modules,outdir) def write_index(self, outdir, froot='gen', relative_to=None): """Make a reST API index file from written files Parameters ---------- path : string Filename to write index to outdir : string Directory to which to write generated index file froot : string, optional root (filename without extension) of filename to write to Defaults to 'gen'. We add ``self.rst_extension``. relative_to : string path to which written filenames are relative. This component of the written file path will be removed from outdir, in the generated index. Default is None, meaning, leave path as it is. """ if self.written_modules is None: raise ValueError('No modules written') # Get full filename path path = os.path.join(outdir, froot+self.rst_extension) # Path written into index is relative to rootpath if relative_to is not None: relpath = outdir.replace(relative_to + os.path.sep, '') else: relpath = outdir idx = open(path,'wt') w = idx.write w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n') w('.. toctree::\n\n') for f in self.written_modules: w(' %s\n' % os.path.join(relpath,f)) idx.close() Shapely-1.3.0/docs/sphinxext/docscrape.py000066400000000000000000000347661226057120100204330ustar00rootroot00000000000000"""Extract reference documentation from the NumPy source tree. """ import inspect import textwrap import re import pydoc from StringIO import StringIO from warnings import warn 4 class Reader(object): """A line-based string reader. """ def __init__(self, data): """ Parameters ---------- data : str String with lines separated by '\n'. """ if isinstance(data,list): self._str = data else: self._str = data.split('\n') # store string as list of lines self.reset() def __getitem__(self, n): return self._str[n] def reset(self): self._l = 0 # current line nr def read(self): if not self.eof(): out = self[self._l] self._l += 1 return out else: return '' def seek_next_non_empty_line(self): for l in self[self._l:]: if l.strip(): break else: self._l += 1 def eof(self): return self._l >= len(self._str) def read_to_condition(self, condition_func): start = self._l for line in self[start:]: if condition_func(line): return self[start:self._l] self._l += 1 if self.eof(): return self[start:self._l+1] return [] def read_to_next_empty_line(self): self.seek_next_non_empty_line() def is_empty(line): return not line.strip() return self.read_to_condition(is_empty) def read_to_next_unindented_line(self): def is_unindented(line): return (line.strip() and (len(line.lstrip()) == len(line))) return self.read_to_condition(is_unindented) def peek(self,n=0): if self._l + n < len(self._str): return self[self._l + n] else: return '' def is_empty(self): return not ''.join(self._str).strip() class NumpyDocString(object): def __init__(self,docstring): docstring = textwrap.dedent(docstring).split('\n') self._doc = Reader(docstring) self._parsed_data = { 'Signature': '', 'Summary': [''], 'Extended Summary': [], 'Parameters': [], 'Returns': [], 'Raises': [], 'Warns': [], 'Other Parameters': [], 'Attributes': [], 'Methods': [], 'See Also': [], 'Notes': [], 'Warnings': [], 'References': '', 'Examples': '', 'index': {} } self._parse() def __getitem__(self,key): return self._parsed_data[key] def __setitem__(self,key,val): if not self._parsed_data.has_key(key): warn("Unknown section %s" % key) else: self._parsed_data[key] = val def _is_at_section(self): self._doc.seek_next_non_empty_line() if self._doc.eof(): return False l1 = self._doc.peek().strip() # e.g. Parameters if l1.startswith('.. index::'): return True l2 = self._doc.peek(1).strip() # ---------- or ========== return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) def _strip(self,doc): i = 0 j = 0 for i,line in enumerate(doc): if line.strip(): break for j,line in enumerate(doc[::-1]): if line.strip(): break return doc[i:len(doc)-j] def _read_to_next_section(self): section = self._doc.read_to_next_empty_line() while not self._is_at_section() and not self._doc.eof(): if not self._doc.peek(-1).strip(): # previous line was empty section += [''] section += self._doc.read_to_next_empty_line() return section def _read_sections(self): while not self._doc.eof(): data = self._read_to_next_section() name = data[0].strip() if name.startswith('..'): # index section yield name, data[1:] elif len(data) < 2: yield StopIteration else: yield name, self._strip(data[2:]) def _parse_param_list(self,content): r = Reader(content) params = [] while not r.eof(): header = r.read().strip() if ' : ' in header: arg_name, arg_type = header.split(' : ')[:2] else: arg_name, arg_type = header, '' desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) params.append((arg_name,arg_type,desc)) return params _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) def _parse_see_also(self, content): """ func_name : Descriptive text continued text another_func_name : Descriptive text func_name1, func_name2, :meth:`func_name`, func_name3 """ items = [] def parse_item_name(text): """Match ':role:`name`' or 'name'""" m = self._name_rgx.match(text) if m: g = m.groups() if g[1] is None: return g[3], None else: return g[2], g[1] raise ValueError("%s is not a item name" % text) def push_item(name, rest): if not name: return name, role = parse_item_name(name) items.append((name, list(rest), role)) del rest[:] current_func = None rest = [] for line in content: if not line.strip(): continue m = self._name_rgx.match(line) if m and line[m.end():].strip().startswith(':'): push_item(current_func, rest) current_func, line = line[:m.end()], line[m.end():] rest = [line.split(':', 1)[1].strip()] if not rest[0]: rest = [] elif not line.startswith(' '): push_item(current_func, rest) current_func = None if ',' in line: for func in line.split(','): push_item(func, []) elif line.strip(): current_func = line elif current_func is not None: rest.append(line.strip()) push_item(current_func, rest) return items def _parse_index(self, section, content): """ .. index: default :refguide: something, else, and more """ def strip_each_in(lst): return [s.strip() for s in lst] out = {} section = section.split('::') if len(section) > 1: out['default'] = strip_each_in(section[1].split(','))[0] for line in content: line = line.split(':') if len(line) > 2: out[line[1]] = strip_each_in(line[2].split(',')) return out def _parse_summary(self): """Grab signature (if given) and summary""" if self._is_at_section(): return summary = self._doc.read_to_next_empty_line() summary_str = " ".join([s.strip() for s in summary]).strip() if re.compile('^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): self['Signature'] = summary_str if not self._is_at_section(): self['Summary'] = self._doc.read_to_next_empty_line() else: self['Summary'] = summary if not self._is_at_section(): self['Extended Summary'] = self._read_to_next_section() def _parse(self): self._doc.reset() self._parse_summary() for (section,content) in self._read_sections(): if not section.startswith('..'): section = ' '.join([s.capitalize() for s in section.split(' ')]) if section in ('Parameters', 'Attributes', 'Methods', 'Returns', 'Raises', 'Warns'): self[section] = self._parse_param_list(content) elif section.startswith('.. index::'): self['index'] = self._parse_index(section, content) elif section == 'See Also': self['See Also'] = self._parse_see_also(content) else: self[section] = content # string conversion routines def _str_header(self, name, symbol='-'): return [name, len(name)*symbol] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): if self['Signature']: return [self['Signature'].replace('*','\*')] + [''] else: return [''] def _str_summary(self): if self['Summary']: return self['Summary'] + [''] else: return [] def _str_extended_summary(self): if self['Extended Summary']: return self['Extended Summary'] + [''] else: return [] def _str_param_list(self, name): out = [] if self[name]: out += self._str_header(name) for param,param_type,desc in self[name]: out += ['%s : %s' % (param, param_type)] out += self._str_indent(desc) out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += self[name] out += [''] return out def _str_see_also(self, func_role): if not self['See Also']: return [] out = [] out += self._str_header("See Also") last_had_desc = True for func, desc, role in self['See Also']: if role: link = ':%s:`%s`' % (role, func) elif func_role: link = ':%s:`%s`' % (func_role, func) else: link = "`%s`_" % func if desc or last_had_desc: out += [''] out += [link] else: out[-1] += ", %s" % link if desc: out += self._str_indent([' '.join(desc)]) last_had_desc = True else: last_had_desc = False out += [''] return out def _str_index(self): idx = self['index'] out = [] out += ['.. index:: %s' % idx.get('default','')] for section, references in idx.iteritems(): if section == 'default': continue out += [' :%s: %s' % (section, ', '.join(references))] return out def __str__(self, func_role=''): out = [] out += self._str_signature() out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters','Returns','Raises'): out += self._str_param_list(param_list) out += self._str_section('Warnings') out += self._str_see_also(func_role) for s in ('Notes','References','Examples'): out += self._str_section(s) out += self._str_index() return '\n'.join(out) def indent(str,indent=4): indent_str = ' '*indent if str is None: return indent_str lines = str.split('\n') return '\n'.join(indent_str + l for l in lines) def dedent_lines(lines): """Deindent a list of lines maximally""" return textwrap.dedent("\n".join(lines)).split("\n") def header(text, style='-'): return text + '\n' + style*len(text) + '\n' class FunctionDoc(NumpyDocString): def __init__(self, func, role='func', doc=None): self._f = func self._role = role # e.g. "func" or "meth" if doc is None: doc = inspect.getdoc(func) or '' try: NumpyDocString.__init__(self, doc) except ValueError, e: print '*'*78 print "ERROR: '%s' while parsing `%s`" % (e, self._f) print '*'*78 #print "Docstring follows:" #print doclines #print '='*78 if not self['Signature']: func, func_name = self.get_func() try: # try to read signature argspec = inspect.getargspec(func) argspec = inspect.formatargspec(*argspec) argspec = argspec.replace('*','\*') signature = '%s%s' % (func_name, argspec) except TypeError, e: signature = '%s()' % func_name self['Signature'] = signature def get_func(self): func_name = getattr(self._f, '__name__', self.__class__.__name__) if inspect.isclass(self._f): func = getattr(self._f, '__call__', self._f.__init__) else: func = self._f return func, func_name def __str__(self): out = '' func, func_name = self.get_func() signature = self['Signature'].replace('*', '\*') roles = {'func': 'function', 'meth': 'method'} if self._role: if not roles.has_key(self._role): print "Warning: invalid role %s" % self._role out += '.. %s:: %s\n \n\n' % (roles.get(self._role,''), func_name) out += super(FunctionDoc, self).__str__(func_role=self._role) return out class ClassDoc(NumpyDocString): def __init__(self,cls,modulename='',func_doc=FunctionDoc,doc=None): if not inspect.isclass(cls): raise ValueError("Initialise using a class. Got %r" % cls) self._cls = cls if modulename and not modulename.endswith('.'): modulename += '.' self._mod = modulename self._name = cls.__name__ self._func_doc = func_doc if doc is None: doc = pydoc.getdoc(cls) NumpyDocString.__init__(self, doc) @property def methods(self): return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and callable(func)] def __str__(self): out = '' out += super(ClassDoc, self).__str__() out += "\n\n" #for m in self.methods: # print "Parsing `%s`" % m # out += str(self._func_doc(getattr(self._cls,m), 'meth')) + '\n\n' # out += '.. index::\n single: %s; %s\n\n' % (self._name, m) return out Shapely-1.3.0/docs/sphinxext/docscrape_sphinx.py000066400000000000000000000102071226057120100220040ustar00rootroot00000000000000import re, inspect, textwrap, pydoc from docscrape import NumpyDocString, FunctionDoc, ClassDoc class SphinxDocString(NumpyDocString): # string conversion routines def _str_header(self, name, symbol='`'): return ['.. rubric:: ' + name, ''] def _str_field_list(self, name): return [':' + name + ':'] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): return [''] if self['Signature']: return ['``%s``' % self['Signature']] + [''] else: return [''] def _str_summary(self): return self['Summary'] + [''] def _str_extended_summary(self): return self['Extended Summary'] + [''] def _str_param_list(self, name): out = [] if self[name]: out += self._str_field_list(name) out += [''] for param,param_type,desc in self[name]: out += self._str_indent(['**%s** : %s' % (param.strip(), param_type)]) out += [''] out += self._str_indent(desc,8) out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += [''] content = textwrap.dedent("\n".join(self[name])).split("\n") out += content out += [''] return out def _str_see_also(self, func_role): out = [] if self['See Also']: see_also = super(SphinxDocString, self)._str_see_also(func_role) out = ['.. seealso::', ''] out += self._str_indent(see_also[2:]) return out def _str_warnings(self): out = [] if self['Warnings']: out = ['.. warning::', ''] out += self._str_indent(self['Warnings']) return out def _str_index(self): idx = self['index'] out = [] if len(idx) == 0: return out out += ['.. index:: %s' % idx.get('default','')] for section, references in idx.iteritems(): if section == 'default': continue elif section == 'refguide': out += [' single: %s' % (', '.join(references))] else: out += [' %s: %s' % (section, ','.join(references))] return out def _str_references(self): out = [] if self['References']: out += self._str_header('References') if isinstance(self['References'], str): self['References'] = [self['References']] out.extend(self['References']) out += [''] return out def __str__(self, indent=0, func_role="obj"): out = [] out += self._str_signature() out += self._str_index() + [''] out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters', 'Attributes', 'Methods', 'Returns','Raises'): out += self._str_param_list(param_list) out += self._str_warnings() out += self._str_see_also(func_role) out += self._str_section('Notes') out += self._str_references() out += self._str_section('Examples') out = self._str_indent(out,indent) return '\n'.join(out) class SphinxFunctionDoc(SphinxDocString, FunctionDoc): pass class SphinxClassDoc(SphinxDocString, ClassDoc): pass def get_doc_object(obj, what=None, doc=None): if what is None: if inspect.isclass(obj): what = 'class' elif inspect.ismodule(obj): what = 'module' elif callable(obj): what = 'function' else: what = 'object' if what == 'class': return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc, doc=doc) elif what in ('function', 'method'): return SphinxFunctionDoc(obj, '', doc=doc) else: if doc is None: doc = pydoc.getdoc(obj) return SphinxDocString(doc) Shapely-1.3.0/docs/sphinxext/inheritance_diagram.py000066400000000000000000000325201226057120100224270ustar00rootroot00000000000000""" Defines a docutils directive for inserting inheritance diagrams. Provide the directive with one or more classes or modules (separated by whitespace). For modules, all of the classes in that module will be used. Example:: Given the following classes: class A: pass class B(A): pass class C(A): pass class D(B, C): pass class E(B): pass .. inheritance-diagram: D E Produces a graph like the following: A / \ B C / \ / E D The graph is inserted as a PNG+image map into HTML and a PDF in LaTeX. """ import inspect import os import re import subprocess try: from hashlib import md5 except ImportError: from md5 import md5 from docutils.nodes import Body, Element from docutils.parsers.rst import directives from sphinx.roles import xfileref_role def my_import(name): """Module importer - taken from the python documentation. This function allows importing names with dots in them.""" mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod class DotException(Exception): pass class InheritanceGraph(object): """ Given a list of classes, determines the set of classes that they inherit from all the way to the root "object", and then is able to generate a graphviz dot graph from them. """ def __init__(self, class_names, show_builtins=False): """ *class_names* is a list of child classes to show bases from. If *show_builtins* is True, then Python builtins will be shown in the graph. """ self.class_names = class_names self.classes = self._import_classes(class_names) self.all_classes = self._all_classes(self.classes) if len(self.all_classes) == 0: raise ValueError("No classes found for inheritance diagram") self.show_builtins = show_builtins py_sig_re = re.compile(r'''^([\w.]*\.)? # class names (\w+) \s* $ # optionally arguments ''', re.VERBOSE) def _import_class_or_module(self, name): """ Import a class using its fully-qualified *name*. """ try: path, base = self.py_sig_re.match(name).groups() except: raise ValueError( "Invalid class or module '%s' specified for inheritance diagram" % name) fullname = (path or '') + base path = (path and path.rstrip('.')) if not path: path = base try: module = __import__(path, None, None, []) # We must do an import of the fully qualified name. Otherwise if a # subpackage 'a.b' is requested where 'import a' does NOT provide # 'a.b' automatically, then 'a.b' will not be found below. This # second call will force the equivalent of 'import a.b' to happen # after the top-level import above. my_import(fullname) except ImportError: raise ValueError( "Could not import class or module '%s' specified for inheritance diagram" % name) try: todoc = module for comp in fullname.split('.')[1:]: todoc = getattr(todoc, comp) except AttributeError: raise ValueError( "Could not find class or module '%s' specified for inheritance diagram" % name) # If a class, just return it if inspect.isclass(todoc): return [todoc] elif inspect.ismodule(todoc): classes = [] for cls in todoc.__dict__.values(): if inspect.isclass(cls) and cls.__module__ == todoc.__name__: classes.append(cls) return classes raise ValueError( "'%s' does not resolve to a class or module" % name) def _import_classes(self, class_names): """ Import a list of classes. """ classes = [] for name in class_names: classes.extend(self._import_class_or_module(name)) return classes def _all_classes(self, classes): """ Return a list of all classes that are ancestors of *classes*. """ all_classes = {} def recurse(cls): all_classes[cls] = None for c in cls.__bases__: if c not in all_classes: recurse(c) for cls in classes: recurse(cls) return all_classes.keys() def class_name(self, cls, parts=0): """ Given a class object, return a fully-qualified name. This works for things I've tested in matplotlib so far, but may not be completely general. """ module = cls.__module__ if module == '__builtin__': fullname = cls.__name__ else: fullname = "%s.%s" % (module, cls.__name__) if parts == 0: return fullname name_parts = fullname.split('.') return '.'.join(name_parts[-parts:]) def get_all_class_names(self): """ Get all of the class names involved in the graph. """ return [self.class_name(x) for x in self.all_classes] # These are the default options for graphviz default_graph_options = { "rankdir": "LR", "size": '"8.0, 12.0"' } default_node_options = { "shape": "box", "fontsize": 10, "height": 0.25, "fontname": "Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans", "style": '"setlinewidth(0.5)"' } default_edge_options = { "arrowsize": 0.5, "style": '"setlinewidth(0.5)"' } def _format_node_options(self, options): return ','.join(["%s=%s" % x for x in options.items()]) def _format_graph_options(self, options): return ''.join(["%s=%s;\n" % x for x in options.items()]) def generate_dot(self, fd, name, parts=0, urls={}, graph_options={}, node_options={}, edge_options={}): """ Generate a graphviz dot graph from the classes that were passed in to __init__. *fd* is a Python file-like object to write to. *name* is the name of the graph *urls* is a dictionary mapping class names to http urls *graph_options*, *node_options*, *edge_options* are dictionaries containing key/value pairs to pass on as graphviz properties. """ g_options = self.default_graph_options.copy() g_options.update(graph_options) n_options = self.default_node_options.copy() n_options.update(node_options) e_options = self.default_edge_options.copy() e_options.update(edge_options) fd.write('digraph %s {\n' % name) fd.write(self._format_graph_options(g_options)) for cls in self.all_classes: if not self.show_builtins and cls in __builtins__.values(): continue name = self.class_name(cls, parts) # Write the node this_node_options = n_options.copy() url = urls.get(self.class_name(cls)) if url is not None: this_node_options['URL'] = '"%s"' % url fd.write(' "%s" [%s];\n' % (name, self._format_node_options(this_node_options))) # Write the edges for base in cls.__bases__: if not self.show_builtins and base in __builtins__.values(): continue base_name = self.class_name(base, parts) fd.write(' "%s" -> "%s" [%s];\n' % (base_name, name, self._format_node_options(e_options))) fd.write('}\n') def run_dot(self, args, name, parts=0, urls={}, graph_options={}, node_options={}, edge_options={}): """ Run graphviz 'dot' over this graph, returning whatever 'dot' writes to stdout. *args* will be passed along as commandline arguments. *name* is the name of the graph *urls* is a dictionary mapping class names to http urls Raises DotException for any of the many os and installation-related errors that may occur. """ try: dot = subprocess.Popen(['dot'] + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True) except OSError: raise DotException("Could not execute 'dot'. Are you sure you have 'graphviz' installed?") except ValueError: raise DotException("'dot' called with invalid arguments") except: raise DotException("Unexpected error calling 'dot'") self.generate_dot(dot.stdin, name, parts, urls, graph_options, node_options, edge_options) dot.stdin.close() result = dot.stdout.read() returncode = dot.wait() if returncode != 0: raise DotException("'dot' returned the errorcode %d" % returncode) return result class inheritance_diagram(Body, Element): """ A docutils node to use as a placeholder for the inheritance diagram. """ pass def inheritance_diagram_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """ Run when the inheritance_diagram directive is first encountered. """ node = inheritance_diagram() class_names = arguments # Create a graph starting with the list of classes graph = InheritanceGraph(class_names) # Create xref nodes for each target of the graph's image map and # add them to the doc tree so that Sphinx can resolve the # references to real URLs later. These nodes will eventually be # removed from the doctree after we're done with them. for name in graph.get_all_class_names(): refnodes, x = xfileref_role( 'class', ':class:`%s`' % name, name, 0, state) node.extend(refnodes) # Store the graph object so we can use it to generate the # dot file later node['graph'] = graph # Store the original content for use as a hash node['parts'] = options.get('parts', 0) node['content'] = " ".join(class_names) return [node] def get_graph_hash(node): return md5(node['content'] + str(node['parts'])).hexdigest()[-10:] def html_output_graph(self, node): """ Output the graph for HTML. This will insert a PNG with clickable image map. """ graph = node['graph'] parts = node['parts'] graph_hash = get_graph_hash(node) name = "inheritance%s" % graph_hash path = '_images' dest_path = os.path.join(setup.app.builder.outdir, path) if not os.path.exists(dest_path): os.makedirs(dest_path) png_path = os.path.join(dest_path, name + ".png") path = setup.app.builder.imgpath # Create a mapping from fully-qualified class names to URLs. urls = {} for child in node: if child.get('refuri') is not None: urls[child['reftitle']] = child.get('refuri') elif child.get('refid') is not None: urls[child['reftitle']] = '#' + child.get('refid') # These arguments to dot will save a PNG file to disk and write # an HTML image map to stdout. image_map = graph.run_dot(['-Tpng', '-o%s' % png_path, '-Tcmapx'], name, parts, urls) return ('%s' % (path, name, name, image_map)) def latex_output_graph(self, node): """ Output the graph for LaTeX. This will insert a PDF. """ graph = node['graph'] parts = node['parts'] graph_hash = get_graph_hash(node) name = "inheritance%s" % graph_hash dest_path = os.path.abspath(os.path.join(setup.app.builder.outdir, '_images')) if not os.path.exists(dest_path): os.makedirs(dest_path) pdf_path = os.path.abspath(os.path.join(dest_path, name + ".pdf")) graph.run_dot(['-Tpdf', '-o%s' % pdf_path], name, parts, graph_options={'size': '"6.0,6.0"'}) return '\n\\includegraphics{%s}\n\n' % pdf_path def visit_inheritance_diagram(inner_func): """ This is just a wrapper around html/latex_output_graph to make it easier to handle errors and insert warnings. """ def visitor(self, node): try: content = inner_func(self, node) except DotException, e: # Insert the exception as a warning in the document warning = self.document.reporter.warning(str(e), line=node.line) warning.parent = node node.children = [warning] else: source = self.document.attributes['source'] self.body.append(content) node.children = [] return visitor def do_nothing(self, node): pass def setup(app): setup.app = app setup.confdir = app.confdir app.add_node( inheritance_diagram, latex=(visit_inheritance_diagram(latex_output_graph), do_nothing), html=(visit_inheritance_diagram(html_output_graph), do_nothing)) app.add_directive( 'inheritance-diagram', inheritance_diagram_directive, False, (1, 100, 0), parts = directives.nonnegative_int) Shapely-1.3.0/docs/sphinxext/ipython_console_highlighting.py000066400000000000000000000101271226057120100244120ustar00rootroot00000000000000"""reST directive for syntax-highlighting ipython interactive sessions. XXX - See what improvements can be made based on the new (as of Sept 2009) 'pycon' lexer for the python console. At the very least it will give better highlighted tracebacks. """ #----------------------------------------------------------------------------- # Needed modules # Standard library import re # Third party from pygments.lexer import Lexer, do_insertions from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, PythonTracebackLexer) from pygments.token import Comment, Generic from sphinx import highlighting #----------------------------------------------------------------------------- # Global constants line_re = re.compile('.*?\n') #----------------------------------------------------------------------------- # Code begins - classes and functions class IPythonConsoleLexer(Lexer): """ For IPython console output or doctests, such as: .. sourcecode:: ipython In [1]: a = 'foo' In [2]: a Out[2]: 'foo' In [3]: print a foo In [4]: 1 / 0 Notes: - Tracebacks are not currently supported. - It assumes the default IPython prompts, not customized ones. """ name = 'IPython console session' aliases = ['ipython'] mimetypes = ['text/x-ipython-console'] input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)") output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)") continue_prompt = re.compile(" \.\.\.+:") tb_start = re.compile("\-+") def get_tokens_unprocessed(self, text): pylexer = PythonLexer(**self.options) tblexer = PythonTracebackLexer(**self.options) curcode = '' insertions = [] for match in line_re.finditer(text): line = match.group() input_prompt = self.input_prompt.match(line) continue_prompt = self.continue_prompt.match(line.rstrip()) output_prompt = self.output_prompt.match(line) if line.startswith("#"): insertions.append((len(curcode), [(0, Comment, line)])) elif input_prompt is not None: insertions.append((len(curcode), [(0, Generic.Prompt, input_prompt.group())])) curcode += line[input_prompt.end():] elif continue_prompt is not None: insertions.append((len(curcode), [(0, Generic.Prompt, continue_prompt.group())])) curcode += line[continue_prompt.end():] elif output_prompt is not None: # Use the 'error' token for output. We should probably make # our own token, but error is typicaly in a bright color like # red, so it works fine for our output prompts. insertions.append((len(curcode), [(0, Generic.Error, output_prompt.group())])) curcode += line[output_prompt.end():] else: if curcode: for item in do_insertions(insertions, pylexer.get_tokens_unprocessed(curcode)): yield item curcode = '' insertions = [] yield match.start(), Generic.Output, line if curcode: for item in do_insertions(insertions, pylexer.get_tokens_unprocessed(curcode)): yield item def setup(app): """Setup as a sphinx extension.""" # This is only a lexer, so adding it below to pygments appears sufficient. # But if somebody knows that the right API usage should be to do that via # sphinx, by all means fix it here. At least having this setup.py # suppresses the sphinx warning we'd get without it. pass #----------------------------------------------------------------------------- # Register the extension as a valid pygments lexer highlighting.lexers['ipython'] = IPythonConsoleLexer() Shapely-1.3.0/docs/sphinxext/numpydoc.py000066400000000000000000000077321226057120100203170ustar00rootroot00000000000000""" ======== numpydoc ======== Sphinx extension that handles docstrings in the Numpy standard format. [1] It will: - Convert Parameters etc. sections to field lists. - Convert See Also section to a See also entry. - Renumber references. - Extract the signature from the docstring, if it can't be determined otherwise. .. [1] http://projects.scipy.org/scipy/numpy/wiki/CodingStyleGuidelines#docstring-standard """ import os, re, pydoc from docscrape_sphinx import get_doc_object, SphinxDocString import inspect def mangle_docstrings(app, what, name, obj, options, lines, reference_offset=[0]): if what == 'module': # Strip top title title_re = re.compile(r'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*', re.I|re.S) lines[:] = title_re.sub('', "\n".join(lines)).split("\n") else: doc = get_doc_object(obj, what, "\n".join(lines)) lines[:] = str(doc).split("\n") if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \ obj.__name__: if hasattr(obj, '__module__'): v = dict(full_name="%s.%s" % (obj.__module__, obj.__name__)) else: v = dict(full_name=obj.__name__) lines += ['', '.. htmlonly::', ''] lines += [' %s' % x for x in (app.config.numpydoc_edit_link % v).split("\n")] # replace reference numbers so that there are no duplicates references = [] for l in lines: l = l.strip() if l.startswith('.. ['): try: references.append(int(l[len('.. ['):l.index(']')])) except ValueError: print "WARNING: invalid reference in %s docstring" % name # Start renaming from the biggest number, otherwise we may # overwrite references. references.sort() if references: for i, line in enumerate(lines): for r in references: new_r = reference_offset[0] + r lines[i] = lines[i].replace('[%d]_' % r, '[%d]_' % new_r) lines[i] = lines[i].replace('.. [%d]' % r, '.. [%d]' % new_r) reference_offset[0] += len(references) def mangle_signature(app, what, name, obj, options, sig, retann): # Do not try to inspect classes that don't define `__init__` if (inspect.isclass(obj) and 'initializes x; see ' in pydoc.getdoc(obj.__init__)): return '', '' if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): return if not hasattr(obj, '__doc__'): return doc = SphinxDocString(pydoc.getdoc(obj)) if doc['Signature']: sig = re.sub("^[^(]*", "", doc['Signature']) return sig, '' def initialize(app): try: app.connect('autodoc-process-signature', mangle_signature) except: monkeypatch_sphinx_ext_autodoc() def setup(app, get_doc_object_=get_doc_object): global get_doc_object get_doc_object = get_doc_object_ app.connect('autodoc-process-docstring', mangle_docstrings) app.connect('builder-inited', initialize) app.add_config_value('numpydoc_edit_link', None, True) #------------------------------------------------------------------------------ # Monkeypatch sphinx.ext.autodoc to accept argspecless autodocs (Sphinx < 0.5) #------------------------------------------------------------------------------ def monkeypatch_sphinx_ext_autodoc(): global _original_format_signature import sphinx.ext.autodoc if sphinx.ext.autodoc.format_signature is our_format_signature: return print "[numpydoc] Monkeypatching sphinx.ext.autodoc ..." _original_format_signature = sphinx.ext.autodoc.format_signature sphinx.ext.autodoc.format_signature = our_format_signature def our_format_signature(what, obj): r = mangle_signature(None, what, None, obj, None, None, None) if r is not None: return r[0] else: return _original_format_signature(what, obj) Shapely-1.3.0/requirements-dev.txt000066400000000000000000000001011226057120100171440ustar00rootroot00000000000000setuptools >= 0.9.8 Numpy==1.8.0 Cython==0.19.2 descartes==1.0.1 Shapely-1.3.0/setup.py000077500000000000000000000157021226057120100146360ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function try: # If possible, use setuptools from setuptools import setup from setuptools.extension import Extension from setuptools.command.build_ext import build_ext as distutils_build_ext except ImportError: from distutils.core import setup from distutils.extension import Extension from distutils.command.build_ext import build_ext as distutils_build_ext from distutils.cmd import Command from distutils.errors import CCompilerError, DistutilsExecError, \ DistutilsPlatformError import errno import glob import os import platform import shutil import subprocess import sys class test(Command): """Run unit tests after in-place build""" description = __doc__ user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): # Force an in-place build for testing speedups cmd = self.reinitialize_command('build_ext') setattr(cmd, 'inplace', 1) self.run_command('build_ext') if sys.version_info[0:2] <= (2, 6): try: from unittest2 import TextTestRunner, TestLoader except ImportError: raise ImportError( "unittest2 is required to run tests with python-%d.%d" % sys.version_info[0:2]) else: from unittest import TextTestRunner, TestLoader import shapely.tests tests = TestLoader().loadTestsFromName('test_suite', shapely.tests) runner = TextTestRunner(verbosity=2) result = runner.run(tests) if not result.wasSuccessful(): sys.exit(1) # Get the version from the shapely module version = None with open('shapely/__init__.py', 'r') as fp: for line in fp: if "__version__" in line: exec(line.replace('_', '')) break if version is None: raise ValueError("Could not determine Shapely's version") with open('VERSION.txt', 'w') as fp: fp.write(version) with open('README.rst', 'r') as fp: readme_text = fp.read() readme_text = readme_text.replace(".. include:: CREDITS.txt", "") with open('CREDITS.txt', 'r') as fp: credits = fp.read() with open('CHANGES.txt', 'r') as fp: changes_text = fp.read() setup_args = dict( name = 'Shapely', version = version, requires = ['Python (>=2.6)', 'libgeos_c (>=3.1)'], description = 'Geometric objects, predicates, and operations', license = 'BSD', keywords = 'geometry topology gis', author = 'Sean Gillies', author_email = 'sean.gillies@gmail.com', maintainer = 'Sean Gillies', maintainer_email = 'sean.gillies@gmail.com', url = 'https://github.com/Toblerity/Shapely', long_description = readme_text + "\n" + credits + "\n" + changes_text, packages = [ 'shapely', 'shapely.geometry', 'shapely.algorithms', 'shapely.examples', 'shapely.speedups', 'shapely.tests', ], cmdclass = {'test': test}, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Topic :: Scientific/Engineering :: GIS', ], ) # Add DLLs for Windows if sys.platform == 'win32': try: os.mkdir('shapely/DLLs') except OSError as ex: if ex.errno != errno.EEXIST: raise if '(AMD64)' in sys.version: for dll in glob.glob('DLLs_AMD64_VC9/*.dll'): shutil.copy(dll, 'shapely/DLLs') elif sys.version_info[0:2] == (2, 5): for dll in glob.glob('DLLs_x86_VC7/*.dll'): shutil.copy(dll, 'shapely/DLLs') else: for dll in glob.glob('DLLs_x86_VC9/*.dll'): shutil.copy(dll, 'shapely/DLLs') setup_args.update( package_data={'shapely': ['shapely/DLLs/*.dll']}, include_package_data=True, ) # Optional compilation of speedups # setuptools stuff from Bob Ippolito's simplejson project if sys.platform == 'win32' and sys.version_info > (2, 6): # 2.6's distutils.msvc9compiler can raise an IOError when failing to # find the compiler ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError) else: ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) class BuildFailed(Exception): pass class build_ext(distutils_build_ext): # This class allows C extension building to fail. def run(self): try: distutils_build_ext.run(self) except DistutilsPlatformError as x: raise BuildFailed(x) def build_extension(self, ext): try: distutils_build_ext.build_extension(self, ext) except ext_errors as x: raise BuildFailed(x) if (hasattr(platform, 'python_implementation') and platform.python_implementation() == 'PyPy'): # python_implementation is only available since 2.6 ext_modules = [] libraries = [] elif sys.platform == 'win32': libraries = ['geos'] else: libraries = ['geos_c'] if os.path.exists("MANIFEST.in"): pyx_file = "shapely/speedups/_speedups.pyx" c_file = "shapely/speedups/_speedups.c" force_cython = False if 'sdist' in sys.argv: force_cython = True try: if (force_cython or not os.path.exists(c_file) or os.path.getmtime(pyx_file) > os.path.getmtime(c_file)): print("Updating C extension with Cython.", file=sys.stderr) subprocess.check_call(["cython", "shapely/speedups/_speedups.pyx"]) except (subprocess.CalledProcessError, OSError): print("Warning: Could not (re)create C extension with Cython.", file=sys.stderr) if force_cython: raise if not os.path.exists("shapely/speedups/_speedups.c"): print("Warning: speedup extension not found", file=sys.stderr) ext_modules = [ Extension( "shapely.speedups._speedups", ["shapely/speedups/_speedups.c"], libraries=libraries) ] try: # try building with speedups setup_args['cmdclass']['build_ext'] = build_ext setup( ext_modules=ext_modules, **setup_args ) except BuildFailed as ex: BUILD_EXT_WARNING = "Warning: The C extension could not be compiled, " \ "speedups are not enabled." print(ex) print(BUILD_EXT_WARNING) print("Failure information, if any, is above.") print("I'm retrying the build without the C extension now.") setup(**setup_args) print(BUILD_EXT_WARNING) print("Plain-Python installation succeeded.") Shapely-1.3.0/shapely/000077500000000000000000000000001226057120100145615ustar00rootroot00000000000000Shapely-1.3.0/shapely/__init__.py000066400000000000000000000000261226057120100166700ustar00rootroot00000000000000__version__ = "1.3.0" Shapely-1.3.0/shapely/affinity.py000077500000000000000000000204321226057120100167500ustar00rootroot00000000000000"""Affine transforms, both in general and specific, named transforms.""" from math import sin, cos, tan, pi __all__ = ['affine_transform', 'rotate', 'scale', 'skew', 'translate'] def affine_transform(geom, matrix): """Returns a transformed geometry using an affine transformation matrix. The coefficient matrix is provided as a list or tuple with 6 or 12 items for 2D or 3D transformations, respectively. For 2D affine transformations, the 6 parameter matrix is: [a, b, d, e, xoff, yoff] which represents the augmented matrix: / a b xoff \ [x' y' 1] = [x y 1] | d e yoff | \ 0 0 1 / or the equations for the transformed coordinates: x' = a * x + b * y + xoff y' = d * x + e * y + yoff For 3D affine transformations, the 12 parameter matrix is: [a, b, c, d, e, f, g, h, i, xoff, yoff, zoff] which represents the augmented matrix: / a b c xoff \ [x' y' z' 1] = [x y z 1] | d e f yoff | | g h i zoff | \ 0 0 0 1 / or the equations for the transformed coordinates: x' = a * x + b * y + c * z + xoff y' = d * x + e * y + f * z + yoff z' = g * x + h * y + i * z + zoff """ if geom.is_empty: return geom if len(matrix) == 6: ndim = 2 a, b, d, e, xoff, yoff = matrix if geom.has_z: ndim = 3 i = 1.0 c = f = g = h = zoff = 0.0 matrix = a, b, c, d, e, f, g, h, i, xoff, yoff, zoff elif len(matrix) == 12: ndim = 3 a, b, c, d, e, f, g, h, i, xoff, yoff, zoff = matrix if not geom.has_z: ndim = 2 matrix = a, b, d, e, xoff, yoff else: raise ValueError("'matrix' expects either 6 or 12 coefficients") def affine_pts(pts): """Internal function to yield affine transform of coordinate tuples""" if ndim == 2: for x, y in pts: xp = a * x + b * y + xoff yp = d * x + e * y + yoff yield (xp, yp) elif ndim == 3: for x, y, z in pts: xp = a * x + b * y + c * z + xoff yp = d * x + e * y + f * z + yoff zp = g * x + h * y + i * z + zoff yield (xp, yp, zp) # Process coordinates from each supported geometry type if geom.type in ('Point', 'LineString'): return type(geom)(list(affine_pts(geom.coords))) elif geom.type == 'Polygon': ring = geom.exterior shell = type(ring)(list(affine_pts(ring.coords))) holes = list(geom.interiors) for pos, ring in enumerate(holes): holes[pos] = type(ring)(list(affine_pts(ring.coords))) return type(geom)(shell, holes) elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection': # Recursive call # TODO: fix GeometryCollection constructor return type(geom)([affine_transform(part, matrix) for part in geom.geoms]) else: raise ValueError('Type %r not recognized' % geom.type) def interpret_origin(geom, origin, ndim): """Returns interpreted coordinate tuple for origin parameter. This is a helper function for other transform functions. The point of origin can be a keyword 'center' for the 2D bounding box center, 'centroid' for the geometry's 2D centroid, a Point object or a coordinate tuple (x0, y0, z0). """ # get coordinate tuple from 'origin' from keyword or Point type if origin == 'center': # bounding box center minx, miny, maxx, maxy = geom.bounds origin = ((maxx + minx)/2.0, (maxy + miny)/2.0) elif origin == 'centroid': origin = geom.centroid.coords[0] elif isinstance(origin, str): raise ValueError("'origin' keyword %r is not recognized" % origin) elif hasattr(origin, 'type') and origin.type == 'Point': origin = origin.coords[0] # origin should now be tuple-like if len(origin) not in (2, 3): raise ValueError("Expected number of items in 'origin' to be " "either 2 or 3") if ndim == 2: return origin[0:2] else: # 3D coordinate if len(origin) == 2: return origin + (0.0,) else: return origin def rotate(geom, angle, origin='center', use_radians=False): """Returns a rotated geometry on a 2D plane. The angle of rotation can be specified in either degrees (default) or radians by setting ``use_radians=True``. Positive angles are counter-clockwise and negative are clockwise rotations. The point of origin can be a keyword 'center' for the bounding box center (default), 'centroid' for the geometry's centroid, a Point object or a coordinate tuple (x0, y0). The affine transformation matrix for 2D rotation is: / cos(r) -sin(r) xoff \ | sin(r) cos(r) yoff | \ 0 0 1 / where the offsets are calculated from the origin Point(x0, y0): xoff = x0 - x0 * cos(r) + y0 * sin(r) yoff = y0 - x0 * sin(r) - y0 * cos(r) """ if not use_radians: # convert from degrees angle *= pi/180.0 cosp = cos(angle) sinp = sin(angle) if abs(cosp) < 2.5e-16: cosp = 0.0 if abs(sinp) < 2.5e-16: sinp = 0.0 x0, y0 = interpret_origin(geom, origin, 2) matrix = (cosp, -sinp, 0.0, sinp, cosp, 0.0, 0.0, 0.0, 1.0, x0 - x0 * cosp + y0 * sinp, y0 - x0 * sinp - y0 * cosp, 0.0) return affine_transform(geom, matrix) def scale(geom, xfact=1.0, yfact=1.0, zfact=1.0, origin='center'): """Returns a scaled geometry, scaled by factors along each dimension. The point of origin can be a keyword 'center' for the 2D bounding box center (default), 'centroid' for the geometry's 2D centroid, a Point object or a coordinate tuple (x0, y0, z0). Negative scale factors will mirror or reflect coordinates. The general 3D affine transformation matrix for scaling is: / xfact 0 0 xoff \ | 0 yfact 0 yoff | | 0 0 zfact zoff | \ 0 0 0 1 / where the offsets are calculated from the origin Point(x0, y0, z0): xoff = x0 - x0 * xfact yoff = y0 - y0 * yfact zoff = z0 - z0 * zfact """ x0, y0, z0 = interpret_origin(geom, origin, 3) matrix = (xfact, 0.0, 0.0, 0.0, yfact, 0.0, 0.0, 0.0, zfact, x0 - x0 * xfact, y0 - y0 * yfact, z0 - z0 * zfact) return affine_transform(geom, matrix) def skew(geom, xs=0.0, ys=0.0, origin='center', use_radians=False): """Returns a skewed geometry, sheared by angles along x and y dimensions. The shear angle can be specified in either degrees (default) or radians by setting ``use_radians=True``. The point of origin can be a keyword 'center' for the bounding box center (default), 'centroid' for the geometry's centroid, a Point object or a coordinate tuple (x0, y0). The general 2D affine transformation matrix for skewing is: / 1 tan(xs) xoff \ | tan(ys) 1 yoff | \ 0 0 1 / where the offsets are calculated from the origin Point(x0, y0): xoff = -y0 * tan(xs) yoff = -x0 * tan(ys) """ if not use_radians: # convert from degrees xs *= pi/180.0 ys *= pi/180.0 tanx = tan(xs) tany = tan(ys) if abs(tanx) < 2.5e-16: tanx = 0.0 if abs(tany) < 2.5e-16: tany = 0.0 x0, y0 = interpret_origin(geom, origin, 2) matrix = (1.0, tanx, 0.0, tany, 1.0, 0.0, 0.0, 0.0, 1.0, -y0 * tanx, -x0 * tany, 0.0) return affine_transform(geom, matrix) def translate(geom, xoff=0.0, yoff=0.0, zoff=0.0): """Returns a translated geometry shifted by offsets along each dimension. The general 3D affine transformation matrix for translation is: / 1 0 0 xoff \ | 0 1 0 yoff | | 0 0 1 zoff | \ 0 0 0 1 / """ matrix = (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, xoff, yoff, zoff) return affine_transform(geom, matrix) Shapely-1.3.0/shapely/algorithms/000077500000000000000000000000001226057120100167325ustar00rootroot00000000000000Shapely-1.3.0/shapely/algorithms/__init__.py000066400000000000000000000000001226057120100210310ustar00rootroot00000000000000Shapely-1.3.0/shapely/algorithms/cga.py000066400000000000000000000007171226057120100200430ustar00rootroot00000000000000 def signed_area(ring): """Return the signed area enclosed by a ring in linear time using the algorithm at: http://www.cgafaq.info/wiki/Polygon_Area. """ xs, ys = ring.coords.xy xs.append(xs[1]) ys.append(ys[1]) return sum(xs[i]*(ys[i+1]-ys[i-1]) for i in range(1, len(ring.coords)))/2.0 def is_ccw_impl(name): """Predicate implementation""" def is_ccw_op(ring): return signed_area(ring) >= 0.0 return is_ccw_op Shapely-1.3.0/shapely/coords.py000066400000000000000000000134611226057120100164310ustar00rootroot00000000000000"""Coordinate sequence utilities """ import sys from array import array from ctypes import byref, c_double, c_uint from shapely.geos import lgeos from shapely.topology import Validating if sys.version_info[0] < 3: range = xrange try: import numpy has_numpy = True except ImportError: has_numpy = False def required(ob): """Return an object that meets Shapely requirements for self-owned C-continguous data, copying if necessary, or just return the original object.""" if has_numpy and hasattr(ob, '__array_interface__'): return numpy.require(ob, numpy.float64, ["C", "OWNDATA"]) else: return ob class CoordinateSequence(object): """ Iterative access to coordinate tuples from the parent geometry's coordinate sequence. Example: >>> from shapely.wkt import loads >>> g = loads('POINT (0.0 0.0)') >>> list(g.coords) [(0.0, 0.0)] """ # Attributes # ---------- # _cseq : c_void_p # Ctypes pointer to GEOS coordinate sequence # _ndim : int # Number of dimensions (2 or 3, generally) # __p__ : object # Parent (Shapely) geometry _cseq = None _ndim = None __p__ = None def __init__(self, parent): self.__p__ = parent def _update(self): self._ndim = self.__p__._ndim self._cseq = lgeos.GEOSGeom_getCoordSeq(self.__p__._geom) def __len__(self): self._update() cs_len = c_uint(0) lgeos.GEOSCoordSeq_getSize(self._cseq, byref(cs_len)) return cs_len.value def __iter__(self): self._update() dx = c_double() dy = c_double() dz = c_double() has_z = self._ndim == 3 for i in range(self.__len__()): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) yield (dx.value, dy.value, dz.value) else: yield (dx.value, dy.value) def __getitem__(self, key): self._update() dx = c_double() dy = c_double() dz = c_double() m = self.__len__() has_z = self._ndim == 3 if isinstance(key, int): if key + m < 0 or key >= m: raise IndexError("index out of range") if key < 0: i = m + key else: i = key lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) return (dx.value, dy.value, dz.value) else: return (dx.value, dy.value) elif isinstance(key, slice): res = [] start, stop, stride = key.indices(m) for i in range(start, stop, stride): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) res.append((dx.value, dy.value, dz.value)) else: res.append((dx.value, dy.value)) return res else: raise TypeError("key must be an index or slice") @property def ctypes(self): self._update() has_z = self._ndim == 3 n = self._ndim m = self.__len__() array_type = c_double * (m * n) data = array_type() temp = c_double() for i in range(m): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(temp)) data[n*i] = temp.value lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(temp)) data[n*i+1] = temp.value if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(temp)) data[n*i+2] = temp.value return data def array_interface(self): """Provide the Numpy array protocol.""" if sys.byteorder == 'little': typestr = ' maxx: maxx = x lgeos.GEOSCoordSeq_getY(cs, i, byref(temp)) y = temp.value if y < miny: miny = y if y > maxy: maxy = y return (minx, miny, maxx, maxy) Shapely-1.3.0/shapely/ctypes_declarations.py000066400000000000000000000337471226057120100212100ustar00rootroot00000000000000'''Prototyping of the GEOS C API See header file: geos-x.y.z/capi/geos_c.h ''' from ctypes import CFUNCTYPE, POINTER, c_void_p, c_char_p, \ c_size_t, c_byte, c_char, c_uint, c_int, c_double # Derived pointer types c_size_t_p = POINTER(c_size_t) class allocated_c_char_p(c_char_p): '''char pointer return type''' pass EXCEPTION_HANDLER_FUNCTYPE = CFUNCTYPE(None, c_char_p, c_char_p) def prototype(lgeos, geos_version): '''Protype functions in geos_c.h for different version of GEOS Use the GEOS version, not the C API version. ''' ''' Initialization, cleanup, version ''' lgeos.initGEOS.restype = None lgeos.initGEOS.argtypes = [EXCEPTION_HANDLER_FUNCTYPE, EXCEPTION_HANDLER_FUNCTYPE] lgeos.finishGEOS.restype = None lgeos.finishGEOS.argtypes = [] lgeos.GEOSversion.restype = c_char_p lgeos.GEOSversion.argtypes = [] ''' NOTE - These functions are DEPRECATED. Please use the new Reader and writer APIS! ''' lgeos.GEOSGeomFromWKT.restype = c_void_p lgeos.GEOSGeomFromWKT.argtypes = [c_char_p] lgeos.GEOSGeomToWKT.restype = allocated_c_char_p lgeos.GEOSGeomToWKT.argtypes = [c_void_p] lgeos.GEOS_setWKBOutputDims.restype = c_int lgeos.GEOS_setWKBOutputDims.argtypes = [c_int] lgeos.GEOSGeomFromWKB_buf.restype = c_void_p lgeos.GEOSGeomFromWKB_buf.argtypes = [c_void_p, c_size_t] lgeos.GEOSGeomToWKB_buf.restype = allocated_c_char_p lgeos.GEOSGeomToWKB_buf.argtypes = [c_void_p, c_size_t_p] ''' Coordinate sequence ''' lgeos.GEOSCoordSeq_create.restype = c_void_p lgeos.GEOSCoordSeq_create.argtypes = [c_uint, c_uint] lgeos.GEOSCoordSeq_clone.restype = c_void_p lgeos.GEOSCoordSeq_clone.argtypes = [c_void_p] lgeos.GEOSCoordSeq_destroy.restype = None lgeos.GEOSCoordSeq_destroy.argtypes = [c_void_p] lgeos.GEOSCoordSeq_setX.restype = c_int lgeos.GEOSCoordSeq_setX.argtypes = [c_void_p, c_uint, c_double] lgeos.GEOSCoordSeq_setY.restype = c_int lgeos.GEOSCoordSeq_setY.argtypes = [c_void_p, c_uint, c_double] lgeos.GEOSCoordSeq_setZ.restype = c_int lgeos.GEOSCoordSeq_setZ.argtypes = [c_void_p, c_uint, c_double] lgeos.GEOSCoordSeq_setOrdinate.restype = c_int lgeos.GEOSCoordSeq_setOrdinate.argtypes = [c_void_p, c_uint, c_uint, c_double] lgeos.GEOSCoordSeq_getX.restype = c_int lgeos.GEOSCoordSeq_getX.argtypes = [c_void_p, c_uint, c_void_p] lgeos.GEOSCoordSeq_getY.restype = c_int lgeos.GEOSCoordSeq_getY.argtypes = [c_void_p, c_uint, c_void_p] lgeos.GEOSCoordSeq_getZ.restype = c_int lgeos.GEOSCoordSeq_getZ.argtypes = [c_void_p, c_uint, c_void_p] lgeos.GEOSCoordSeq_getSize.restype = c_int lgeos.GEOSCoordSeq_getSize.argtypes = [c_void_p, c_void_p] lgeos.GEOSCoordSeq_getDimensions.restype = c_int lgeos.GEOSCoordSeq_getDimensions.argtypes = [c_void_p, c_void_p] ''' Linear refeferencing ''' if geos_version >= (3, 2, 0): lgeos.GEOSProject.restype = c_double lgeos.GEOSProject.argtypes = [c_void_p, c_void_p] lgeos.GEOSInterpolate.restype = c_void_p lgeos.GEOSInterpolate.argtypes = [c_void_p, c_double] lgeos.GEOSProjectNormalized.restype = c_double lgeos.GEOSProjectNormalized.argtypes = [c_void_p, c_void_p] lgeos.GEOSInterpolateNormalized.restype = c_void_p lgeos.GEOSInterpolateNormalized.argtypes = [c_void_p, c_double] ''' Buffer related ''' lgeos.GEOSBuffer.restype = c_void_p lgeos.GEOSBuffer.argtypes = [c_void_p, c_double, c_int] if geos_version >= (3, 2, 0): lgeos.GEOSBufferWithStyle.restype = c_void_p lgeos.GEOSBufferWithStyle.argtypes = [c_void_p, c_double, c_int, c_int, c_int, c_double] lgeos.GEOSSingleSidedBuffer.restype = c_void_p lgeos.GEOSSingleSidedBuffer.argtypes = [c_void_p, c_double, c_int, c_int, c_double, c_int] ''' Geometry constructors ''' lgeos.GEOSGeom_createPoint.restype = c_void_p lgeos.GEOSGeom_createPoint.argtypes = [c_void_p] lgeos.GEOSGeom_createLinearRing.restype = c_void_p lgeos.GEOSGeom_createLinearRing.argtypes = [c_void_p] lgeos.GEOSGeom_createLineString.restype = c_void_p lgeos.GEOSGeom_createLineString.argtypes = [c_void_p] lgeos.GEOSGeom_createPolygon.restype = c_void_p lgeos.GEOSGeom_createPolygon.argtypes = [c_void_p, c_void_p, c_uint] lgeos.GEOSGeom_createCollection.restype = c_void_p lgeos.GEOSGeom_createCollection.argtypes = [c_int, c_void_p, c_uint] lgeos.GEOSGeom_clone.restype = c_void_p lgeos.GEOSGeom_clone.argtypes = [c_void_p] ''' Memory management ''' lgeos.GEOSGeom_destroy.restype = None lgeos.GEOSGeom_destroy.argtypes = [c_void_p] ''' Topology operations Return NULL on exception ''' lgeos.GEOSEnvelope.restype = c_void_p lgeos.GEOSEnvelope.argtypes = [c_void_p] lgeos.GEOSIntersection.restype = c_void_p lgeos.GEOSIntersection.argtypes = [c_void_p, c_void_p] lgeos.GEOSConvexHull.restype = c_void_p lgeos.GEOSConvexHull.argtypes = [c_void_p] lgeos.GEOSDifference.restype = c_void_p lgeos.GEOSDifference.argtypes = [c_void_p, c_void_p] lgeos.GEOSSymDifference.restype = c_void_p lgeos.GEOSSymDifference.argtypes = [c_void_p, c_void_p] lgeos.GEOSBoundary.restype = c_void_p lgeos.GEOSBoundary.argtypes = [c_void_p] lgeos.GEOSUnion.restype = c_void_p lgeos.GEOSUnion.argtypes = [c_void_p, c_void_p] if geos_version >= (3, 3, 0): lgeos.GEOSUnaryUnion.restype = c_void_p lgeos.GEOSUnaryUnion.argtypes = [c_void_p] if geos_version >= (3, 1, 0): '''deprecated in 3.3.0: use GEOSUnaryUnion instead''' lgeos.GEOSUnionCascaded.restype = c_void_p lgeos.GEOSUnionCascaded.argtypes = [c_void_p] lgeos.GEOSPointOnSurface.restype = c_void_p lgeos.GEOSPointOnSurface.argtypes = [c_void_p] lgeos.GEOSGetCentroid.restype = c_void_p lgeos.GEOSGetCentroid.argtypes = [c_void_p] lgeos.GEOSPolygonize.restype = c_void_p lgeos.GEOSPolygonize.argtypes = [c_void_p, c_uint] if geos_version >= (3, 3, 0): lgeos.GEOSPolygonize_full.restype = c_void_p lgeos.GEOSPolygonize_full.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p] lgeos.GEOSLineMerge.restype = c_void_p lgeos.GEOSLineMerge.argtypes = [c_void_p] lgeos.GEOSSimplify.restype = c_void_p lgeos.GEOSSimplify.argtypes = [c_void_p, c_double] lgeos.GEOSTopologyPreserveSimplify.restype = c_void_p lgeos.GEOSTopologyPreserveSimplify.argtypes = [c_void_p, c_double] ''' Binary predicates Return 2 on exception, 1 on true, 0 on false ''' lgeos.GEOSDisjoint.restype = c_byte lgeos.GEOSDisjoint.argtypes = [c_void_p, c_void_p] lgeos.GEOSTouches.restype = c_byte lgeos.GEOSTouches.argtypes = [c_void_p, c_void_p] lgeos.GEOSIntersects.restype = c_byte lgeos.GEOSIntersects.argtypes = [c_void_p, c_void_p] lgeos.GEOSCrosses.restype = c_byte lgeos.GEOSCrosses.argtypes = [c_void_p, c_void_p] lgeos.GEOSWithin.restype = c_byte lgeos.GEOSWithin.argtypes = [c_void_p, c_void_p] lgeos.GEOSContains.restype = c_byte lgeos.GEOSContains.argtypes = [c_void_p, c_void_p] lgeos.GEOSOverlaps.restype = c_byte lgeos.GEOSOverlaps.argtypes = [c_void_p, c_void_p] lgeos.GEOSEquals.restype = c_byte lgeos.GEOSEquals.argtypes = [c_void_p, c_void_p] lgeos.GEOSEqualsExact.restype = c_byte lgeos.GEOSEqualsExact.argtypes = [c_void_p, c_void_p, c_double] ''' Unary predicate Return 2 on exception, 1 on true, 0 on false ''' lgeos.GEOSisEmpty.restype = c_byte lgeos.GEOSisEmpty.argtypes = [c_void_p] lgeos.GEOSisValid.restype = c_byte lgeos.GEOSisValid.argtypes = [c_void_p] if geos_version >= (3, 1, 0): lgeos.GEOSisValidReason.restype = allocated_c_char_p lgeos.GEOSisValidReason.argtypes = [c_void_p] lgeos.GEOSisSimple.restype = c_byte lgeos.GEOSisSimple.argtypes = [c_void_p] lgeos.GEOSisRing.restype = c_byte lgeos.GEOSisRing.argtypes = [c_void_p] lgeos.GEOSHasZ.restype = c_byte lgeos.GEOSHasZ.argtypes = [c_void_p] ''' Dimensionally Extended 9 Intersection Model related ''' lgeos.GEOSRelatePattern.restype = c_char lgeos.GEOSRelatePattern.argtypes = [c_void_p, c_void_p, c_char_p] lgeos.GEOSRelate.restype = allocated_c_char_p lgeos.GEOSRelate.argtypes = [c_void_p, c_void_p] ''' Prepared Geometry Binary predicates Return 2 on exception, 1 on true, 0 on false ''' if geos_version >= (3, 1, 0): lgeos.GEOSPrepare.restype = c_void_p lgeos.GEOSPrepare.argtypes = [c_void_p] lgeos.GEOSPreparedGeom_destroy.restype = None lgeos.GEOSPreparedGeom_destroy.argtypes = [c_void_p] lgeos.GEOSPreparedContains.restype = c_int lgeos.GEOSPreparedContains.argtypes = [c_void_p, c_void_p] lgeos.GEOSPreparedContainsProperly.restype = c_int lgeos.GEOSPreparedContainsProperly.argtypes = [c_void_p, c_void_p] lgeos.GEOSPreparedCovers.restype = c_int lgeos.GEOSPreparedCovers.argtypes = [c_void_p, c_void_p] lgeos.GEOSPreparedIntersects.restype = c_int lgeos.GEOSPreparedIntersects.argtypes = [c_void_p, c_void_p] ''' Geometry info ''' lgeos.GEOSGeomType.restype = c_char_p lgeos.GEOSGeomType.argtypes = [c_void_p] lgeos.GEOSGeomTypeId.restype = c_int lgeos.GEOSGeomTypeId.argtypes = [c_void_p] lgeos.GEOSGetSRID.restype = c_int lgeos.GEOSGetSRID.argtypes = [c_void_p] lgeos.GEOSSetSRID.restype = None lgeos.GEOSSetSRID.argtypes = [c_void_p, c_int] lgeos.GEOSGetNumGeometries.restype = c_int lgeos.GEOSGetNumGeometries.argtypes = [c_void_p] lgeos.GEOSGetGeometryN.restype = c_void_p lgeos.GEOSGetGeometryN.argtypes = [c_void_p, c_int] lgeos.GEOSGetNumInteriorRings.restype = c_int lgeos.GEOSGetNumInteriorRings.argtypes = [c_void_p] lgeos.GEOSGetInteriorRingN.restype = c_void_p lgeos.GEOSGetInteriorRingN.argtypes = [c_void_p, c_int] lgeos.GEOSGetExteriorRing.restype = c_void_p lgeos.GEOSGetExteriorRing.argtypes = [c_void_p] lgeos.GEOSGetNumCoordinates.restype = c_int lgeos.GEOSGetNumCoordinates.argtypes = [c_void_p] lgeos.GEOSGeom_getCoordSeq.restype = c_void_p lgeos.GEOSGeom_getCoordSeq.argtypes = [c_void_p] lgeos.GEOSGeom_getDimensions.restype = c_int lgeos.GEOSGeom_getDimensions.argtypes = [c_void_p] ''' Misc functions ''' lgeos.GEOSArea.restype = c_double lgeos.GEOSArea.argtypes = [c_void_p, c_void_p] lgeos.GEOSLength.restype = c_int lgeos.GEOSLength.argtypes = [c_void_p, c_void_p] lgeos.GEOSDistance.restype = c_int lgeos.GEOSDistance.argtypes = [c_void_p, c_void_p, c_void_p] ''' Reader and Writer APIs ''' '''WKT Reader''' lgeos.GEOSWKTReader_create.restype = c_void_p lgeos.GEOSWKTReader_create.argtypes = [] lgeos.GEOSWKTReader_destroy.restype = None lgeos.GEOSWKTReader_destroy.argtypes = [c_void_p] lgeos.GEOSWKTReader_read.restype = c_void_p lgeos.GEOSWKTReader_read.argtypes = [c_void_p, c_char_p] '''WKT Writer''' lgeos.GEOSWKTWriter_create.restype = c_void_p lgeos.GEOSWKTWriter_create.argtypes = [] lgeos.GEOSWKTWriter_destroy.restype = None lgeos.GEOSWKTWriter_destroy.argtypes = [c_void_p] lgeos.GEOSWKTWriter_write.restype = allocated_c_char_p lgeos.GEOSWKTWriter_write.argtypes = [c_void_p, c_void_p] if geos_version >= (3, 3, 0): lgeos.GEOSWKTWriter_setTrim.restype = None lgeos.GEOSWKTWriter_setTrim.argtypes = [c_void_p, c_int] lgeos.GEOSWKTWriter_setRoundingPrecision.restype = None lgeos.GEOSWKTWriter_setRoundingPrecision.argtypes = [c_void_p, c_int] lgeos.GEOSWKTWriter_setOutputDimension.restype = None lgeos.GEOSWKTWriter_setOutputDimension.argtypes = [c_void_p, c_int] lgeos.GEOSWKTWriter_getOutputDimension.restype = c_int lgeos.GEOSWKTWriter_getOutputDimension.argtypes = [c_void_p] lgeos.GEOSWKTWriter_setOld3D.restype = None lgeos.GEOSWKTWriter_setOld3D.argtypes = [c_void_p, c_int] '''WKB Reader''' lgeos.GEOSWKBReader_create.restype = c_void_p lgeos.GEOSWKBReader_create.argtypes = [] lgeos.GEOSWKBReader_destroy.restype = None lgeos.GEOSWKBReader_destroy.argtypes = [c_void_p] lgeos.GEOSWKBReader_read.restype = c_void_p lgeos.GEOSWKBReader_read.argtypes = [c_void_p, c_char_p, c_size_t] lgeos.GEOSWKBReader_readHEX.restype = c_void_p lgeos.GEOSWKBReader_readHEX.argtypes = [c_void_p, c_char_p, c_size_t] '''WKB Writer''' lgeos.GEOSWKBWriter_create.restype = c_void_p lgeos.GEOSWKBWriter_create.argtypes = [] lgeos.GEOSWKBWriter_destroy.restype = None lgeos.GEOSWKBWriter_destroy.argtypes = [c_void_p] lgeos.GEOSWKBWriter_write.restype = allocated_c_char_p lgeos.GEOSWKBWriter_write.argtypes = [c_void_p, c_void_p, c_size_t_p] lgeos.GEOSWKBWriter_writeHEX.restype = allocated_c_char_p lgeos.GEOSWKBWriter_writeHEX.argtypes = [c_void_p, c_void_p, c_size_t_p] lgeos.GEOSWKBWriter_getOutputDimension.restype = c_int lgeos.GEOSWKBWriter_getOutputDimension.argtypes = [c_void_p] lgeos.GEOSWKBWriter_setOutputDimension.restype = None lgeos.GEOSWKBWriter_setOutputDimension.argtypes = [c_void_p, c_int] lgeos.GEOSWKBWriter_getByteOrder.restype = c_int lgeos.GEOSWKBWriter_getByteOrder.argtypes = [c_void_p] lgeos.GEOSWKBWriter_setByteOrder.restype = None lgeos.GEOSWKBWriter_setByteOrder.argtypes = [c_void_p, c_int] lgeos.GEOSWKBWriter_getIncludeSRID.restype = c_int lgeos.GEOSWKBWriter_getIncludeSRID.argtypes = [c_void_p] lgeos.GEOSWKBWriter_setIncludeSRID.restype = None lgeos.GEOSWKBWriter_setIncludeSRID.argtypes = [c_void_p, c_int] if geos_version >= (3, 1, 1): ''' Free buffers returned by stuff like GEOSWKBWriter_write(), GEOSWKBWriter_writeHEX() and GEOSWKTWriter_write() ''' lgeos.GEOSFree.restype = None lgeos.GEOSFree.argtypes = [c_void_p] Shapely-1.3.0/shapely/examples/000077500000000000000000000000001226057120100163775ustar00rootroot00000000000000Shapely-1.3.0/shapely/examples/__init__.py000066400000000000000000000000221226057120100205020ustar00rootroot00000000000000# Examples module Shapely-1.3.0/shapely/examples/dissolve.py000066400000000000000000000033231226057120100206020ustar00rootroot00000000000000# dissolve.py # # Demonstrate how Shapely can be used to build up a collection of patches by # dissolving circular regions and how Shapely supports plotting of the results. from functools import partial import random import pylab from shapely.geometry import Point from shapely.ops import cascaded_union # Use a partial function to make 100 points uniformly distributed in a 40x40 # box centered on 0,0. r = partial(random.uniform, -20.0, 20.0) points = [Point(r(), r()) for i in range(100)] # Buffer the points, producing 100 polygon spots spots = [p.buffer(2.5) for p in points] # Perform a cascaded union of the polygon spots, dissolving them into a # collection of polygon patches patches = cascaded_union(spots) if __name__ == "__main__": # Illustrate the results using matplotlib's pylab interface pylab.figure(num=None, figsize=(4, 4), dpi=180) for patch in patches.geoms: assert patch.geom_type in ['Polygon'] assert patch.is_valid # Fill and outline each patch x, y = patch.exterior.xy pylab.fill(x, y, color='#cccccc', aa=True) pylab.plot(x, y, color='#666666', aa=True, lw=1.0) # Do the same for the holes of the patch for hole in patch.interiors: x, y = hole.xy pylab.fill(x, y, color='#ffffff', aa=True) pylab.plot(x, y, color='#999999', aa=True, lw=1.0) # Plot the original points pylab.plot([p.x for p in points], [p.y for p in points], 'b,', alpha=0.75) # Write the number of patches and the total patch area to the figure pylab.text(-25, 25, "Patches: %d, total area: %.2f" % (len(patches.geoms), patches.area)) pylab.savefig('dissolve.png') Shapely-1.3.0/shapely/examples/geoms.py000066400000000000000000000022421226057120100200630ustar00rootroot00000000000000from numpy import asarray import pylab from shapely.geometry import Point, LineString, Polygon polygon = Polygon(((-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0), (1.0, -1.0))) point_r = Point(-1.5, 1.2) point_g = Point(-1.0, 1.0) point_b = Point(-0.5, 0.5) line_r = LineString(((-0.5, 0.5), (0.5, 0.5))) line_g = LineString(((1.0, -1.0), (1.8, 0.5))) line_b = LineString(((-1.8, -1.2), (1.8, 0.5))) def plot_point(g, o, l): pylab.plot([g.x], [g.y], o, label=l) def plot_line(g, o): a = asarray(g) pylab.plot(a[:,0], a[:,1], o) def fill_polygon(g, o): a = asarray(g.exterior) pylab.fill(a[:,0], a[:,1], o, alpha=0.5) def fill_multipolygon(g, o): for g in g.geoms: fill_polygon(g, o) if __name__ == "__main__": from numpy import asarray import pylab fig = pylab.figure(1, figsize=(4, 3), dpi=150) #pylab.axis([-2.0, 2.0, -1.5, 1.5]) pylab.axis('tight') a = asarray(polygon.exterior) pylab.fill(a[:,0], a[:,1], 'c') plot_point(point_r, 'ro', 'b') plot_point(point_g, 'go', 'c') plot_point(point_b, 'bo', 'd') plot_line(line_r, 'r') plot_line(line_g, 'g') plot_line(line_b, 'b') pylab.show() Shapely-1.3.0/shapely/examples/intersect.py000066400000000000000000000051021226057120100207470ustar00rootroot00000000000000# intersect.py # # Demonstrate how Shapely can be used to analyze and plot the intersection of # a trajectory and regions in space. from functools import partial import random import pylab from shapely.geometry import LineString, Point from shapely.ops import cascaded_union # Build patches as in dissolved.py r = partial(random.uniform, -20.0, 20.0) points = [Point(r(), r()) for i in range(100)] spots = [p.buffer(2.5) for p in points] patches = cascaded_union(spots) # Represent the following geolocation parameters # # initial position: -25, -25 # heading: 45.0 # speed: 50*sqrt(2) # # as a line vector = LineString(((-25.0, -25.0), (25.0, 25.0))) # Find intercepted and missed patches. List the former so we can count them # later intercepts = [patch for patch in patches.geoms if vector.intersects(patch)] misses = (patch for patch in patches.geoms if not vector.intersects(patch)) # Plot the intersection intersection = vector.intersection(patches) assert intersection.geom_type in ['MultiLineString'] if __name__ == "__main__": # Illustrate the results using matplotlib's pylab interface pylab.figure(num=None, figsize=(4, 4), dpi=180) # Plot the misses for spot in misses: x, y = spot.exterior.xy pylab.fill(x, y, color='#cccccc', aa=True) pylab.plot(x, y, color='#999999', aa=True, lw=1.0) # Do the same for the holes of the patch for hole in spot.interiors: x, y = hole.xy pylab.fill(x, y, color='#ffffff', aa=True) pylab.plot(x, y, color='#999999', aa=True, lw=1.0) # Plot the intercepts for spot in intercepts: x, y = spot.exterior.xy pylab.fill(x, y, color='red', alpha=0.25, aa=True) pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0) # Do the same for the holes of the patch for hole in spot.interiors: x, y = hole.xy pylab.fill(x, y, color='#ffffff', aa=True) pylab.plot(x, y, color='red', alpha=0.5, aa=True, lw=1.0) # Draw the projected trajectory pylab.arrow(-25, -25, 50, 50, color='#999999', aa=True, head_width=1.0, head_length=1.0) for segment in intersection.geoms: x, y = segment.xy pylab.plot(x, y, color='red', aa=True, lw=1.5) # Write the number of patches and the total patch area to the figure pylab.text(-28, 25, "Patches: %d/%d (%d), total length: %.1f" \ % (len(intercepts), len(patches.geoms), len(intersection.geoms), intersection.length)) pylab.savefig('intersect.png') Shapely-1.3.0/shapely/examples/world.py000066400000000000000000000007011226057120100200760ustar00rootroot00000000000000import ogr import pylab from numpy import asarray from shapely.wkb import loads source = ogr.Open("/var/gis/data/world/world_borders.shp") borders = source.GetLayerByName("world_borders") fig = pylab.figure(1, figsize=(4,2), dpi=300) while 1: feature = borders.GetNextFeature() if not feature: break geom = loads(feature.GetGeometryRef().ExportToWkb()) a = asarray(geom) pylab.plot(a[:,0], a[:,1]) pylab.show() Shapely-1.3.0/shapely/ftools.py000066400000000000000000000055641226057120100164530ustar00rootroot00000000000000# Backport some of functools from Python 2.5 standard library for Shapely # on Python 2.4 # # Python module wrapper for _functools C module # to allow utilities written in Python to be added # to the functools module. # Written by Nick Coghlan # Copyright (C) 2006 Python Software Foundation. # See C source code for _functools credits/copyright # # _functools module written and maintained # by Hye-Shik Chang # with adaptations by Raymond Hettinger # Copyright (c) 2004, 2005, 2006 Python Software Foundation. # All rights reserved. def _partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func( *(args + fargs), **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc # update_wrapper() and wraps() are tools to help write # wrapper functions that can handle naive introspection WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') WRAPPER_UPDATES = ('__dict__',) def _update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Update a wrapper function to look like the wrapped function wrapper is the function to be updated wrapped is the original function assigned is a tuple naming the attributes assigned directly from the wrapped function to the wrapper function (defaults to functools.WRAPPER_ASSIGNMENTS) updated is a tuple naming the attributes of the wrapper that are updated with the corresponding attribute from the wrapped function (defaults to functools.WRAPPER_UPDATES) """ for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Return the wrapper so this can be used as a decorator via partial() return wrapper def _wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Decorator factory to apply update_wrapper() to a wrapper function Returns a decorator that invokes update_wrapper() with the decorated function as the wrapper argument and the arguments to wraps() as the remaining arguments. Default arguments are as for update_wrapper(). This is a convenience function to simplify applying partial() to update_wrapper(). """ return _partial(_update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) # Use stdlib's functools if available try: from functools import partial, update_wrapper, wraps have_functools = 1 except ImportError: partial = _partial update_wrapper = _update_wrapper wraps = _wraps have_functools = 0 Shapely-1.3.0/shapely/geometry/000077500000000000000000000000001226057120100164145ustar00rootroot00000000000000Shapely-1.3.0/shapely/geometry/__init__.py000066400000000000000000000014571226057120100205340ustar00rootroot00000000000000"""Geometry classes and factories """ from .base import CAP_STYLE, JOIN_STYLE from .geo import box, shape, asShape, mapping from .point import Point, asPoint from .linestring import LineString, asLineString from .polygon import Polygon, asPolygon, LinearRing, asLinearRing from .multipoint import MultiPoint, asMultiPoint from .multilinestring import MultiLineString, asMultiLineString from .multipolygon import MultiPolygon, asMultiPolygon from .collection import GeometryCollection __all__ = [ 'box', 'shape', 'asShape', 'Point', 'asPoint', 'LineString', 'asLineString', 'Polygon', 'asPolygon', 'MultiPoint', 'asMultiPoint', 'MultiLineString', 'asMultiLineString', 'MultiPolygon', 'asMultiPolygon', 'GeometryCollection', 'mapping', 'LinearRing', 'asLinearRing', 'CAP_STYLE', 'JOIN_STYLE', ] Shapely-1.3.0/shapely/geometry/base.py000066400000000000000000000554671226057120100177210ustar00rootroot00000000000000"""Base geometry class and utilities """ import sys from warnings import warn from binascii import a2b_hex from ctypes import pointer, c_size_t, c_char_p, c_void_p from shapely.coords import CoordinateSequence from shapely.ftools import wraps from shapely.geos import lgeos, ReadingError from shapely.geos import WKBWriter, WKTWriter from shapely.impl import DefaultImplementation, delegated if sys.version_info[0] < 3: range = xrange GEOMETRY_TYPES = [ 'Point', 'LineString', 'LinearRing', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection', ] def dump_coords(geom): """Dump coordinates of a geometry in the same order as data packing""" if not isinstance(geom, BaseGeometry): raise ValueError('Must be instance of a geometry class; found ' + geom.__class__.__name__) elif geom.type in ('Point', 'LineString', 'LinearRing'): return geom.coords[:] elif geom.type == 'Polygon': return geom.exterior.coords[:] + [i.coords[:] for i in geom.interiors] elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection': # Recursive call return [dump_coords(part) for part in geom] else: raise ValueError('Unhandled geometry type: ' + repr(geom.type)) def geometry_type_name(g): if g is None: raise ValueError("Null geometry has no type") return GEOMETRY_TYPES[lgeos.GEOSGeomTypeId(g)] def geom_factory(g, parent=None): # Abstract geometry factory for use with topological methods below if not g: raise ValueError("No Shapely geometry can be created from null value") ob = BaseGeometry() geom_type = geometry_type_name(g) # TODO: check cost of dynamic import by profiling mod = __import__( 'shapely.geometry', globals(), locals(), [geom_type], ) ob.__class__ = getattr(mod, geom_type) ob.__geom__ = g ob.__p__ = parent if lgeos.methods['has_z'](g): ob._ndim = 3 else: ob._ndim = 2 return ob def geom_from_wkt(data): warn("`geom_from_wkt` is deprecated. Use `geos.wkt_reader.read(data)`.", DeprecationWarning) if sys.version_info[0] >= 3: data = data.encode('ascii') geom = lgeos.GEOSGeomFromWKT(c_char_p(data)) if not geom: raise ReadingError( "Could not create geometry because of errors while reading input.") return geom_factory(geom) def geom_to_wkt(ob): warn("`geom_to_wkt` is deprecated. Use `geos.wkt_writer.write(ob)`.", DeprecationWarning) if ob is None or ob._geom is None: raise ValueError("Null geometry supports no operations") return lgeos.GEOSGeomToWKT(ob._geom) def deserialize_wkb(data): geom = lgeos.GEOSGeomFromWKB_buf(c_char_p(data), c_size_t(len(data))) if not geom: raise ReadingError( "Could not create geometry because of errors while reading input.") return geom def geom_from_wkb(data): warn("`geom_from_wkb` is deprecated. Use `geos.wkb_reader.read(data)`.", DeprecationWarning) return geom_factory(deserialize_wkb(data)) def geom_to_wkb(ob): warn("`geom_to_wkb` is deprecated. Use `geos.wkb_writer.write(ob)`.", DeprecationWarning) if ob is None or ob._geom is None: raise ValueError("Null geometry supports no operations") size = c_size_t() return lgeos.GEOSGeomToWKB_buf(c_void_p(ob._geom), pointer(size)) def exceptNull(func): """Decorator which helps avoid GEOS operations on null pointers.""" @wraps(func) def wrapper(*args, **kwargs): if not args[0]._geom or args[0].is_empty: raise ValueError("Null/empty geometry supports no operations") return func(*args, **kwargs) return wrapper class CAP_STYLE(object): round = 1 flat = 2 square = 3 class JOIN_STYLE(object): round = 1 mitre = 2 bevel = 3 EMPTY = deserialize_wkb(a2b_hex(b'010700000000000000')) class BaseGeometry(object): """ Provides GEOS spatial predicates and topological operations. """ # Attributes # ---------- # __geom__ : c_void_p # Cached ctypes pointer to GEOS geometry. Not to be accessed. # _geom : c_void_p # Property by which the GEOS geometry is accessed. # __p__ : object # Parent (Shapely) geometry # _ctypes_data : object # Cached ctypes data buffer # _ndim : int # Number of dimensions (2 or 3, generally) # _crs : object # Coordinate reference system. Available for Shapely extensions, but # not implemented here. # _owned : bool # True if this object's GEOS geometry is owned by another as in the # case of a multipart geometry member. __geom__ = EMPTY __p__ = None _ctypes_data = None _ndim = None _crs = None _owned = False # Backend config impl = DefaultImplementation @property def _is_empty(self): return self.__geom__ in [EMPTY, None] # a reference to the so/dll proxy to preserve access during clean up _lgeos = lgeos def empty(self): # TODO: defer cleanup to the implementation. We shouldn't be # explicitly calling a lgeos method here. if not (self._owned or self._is_empty): try: self._lgeos.GEOSGeom_destroy(self.__geom__) except AttributeError: pass # _lgeos might be empty on shutdown self.__geom__ = EMPTY def __del__(self): self.empty() self.__geom__ = None self.__p__ = None def __str__(self): return self.wkt # To support pickling def __reduce__(self): return (self.__class__, (), self.wkb) def __setstate__(self, state): self.empty() self.__geom__ = deserialize_wkb(state) if lgeos.methods['has_z'](self.__geom__): self._ndim = 3 else: self._ndim = 2 @property def _geom(self): return self.__geom__ @_geom.setter def _geom(self, val): self.empty() self.__geom__ = val # Operators # --------- def __and__(self, other): return self.intersection(other) def __or__(self, other): return self.union(other) def __sub__(self, other): return self.difference(other) def __xor__(self, other): return self.symmetric_difference(other) # Array and ctypes interfaces # --------------------------- @property def ctypes(self): """Return ctypes buffer""" raise NotImplementedError @property def array_interface_base(self): if sys.byteorder == 'little': typestr = '>> from shapely.wkt import loads >>> g = loads('POINT (0.0 0.0)') >>> g.buffer(1.0).area # 16-gon approx of a unit radius circle 3.1365484905459389 >>> g.buffer(1.0, 128).area # 128-gon approximation 3.1415138011443009 >>> g.buffer(1.0, 3).area # triangle approximation 3.0 >>> list(g.buffer(1.0, cap_style='square').exterior.coords) [(1.0, 1.0), (1.0, -1.0), (-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0)] >>> g.buffer(1.0, cap_style='square').area 4.0 """ if quadsegs is not None: warn( "The `quadsegs` argument is deprecated. Use `resolution`.", DeprecationWarning) res = quadsegs else: res = resolution if cap_style == CAP_STYLE.round and join_style == JOIN_STYLE.round: return geom_factory(self.impl['buffer'](self, distance, res)) if 'buffer_with_style' not in self.impl: raise NotImplementedError("Styled buffering not available for " "GEOS versions < 3.2.") return geom_factory(self.impl['buffer_with_style'](self, distance, res, cap_style, join_style, mitre_limit)) @delegated def simplify(self, tolerance, preserve_topology=True): """Returns a simplified geometry produced by the Douglas-Puecker algorithm Coordinates of the simplified geometry will be no more than the tolerance distance from the original. Unless the topology preserving option is used, the algorithm may produce self-intersecting or otherwise invalid geometries. """ if preserve_topology: op = self.impl['topology_preserve_simplify'] else: op = self.impl['simplify'] return geom_factory(op(self, tolerance)) # Binary operations # ----------------- def difference(self, other): """Returns the difference of the geometries""" return geom_factory(self.impl['difference'](self, other)) def intersection(self, other): """Returns the intersection of the geometries""" return geom_factory(self.impl['intersection'](self, other)) def symmetric_difference(self, other): """Returns the symmetric difference of the geometries (Shapely geometry)""" return geom_factory(self.impl['symmetric_difference'](self, other)) def union(self, other): """Returns the union of the geometries (Shapely geometry)""" return geom_factory(self.impl['union'](self, other)) # Unary predicates # ---------------- @property def has_z(self): """True if the geometry's coordinate sequence(s) have z values (are 3-dimensional)""" return bool(self.impl['has_z'](self)) @property def is_empty(self): """True if the set of points in this geometry is empty, else False""" return (self._geom is None) or bool(self.impl['is_empty'](self)) @property def is_ring(self): """True if the geometry is a closed ring, else False""" return bool(self.impl['is_ring'](self)) @property def is_simple(self): """True if the geometry is simple, meaning that any self-intersections are only at boundary points, else False""" return bool(self.impl['is_simple'](self)) @property def is_valid(self): """True if the geometry is valid (definition depends on sub-class), else False""" return bool(self.impl['is_valid'](self)) # Binary predicates # ----------------- def relate(self, other): """Returns the DE-9IM intersection matrix for the two geometries (string)""" return self.impl['relate'](self, other) def contains(self, other): """Returns True if the geometry contains the other, else False""" return bool(self.impl['contains'](self, other)) def crosses(self, other): """Returns True if the geometries cross, else False""" return bool(self.impl['crosses'](self, other)) def disjoint(self, other): """Returns True if geometries are disjoint, else False""" return bool(self.impl['disjoint'](self, other)) def equals(self, other): """Returns True if geometries are equal, else False""" return bool(self.impl['equals'](self, other)) def intersects(self, other): """Returns True if geometries intersect, else False""" return bool(self.impl['intersects'](self, other)) def overlaps(self, other): """Returns True if geometries overlap, else False""" return bool(self.impl['overlaps'](self, other)) def touches(self, other): """Returns True if geometries touch, else False""" return bool(self.impl['touches'](self, other)) def within(self, other): """Returns True if geometry is within the other, else False""" return bool(self.impl['within'](self, other)) def equals_exact(self, other, tolerance): """Returns True if geometries are equal to within a specified tolerance""" # return BinaryPredicateOp('equals_exact', self)(other, tolerance) return bool(self.impl['equals_exact'](self, other, tolerance)) def almost_equals(self, other, decimal=6): """Returns True if geometries are equal at all coordinates to a specified decimal place""" return self.equals_exact(other, 0.5 * 10**(-decimal)) # Linear referencing # ------------------ @delegated def project(self, other, normalized=False): """Returns the distance along this geometry to a point nearest the specified point If the normalized arg is True, return the distance normalized to the length of the linear geometry. """ if normalized: op = self.impl['project_normalized'] else: op = self.impl['project'] return op(self, other) @delegated def interpolate(self, distance, normalized=False): """Return a point at the specified distance along a linear geometry If the normalized arg is True, the distance will be interpreted as a fraction of the geometry's length. """ if normalized: op = self.impl['interpolate_normalized'] else: op = self.impl['interpolate'] return geom_factory(op(self, distance)) class BaseMultipartGeometry(BaseGeometry): def shape_factory(self, *args): # Factory for part instances, usually a geometry class raise NotImplementedError("To be implemented by derived classes") @property def ctypes(self): raise NotImplementedError( "Multi-part geometries have no ctypes representations") @property def __array_interface__(self): """Provide the Numpy array protocol.""" raise NotImplementedError("Multi-part geometries do not themselves " "provide the array interface") def _get_coords(self): raise NotImplementedError("Sub-geometries may have coordinate " "sequences, but collections do not") def _set_coords(self, ob): raise NotImplementedError("Sub-geometries may have coordinate " "sequences, but collections do not") @property def coords(self): raise NotImplementedError( "Multi-part geometries do not provide a coordinate sequence") @property def geoms(self): if self.is_empty: return [] return GeometrySequence(self, self.shape_factory) def __iter__(self): if not self.is_empty: return iter(self.geoms) else: return iter([]) def __len__(self): if not self.is_empty: return len(self.geoms) else: return 0 def __getitem__(self, index): if not self.is_empty: return self.geoms[index] else: return ()[index] class GeometrySequence(object): """ Iterative access to members of a homogeneous multipart geometry. """ # Attributes # ---------- # _factory : callable # Returns instances of Shapely geometries # _geom : c_void_p # Ctypes pointer to the parent's GEOS geometry # _ndim : int # Number of dimensions (2 or 3, generally) # __p__ : object # Parent (Shapely) geometry shape_factory = None _geom = None __p__ = None _ndim = None def __init__(self, parent, type): self.shape_factory = type self.__p__ = parent def _update(self): self._geom = self.__p__._geom self._ndim = self.__p__._ndim def _get_geom_item(self, i): g = self.shape_factory() g._owned = True g._geom = lgeos.GEOSGetGeometryN(self._geom, i) g._ndim = self._ndim g.__p__ = self return g def __iter__(self): self._update() for i in range(self.__len__()): yield self._get_geom_item(i) def __len__(self): self._update() return lgeos.GEOSGetNumGeometries(self._geom) def __getitem__(self, key): self._update() m = self.__len__() if isinstance(key, int): if key + m < 0 or key >= m: raise IndexError("index out of range") if key < 0: i = m + key else: i = key return self._get_geom_item(i) elif isinstance(key, slice): if type(self) == HeterogeneousGeometrySequence: raise TypeError( "Heterogenous geometry collections are not sliceable") res = [] start, stop, stride = key.indices(m) for i in range(start, stop, stride): res.append(self._get_geom_item(i)) return type(self.__p__)(res or None) else: raise TypeError("key must be an index or slice") @property def _longest(self): max = 0 for g in iter(self): l = len(g.coords) if l > max: max = l class HeterogeneousGeometrySequence(GeometrySequence): """ Iterative access to a heterogeneous sequence of geometries. """ def __init__(self, parent): super(HeterogeneousGeometrySequence, self).__init__(parent, None) def _get_geom_item(self, i): sub = lgeos.GEOSGetGeometryN(self._geom, i) g = geom_factory(sub, parent=self) g._owned = True return g def _test(): """Test runner""" import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/collection.py000066400000000000000000000016261226057120100211260ustar00rootroot00000000000000"""Multi-part collections of geometries """ from shapely.geometry.base import BaseMultipartGeometry from shapely.geometry.base import HeterogeneousGeometrySequence class GeometryCollection(BaseMultipartGeometry): """A heterogenous collection of geometries Attributes ---------- geoms : sequence A sequence of Shapely geometry instances """ def __init__(self): BaseMultipartGeometry.__init__(self) @property def __geo_interface__(self): geometries = [] for geom in self.geoms: geometries.append(geom.__geo_interface__) return dict(type='GeometryCollection', geometries=geometries) @property def geoms(self): if self.is_empty: return [] return HeterogeneousGeometrySequence(self) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/geo.py000066400000000000000000000050561226057120100175460ustar00rootroot00000000000000""" Geometry factories based on the geo interface """ from .point import Point, asPoint from .linestring import LineString, asLineString from .polygon import Polygon, asPolygon from .multipoint import MultiPoint, asMultiPoint from .multilinestring import MultiLineString, asMultiLineString from .multipolygon import MultiPolygon, MultiPolygonAdapter def box(minx, miny, maxx, maxy, ccw=True): """Returns a rectangular polygon with configurable normal vector""" coords = [(maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)] if not ccw: coords = coords[::-1] return Polygon(coords) def shape(context): """Returns a new, independent geometry with coordinates *copied* from the context. """ if hasattr(context, "__geo_interface__"): ob = context.__geo_interface__ else: ob = context geom_type = ob.get("type").lower() if geom_type == "point": return Point(ob["coordinates"]) elif geom_type == "linestring": return LineString(ob["coordinates"]) elif geom_type == "polygon": return Polygon(ob["coordinates"][0], ob["coordinates"][1:]) elif geom_type == "multipoint": return MultiPoint(ob["coordinates"]) elif geom_type == "multilinestring": return MultiLineString(ob["coordinates"]) elif geom_type == "multipolygon": return MultiPolygon(ob["coordinates"], context_type='geojson') else: raise ValueError("Unknown geometry type: %s" % geom_type) def asShape(context): """Adapts the context to a geometry interface. The coordinates remain stored in the context. """ if hasattr(context, "__geo_interface__"): ob = context.__geo_interface__ else: ob = context try: geom_type = ob.get("type").lower() except AttributeError: raise ValueError("Context does not provide geo interface") if geom_type == "point": return asPoint(ob["coordinates"]) elif geom_type == "linestring": return asLineString(ob["coordinates"]) elif geom_type == "polygon": return asPolygon(ob["coordinates"][0], ob["coordinates"][1:]) elif geom_type == "multipoint": return asMultiPoint(ob["coordinates"]) elif geom_type == "multilinestring": return asMultiLineString(ob["coordinates"]) elif geom_type == "multipolygon": return MultiPolygonAdapter(ob["coordinates"], context_type='geojson') else: raise ValueError("Unknown geometry type: %s" % geom_type) def mapping(ob): """Returns a GeoJSON-like mapping""" return ob.__geo_interface__ Shapely-1.3.0/shapely/geometry/linestring.py000066400000000000000000000204331226057120100211460ustar00rootroot00000000000000"""Line strings and related utilities """ import sys if sys.version_info[0] < 3: range = xrange from ctypes import c_double, cast, POINTER from shapely.coords import required from shapely.geos import lgeos, TopologicalError from shapely.geometry.base import BaseGeometry, geom_factory, JOIN_STYLE from shapely.geometry.proxy import CachingGeometryProxy __all__ = ['LineString', 'asLineString'] class LineString(BaseGeometry): """ A one-dimensional figure comprising one or more line segments A LineString has non-zero length and zero area. It may approximate a curve and need not be straight. Unlike a LinearRing, a LineString is not closed. """ def __init__(self, coordinates=None): """ Parameters ---------- coordinates : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples or an object that provides the numpy array interface, including another instance of LineString. Example ------- Create a line with two segments >>> a = LineString([[0, 0], [1, 0], [1, 1]]) >>> a.length 2.0 """ BaseGeometry.__init__(self) if coordinates is not None: self._set_coords(coordinates) @property def __geo_interface__(self): return { 'type': 'LineString', 'coordinates': tuple(self.coords) } @property def ctypes(self): if not self._ctypes_data: self._ctypes_data = self.coords.ctypes return self._ctypes_data def array_interface(self): """Provide the Numpy array protocol.""" return self.coords.array_interface() __array_interface__ = property(array_interface) # Coordinate access def _set_coords(self, coordinates): self.empty() self._geom, self._ndim = geos_linestring_from_py(coordinates) coords = property(BaseGeometry._get_coords, _set_coords) @property def xy(self): """Separate arrays of X and Y coordinate values Example: >>> x, y = LineString(((0, 0), (1, 1))).xy >>> list(x) [0.0, 1.0] >>> list(y) [0.0, 1.0] """ return self.coords.xy def parallel_offset( self, distance, side, resolution=16, join_style=JOIN_STYLE.round, mitre_limit=1.0): """Returns a LineString or MultiLineString geometry at a distance from the object on its right or its left side. Distance must be a positive float value. The side parameter may be 'left' or 'right'. The resolution of the buffer around each vertex of the object increases by increasing the resolution keyword parameter or third positional parameter. The join style is for outside corners between line segments. Accepted values are JOIN_STYLE.round (1), JOIN_STYLE.mitre (2), and JOIN_STYLE.bevel (3). The mitre ratio limit is used for very sharp corners. It is the ratio of the distance from the corner to the end of the mitred offset corner. When two line segments meet at a sharp angle, a miter join will extend far beyond the original geometry. To prevent unreasonable geometry, the mitre limit allows controlling the maximum length of the join corner. Corners with a ratio which exceed the limit will be beveled.""" try: return geom_factory(self.impl['parallel_offset']( self, distance, resolution, join_style, mitre_limit, bool(side == 'left'))) except WindowsError: raise TopologicalError() class LineStringAdapter(CachingGeometryProxy, LineString): def __init__(self, context): self.context = context self.factory = geos_linestring_from_py @property def _ndim(self): try: # From array protocol array = self.context.__array_interface__ n = array['shape'][1] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.context[0]) @property def __array_interface__(self): """Provide the Numpy array protocol.""" try: return self.context.__array_interface__ except AttributeError: return self.array_interface() _get_coords = BaseGeometry._get_coords def _set_coords(self, ob): raise NotImplementedError( "Adapters can not modify their coordinate sources") coords = property(_get_coords) def asLineString(context): """Adapt an object the LineString interface""" return LineStringAdapter(context) def geos_linestring_from_py(ob, update_geom=None, update_ndim=0): # If numpy is present, we use numpy.require to ensure that we have a # C-continguous array that owns its data. View data will be copied. ob = required(ob) try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 2 m = array['shape'][0] if m < 2: raise ValueError( "LineStrings must have at least 2 coordinate tuples") try: n = array['shape'][1] except IndexError: raise ValueError( "Input %s is the wrong shape for a LineString" % str(ob)) assert n == 2 or n == 3 # Make pointer to the coordinate array if isinstance(array['data'], tuple): # numpy tuple (addr, read-only) cp = cast(array['data'][0], POINTER(c_double)) else: cp = array['data'] # Create a coordinate sequence if update_geom is not None: cs = lgeos.GEOSGeom_getCoordSeq(update_geom) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has " "dimensions: %d" % update_ndim) else: cs = lgeos.GEOSCoordSeq_create(m, n) # add to coordinate sequence for i in range(m): dx = c_double(cp[n*i]) dy = c_double(cp[n*i+1]) dz = None if n == 3: try: dz = c_double(cp[n*i+2]) except IndexError: raise ValueError("Inconsistent coordinate dimensionality") # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, i, dx) lgeos.GEOSCoordSeq_setY(cs, i, dy) if n == 3: lgeos.GEOSCoordSeq_setZ(cs, i, dz) except AttributeError: # Fall back on list try: m = len(ob) except TypeError: # Iterators, e.g. Python 3 zip ob = list(ob) m = len(ob) if m < 2: raise ValueError( "LineStrings must have at least 2 coordinate tuples") try: n = len(ob[0]) except TypeError: raise ValueError( "Input %s is the wrong shape for a LineString" % str(ob)) assert n == 2 or n == 3 # Create a coordinate sequence if update_geom is not None: cs = lgeos.GEOSGeom_getCoordSeq(update_geom) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has " "dimensions: %d" % update_ndim) else: cs = lgeos.GEOSCoordSeq_create(m, n) # add to coordinate sequence for i in range(m): coords = ob[i] # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, i, coords[0]) lgeos.GEOSCoordSeq_setY(cs, i, coords[1]) if n == 3: try: lgeos.GEOSCoordSeq_setZ(cs, i, coords[2]) except IndexError: raise ValueError("Inconsistent coordinate dimensionality") if update_geom is not None: return None else: return lgeos.GEOSGeom_createLineString(cs), n def update_linestring_from_py(geom, ob): geos_linestring_from_py(ob, geom._geom, geom._ndim) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/multilinestring.py000066400000000000000000000071201226057120100222170ustar00rootroot00000000000000"""Collections of linestrings and related utilities """ import sys if sys.version_info[0] < 3: range = xrange from ctypes import c_double, c_void_p, cast, POINTER from shapely.geos import lgeos from shapely.geometry.base import BaseMultipartGeometry from shapely.geometry.linestring import LineString, geos_linestring_from_py from shapely.geometry.proxy import CachingGeometryProxy __all__ = ['MultiLineString', 'asMultiLineString'] class MultiLineString(BaseMultipartGeometry): """ A collection of one or more line strings A MultiLineString has non-zero length and zero area. Attributes ---------- geoms : sequence A sequence of LineStrings """ def __init__(self, lines=None): """ Parameters ---------- lines : sequence A sequence of line-like coordinate sequences or objects that provide the numpy array interface, including instances of LineString. Example ------- Construct a collection containing one line string. >>> lines = MultiLineString( [[[0.0, 0.0], [1.0, 2.0]]] ) """ super(MultiLineString, self).__init__() if not lines: # allow creation of empty multilinestrings, to support unpickling pass else: self._geom, self._ndim = geos_multilinestring_from_py(lines) def shape_factory(self, *args): return LineString(*args) @property def __geo_interface__(self): return { 'type': 'MultiLineString', 'coordinates': tuple(tuple(c for c in g.coords) for g in self.geoms) } class MultiLineStringAdapter(CachingGeometryProxy, MultiLineString): context = None _owned = False def __init__(self, context): self.context = context self.factory = geos_multilinestring_from_py @property def _ndim(self): try: # From array protocol array = self.context[0].__array_interface__ n = array['shape'][1] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.context[0][0]) def asMultiLineString(context): """Adapts a sequence of objects to the MultiLineString interface""" return MultiLineStringAdapter(context) def geos_multilinestring_from_py(ob): # ob must be either a sequence or array of sequences or arrays try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 1 L = array['shape'][0] assert L >= 1 # Array of pointers to sub-geometries subs = (c_void_p * L)() for l in range(L): geom, ndims = geos_linestring_from_py(array['data'][l]) subs[i] = cast(geom, c_void_p) N = lgeos.GEOSGeom_getDimensions(subs[0]) except (NotImplementedError, AttributeError): obs = getattr(ob, 'geoms', ob) L = len(obs) exemplar = obs[0] try: N = len(exemplar[0]) except TypeError: N = exemplar._ndim assert L >= 1 assert N == 2 or N == 3 # Array of pointers to point geometries subs = (c_void_p * L)() # add to coordinate sequence for l in range(L): geom, ndims = geos_linestring_from_py(obs[l]) subs[l] = cast(geom, c_void_p) return (lgeos.GEOSGeom_createCollection(5, subs, L), N) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/multipoint.py000066400000000000000000000122411226057120100211720ustar00rootroot00000000000000"""Collections of points and related utilities """ import sys if sys.version_info[0] < 3: range = xrange from ctypes import byref, c_double, c_void_p, cast, POINTER from ctypes import ArgumentError from shapely.coords import required from shapely.geos import lgeos from shapely.geometry.base import BaseMultipartGeometry, exceptNull from shapely.geometry.point import Point, geos_point_from_py from shapely.geometry.proxy import CachingGeometryProxy __all__ = ['MultiPoint', 'asMultiPoint'] class MultiPoint(BaseMultipartGeometry): """A collection of one or more points A MultiPoint has zero area and zero length. Attributes ---------- geoms : sequence A sequence of Points """ def __init__(self, points=None): """ Parameters ---------- points : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples or a sequence of objects that implement the numpy array interface, including instaces of Point. Example ------- Construct a 2 point collection >>> ob = MultiPoint([[0.0, 0.0], [1.0, 2.0]]) >>> len(ob.geoms) 2 >>> type(ob.geoms[0]) == Point True """ super(MultiPoint, self).__init__() if points is None: # allow creation of empty multipoints, to support unpickling pass else: self._geom, self._ndim = geos_multipoint_from_py(points) def shape_factory(self, *args): return Point(*args) @property def __geo_interface__(self): return { 'type': 'MultiPoint', 'coordinates': tuple([g.coords[0] for g in self.geoms]) } @property @exceptNull def ctypes(self): if not self._ctypes_data: temp = c_double() n = self._ndim m = len(self.geoms) array_type = c_double * (m * n) data = array_type() for i in range(m): g = self.geoms[i]._geom cs = lgeos.GEOSGeom_getCoordSeq(g) lgeos.GEOSCoordSeq_getX(cs, 0, byref(temp)) data[n*i] = temp.value lgeos.GEOSCoordSeq_getY(cs, 0, byref(temp)) data[n*i+1] = temp.value if n == 3: # TODO: use hasz lgeos.GEOSCoordSeq_getZ(cs, 0, byref(temp)) data[n*i+2] = temp.value self._ctypes_data = data return self._ctypes_data @exceptNull def array_interface(self): """Provide the Numpy array protocol.""" ai = self.array_interface_base ai.update({'shape': (len(self.geoms), self._ndim)}) return ai __array_interface__ = property(array_interface) class MultiPointAdapter(CachingGeometryProxy, MultiPoint): context = None _owned = False def __init__(self, context): self.context = context self.factory = geos_multipoint_from_py @property def _ndim(self): try: # From array protocol array = self.context.__array_interface__ n = array['shape'][1] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.context[0]) @property def __array_interface__(self): """Provide the Numpy array protocol.""" try: return self.context.__array_interface__ except AttributeError: return self.array_interface() def asMultiPoint(context): """Adapt a sequence of objects to the MultiPoint interface""" return MultiPointAdapter(context) def geos_multipoint_from_py(ob): # If numpy is present, we use numpy.require to ensure that we have a # C-continguous array that owns its data. View data will be copied. ob = required(ob) try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 2 m = array['shape'][0] n = array['shape'][1] assert m >= 1 assert n == 2 or n == 3 # Make pointer to the coordinate array if isinstance(array['data'], tuple): # numpy tuple (addr, read-only) cp = cast(array['data'][0], POINTER(c_double)) else: cp = array['data'] # Array of pointers to sub-geometries subs = (c_void_p * m)() for i in range(m): geom, ndims = geos_point_from_py(cp[n*i:n*i+2]) subs[i] = cast(geom, c_void_p) except AttributeError: # Fall back on list m = len(ob) try: n = len(ob[0]) except TypeError: n = ob[0]._ndim assert n == 2 or n == 3 # Array of pointers to point geometries subs = (c_void_p * m)() # add to coordinate sequence for i in range(m): coords = ob[i] geom, ndims = geos_point_from_py(coords) subs[i] = cast(geom, c_void_p) return lgeos.GEOSGeom_createCollection(4, subs, m), n # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/multipolygon.py000066400000000000000000000107001226057120100215260ustar00rootroot00000000000000"""Collections of polygons and related utilities """ import sys if sys.version_info[0] < 3: range = xrange from ctypes import c_void_p, cast from shapely.geos import lgeos from shapely.geometry.base import BaseMultipartGeometry from shapely.geometry.polygon import Polygon, geos_polygon_from_py from shapely.geometry.proxy import CachingGeometryProxy __all__ = ['MultiPolygon', 'asMultiPolygon'] class MultiPolygon(BaseMultipartGeometry): """A collection of one or more polygons If component polygons overlap the collection is `invalid` and some operations on it may fail. Attributes ---------- geoms : sequence A sequence of `Polygon` instances """ def __init__(self, polygons=None, context_type='polygons'): """ Parameters ---------- polygons : sequence A sequence of (shell, holes) tuples where shell is the sequence representation of a linear ring (see linearring.py) and holes is a sequence of such linear rings Example ------- Construct a collection from a sequence of coordinate tuples >>> ob = MultiPolygon( [ ... ( ... ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)), ... [((0.1,0.1), (0.1,0.2), (0.2,0.2), (0.2,0.1))] ... ) ... ] ) >>> len(ob.geoms) 1 >>> type(ob.geoms[0]) == Polygon True """ super(MultiPolygon, self).__init__() if not polygons: # allow creation of empty multipolygons, to support unpickling pass elif context_type == 'polygons': self._geom, self._ndim = geos_multipolygon_from_polygons(polygons) elif context_type == 'geojson': self._geom, self._ndim = geos_multipolygon_from_py(polygons) def shape_factory(self, *args): return Polygon(*args) @property def __geo_interface__(self): allcoords = [] for geom in self.geoms: coords = [] coords.append(tuple(geom.exterior.coords)) for hole in geom.interiors: coords.append(tuple(hole.coords)) allcoords.append(tuple(coords)) return { 'type': 'MultiPolygon', 'coordinates': allcoords } class MultiPolygonAdapter(CachingGeometryProxy, MultiPolygon): context = None _owned = False def __init__(self, context, context_type='polygons'): self.context = context if context_type == 'geojson': self.factory = geos_multipolygon_from_py elif context_type == 'polygons': self.factory = geos_multipolygon_from_polygons @property def _ndim(self): try: # From array protocol array = self.context[0][0].__array_interface__ n = array['shape'][1] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.context[0][0][0]) def asMultiPolygon(context): """Adapts a sequence of objects to the MultiPolygon interface""" return MultiPolygonAdapter(context) def geos_multipolygon_from_py(ob): """ob must provide Python geo interface coordinates.""" L = len(ob) assert L >= 1 N = len(ob[0][0][0]) assert N == 2 or N == 3 subs = (c_void_p * L)() for l in range(L): geom, ndims = geos_polygon_from_py(ob[l][0], ob[l][1:]) subs[l] = cast(geom, c_void_p) return (lgeos.GEOSGeom_createCollection(6, subs, L), N) def geos_multipolygon_from_polygons(ob): """ob must be either a sequence or array of sequences or arrays.""" obs = getattr(ob, 'geoms', None) or ob L = len(obs) assert L >= 1 exemplar = obs[0] try: N = len(exemplar[0][0]) except TypeError: N = exemplar._ndim assert N == 2 or N == 3 subs = (c_void_p * L)() for l in range(L): shell = getattr(obs[l], 'exterior', None) if shell is None: shell = obs[l][0] holes = getattr(obs[l], 'interiors', None) if holes is None: holes = obs[l][1] geom, ndims = geos_polygon_from_py(shell, holes) subs[l] = cast(geom, c_void_p) return (lgeos.GEOSGeom_createCollection(6, subs, L), N) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/point.py000066400000000000000000000144031226057120100201210ustar00rootroot00000000000000"""Points and related utilities """ from ctypes import c_double from ctypes import cast, POINTER from shapely.coords import required from shapely.geos import lgeos, DimensionError from shapely.geometry.base import BaseGeometry from shapely.geometry.proxy import CachingGeometryProxy __all__ = ['Point', 'asPoint'] class Point(BaseGeometry): """ A zero dimensional feature A point has zero length and zero area. Attributes ---------- x, y, z : float Coordinate values Example ------- >>> p = Point(1.0, -1.0) >>> print(p) POINT (1.0000000000000000 -1.0000000000000000) >>> p.y -1.0 >>> p.x 1.0 """ def __init__(self, *args): """ Parameters ---------- There are 2 cases: 1) 1 parameter: this must satisfy the numpy array protocol. 2) 2 or more parameters: x, y, z : float Easting, northing, and elevation. """ BaseGeometry.__init__(self) if len(args) > 0: self._set_coords(*args) # Coordinate getters and setters @property def x(self): """Return x coordinate.""" return self.coords[0][0] @property def y(self): """Return y coordinate.""" return self.coords[0][1] @property def z(self): """Return z coordinate.""" if self._ndim != 3: raise DimensionError("This point has no z coordinate.") return self.coords[0][2] @property def __geo_interface__(self): return { 'type': 'Point', 'coordinates': self.coords[0] } @property def ctypes(self): if not self._ctypes_data: array_type = c_double * self._ndim array = array_type() xy = self.coords[0] array[0] = xy[0] array[1] = xy[1] if self._ndim == 3: array[2] = xy[2] self._ctypes_data = array return self._ctypes_data def array_interface(self): """Provide the Numpy array protocol.""" ai = self.array_interface_base ai.update({'shape': (self._ndim,)}) return ai __array_interface__ = property(array_interface) @property def bounds(self): xy = self.coords[0] return (xy[0], xy[1], xy[0], xy[1]) # Coordinate access def _set_coords(self, *args): self.empty() if len(args) == 1: self._geom, self._ndim = geos_point_from_py(args[0]) else: self._geom, self._ndim = geos_point_from_py(tuple(args)) coords = property(BaseGeometry._get_coords, _set_coords) @property def xy(self): """Separate arrays of X and Y coordinate values Example: >>> x, y = Point(0, 0).xy >>> list(x) [0.0] >>> list(y) [0.0] """ return self.coords.xy class PointAdapter(CachingGeometryProxy, Point): _owned = False def __init__(self, context): self.context = context self.factory = geos_point_from_py @property def _ndim(self): try: # From array protocol array = self.context.__array_interface__ n = array['shape'][0] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.context) @property def __array_interface__(self): """Provide the Numpy array protocol.""" try: return self.context.__array_interface__ except AttributeError: return self.array_interface() _get_coords = BaseGeometry._get_coords def _set_coords(self, ob): raise NotImplementedError("Adapters can not modify their sources") coords = property(_get_coords) def asPoint(context): """Adapt an object to the Point interface""" return PointAdapter(context) def geos_point_from_py(ob, update_geom=None, update_ndim=0): """Create a GEOS geom from an object that is a coordinate sequence or that provides the array interface. Returns the GEOS geometry and the number of its dimensions. """ # If numpy is present, we use numpy.require to ensure that we have a # C-continguous array that owns its data. View data will be copied. ob = required(ob) try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 1 n = array['shape'][0] assert n == 2 or n == 3 dz = None da = array['data'] if isinstance(da, tuple): cdata = da[0] # If we had numpy, we would do # from numpy.ctypeslib import as_ctypes # cp = as_ctypes(ob) - check that code? cp = cast(cdata, POINTER(c_double)) dx = c_double(cp[0]) dy = c_double(cp[1]) if n == 3: dz = c_double(cp[2]) else: dx, dy = da[0:2] if n == 3: dz = da[2] except AttributeError: # Fall back on the case of Python sequence data # Accept either (x, y) or [(x, y)] if not hasattr(ob, '__getitem__'): # Iterators, e.g. Python 3 zip ob = list(ob) if isinstance(ob[0], tuple): coords = ob[0] else: coords = ob n = len(coords) dx = c_double(coords[0]) dy = c_double(coords[1]) dz = None if n == 3: dz = c_double(coords[2]) if update_geom: cs = lgeos.GEOSGeom_getCoordSeq(update_geom) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: " "%d" % update_ndim) else: cs = lgeos.GEOSCoordSeq_create(1, n) # Because of a bug in the GEOS C API, always set X before Y lgeos.GEOSCoordSeq_setX(cs, 0, dx) lgeos.GEOSCoordSeq_setY(cs, 0, dy) if n == 3: lgeos.GEOSCoordSeq_setZ(cs, 0, dz) if update_geom: return None else: return lgeos.GEOSGeom_createPoint(cs), n def update_point_from_py(geom, ob): geos_point_from_py(ob, geom._geom, geom._ndim) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/polygon.py000066400000000000000000000335261226057120100204660ustar00rootroot00000000000000"""Polygons and their linear ring components """ import sys if sys.version_info[0] < 3: range = xrange from ctypes import c_double, c_void_p, cast, POINTER from ctypes import ArgumentError import weakref from shapely.algorithms.cga import signed_area from shapely.coords import required from shapely.geos import lgeos from shapely.geometry.base import BaseGeometry from shapely.geometry.linestring import LineString, LineStringAdapter from shapely.geometry.proxy import PolygonProxy __all__ = ['Polygon', 'asPolygon', 'LinearRing', 'asLinearRing'] class LinearRing(LineString): """ A closed one-dimensional feature comprising one or more line segments A LinearRing that crosses itself or touches itself at a single point is invalid and operations on it may fail. """ def __init__(self, coordinates=None): """ Parameters ---------- coordinates : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples Rings are implicitly closed. There is no need to specific a final coordinate pair identical to the first. Example ------- Construct a square ring. >>> ring = LinearRing( ((0, 0), (0, 1), (1 ,1 ), (1 , 0)) ) >>> ring.is_closed True >>> ring.length 4.0 """ BaseGeometry.__init__(self) if coordinates is not None: self._set_coords(coordinates) @property def __geo_interface__(self): return { 'type': 'LinearRing', 'coordinates': tuple(self.coords) } # Coordinate access _get_coords = BaseGeometry._get_coords def _set_coords(self, coordinates): self.empty() self._geom, self._ndim = geos_linearring_from_py(coordinates) coords = property(_get_coords, _set_coords) @property def is_ccw(self): """True is the ring is oriented counter clock-wise""" return bool(self.impl['is_ccw'](self)) @property def is_simple(self): """True if the geometry is simple, meaning that any self-intersections are only at boundary points, else False""" return LineString(self).is_simple class LinearRingAdapter(LineStringAdapter): __p__ = None def __init__(self, context): self.context = context self.factory = geos_linearring_from_py @property def __geo_interface__(self): return { 'type': 'LinearRing', 'coordinates': tuple(self.coords) } coords = property(BaseGeometry._get_coords) def asLinearRing(context): """Adapt an object to the LinearRing interface""" return LinearRingAdapter(context) class InteriorRingSequence(object): _factory = None _geom = None __p__ = None _ndim = None _index = 0 _length = 0 __rings__ = None _gtag = None def __init__(self, parent): self.__p__ = parent self._geom = parent._geom self._ndim = parent._ndim def __iter__(self): self._index = 0 self._length = self.__len__() return self def __next__(self): if self._index < self._length: ring = self._get_ring(self._index) self._index += 1 return ring else: raise StopIteration if sys.version_info[0] < 3: next = __next__ def __len__(self): return lgeos.GEOSGetNumInteriorRings(self._geom) def __getitem__(self, key): m = self.__len__() if isinstance(key, int): if key + m < 0 or key >= m: raise IndexError("index out of range") if key < 0: i = m + key else: i = key return self._get_ring(i) elif isinstance(key, slice): res = [] start, stop, stride = key.indices(m) for i in range(start, stop, stride): res.append(self._get_ring(i)) return res else: raise TypeError("key must be an index or slice") @property def _longest(self): max = 0 for g in iter(self): l = len(g.coords) if l > max: max = l def gtag(self): return hash(repr(self.__p__)) def _get_ring(self, i): gtag = self.gtag() if gtag != self._gtag: self.__rings__ = {} if i not in self.__rings__: g = lgeos.GEOSGetInteriorRingN(self._geom, i) ring = LinearRing() ring.__geom__ = g ring.__p__ = self ring._owned = True ring._ndim = self._ndim self.__rings__[i] = weakref.ref(ring) return self.__rings__[i]() class Polygon(BaseGeometry): """ A two-dimensional figure bounded by a linear ring A polygon has a non-zero area. It may have one or more negative-space "holes" which are also bounded by linear rings. If any rings cross each other, the feature is invalid and operations on it may fail. Attributes ---------- exterior : LinearRing The ring which bounds the positive space of the polygon. interiors : sequence A sequence of rings which bound all existing holes. """ _exterior = None _interiors = [] _ndim = 2 def __init__(self, shell=None, holes=None): """ Parameters ---------- shell : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples holes : sequence A sequence of objects which satisfy the same requirements as the shell parameters above Example ------- Create a square polygon with no holes >>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)) >>> polygon = Polygon(coords) >>> polygon.area 1.0 """ BaseGeometry.__init__(self) if shell is not None: self._geom, self._ndim = geos_polygon_from_py(shell, holes) @property def exterior(self): if self.is_empty: return None elif self._exterior is None or self._exterior() is None: g = lgeos.GEOSGetExteriorRing(self._geom) ring = LinearRing() ring.__geom__ = g ring.__p__ = self ring._owned = True ring._ndim = self._ndim self._exterior = weakref.ref(ring) return self._exterior() @property def interiors(self): if self.is_empty: return [] return InteriorRingSequence(self) @property def ctypes(self): if not self._ctypes_data: self._ctypes_data = self.exterior.ctypes return self._ctypes_data @property def __array_interface__(self): raise NotImplementedError( "A polygon does not itself provide the array interface. Its rings do.") def _get_coords(self): raise NotImplementedError( "Component rings have coordinate sequences, but the polygon does not") def _set_coords(self, ob): raise NotImplementedError( "Component rings have coordinate sequences, but the polygon does not") @property def coords(self): raise NotImplementedError( "Component rings have coordinate sequences, but the polygon does not") @property def __geo_interface__(self): coords = [tuple(self.exterior.coords)] for hole in self.interiors: coords.append(tuple(hole.coords)) return { 'type': 'Polygon', 'coordinates': tuple(coords) } class PolygonAdapter(PolygonProxy, Polygon): def __init__(self, shell, holes=None): self.shell = shell self.holes = holes self.context = (shell, holes) self.factory = geos_polygon_from_py @property def _ndim(self): try: # From array protocol array = self.shell.__array_interface__ n = array['shape'][1] assert n == 2 or n == 3 return n except AttributeError: # Fall back on list return len(self.shell[0]) def asPolygon(shell, holes=None): """Adapt objects to the Polygon interface""" return PolygonAdapter(shell, holes) def orient(polygon, sign=1.0): s = float(sign) rings = [] ring = polygon.exterior if signed_area(ring)/s >= 0.0: rings.append(ring) else: rings.append(list(ring.coords)[::-1]) for ring in polygon.interiors: if signed_area(ring)/s <= 0.0: rings.append(ring) else: rings.append(list(ring.coords)[::-1]) return Polygon(rings[0], rings[1:]) def geos_linearring_from_py(ob, update_geom=None, update_ndim=0): # If numpy is present, we use numpy.require to ensure that we have a # C-continguous array that owns its data. View data will be copied. ob = required(ob) try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 2 m = array['shape'][0] n = array['shape'][1] if m < 3: raise ValueError( "A LinearRing must have at least 3 coordinate tuples") assert n == 2 or n == 3 # Make pointer to the coordinate array if isinstance(array['data'], tuple): # numpy tuple (addr, read-only) cp = cast(array['data'][0], POINTER(c_double)) else: cp = array['data'] # Add closing coordinates to sequence? if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]: M = m + 1 else: M = m # Create a coordinate sequence if update_geom is not None: cs = lgeos.GEOSGeom_getCoordSeq(update_geom) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = lgeos.GEOSCoordSeq_create(M, n) # add to coordinate sequence for i in range(m): # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, i, cp[n*i]) lgeos.GEOSCoordSeq_setY(cs, i, cp[n*i+1]) if n == 3: lgeos.GEOSCoordSeq_setZ(cs, i, cp[n*i+2]) # Add closing coordinates to sequence? if M > m: # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, M-1, cp[0]) lgeos.GEOSCoordSeq_setY(cs, M-1, cp[1]) if n == 3: lgeos.GEOSCoordSeq_setZ(cs, M-1, cp[2]) except AttributeError: # Fall back on list try: m = len(ob) except TypeError: # Iterators, e.g. Python 3 zip ob = list(ob) m = len(ob) n = len(ob[0]) if m < 3: raise ValueError( "A LinearRing must have at least 3 coordinate tuples") assert (n == 2 or n == 3) # Add closing coordinates if not provided if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]: M = m + 1 else: M = m # Create a coordinate sequence if update_geom is not None: cs = lgeos.GEOSGeom_getCoordSeq(update_geom) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = lgeos.GEOSCoordSeq_create(M, n) # add to coordinate sequence for i in range(m): coords = ob[i] # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, i, coords[0]) lgeos.GEOSCoordSeq_setY(cs, i, coords[1]) if n == 3: try: lgeos.GEOSCoordSeq_setZ(cs, i, coords[2]) except IndexError: raise ValueError("Inconsistent coordinate dimensionality") # Add closing coordinates to sequence? if M > m: coords = ob[0] # Because of a bug in the GEOS C API, # always set X before Y lgeos.GEOSCoordSeq_setX(cs, M-1, coords[0]) lgeos.GEOSCoordSeq_setY(cs, M-1, coords[1]) if n == 3: lgeos.GEOSCoordSeq_setZ(cs, M-1, coords[2]) if update_geom is not None: return None else: return lgeos.GEOSGeom_createLinearRing(cs), n def update_linearring_from_py(geom, ob): geos_linearring_from_py(ob, geom._geom, geom._ndim) def geos_polygon_from_py(shell, holes=None): if shell is not None: geos_shell, ndim = geos_linearring_from_py(shell) if holes is not None and len(holes) > 0: ob = holes L = len(ob) exemplar = ob[0] try: N = len(exemplar[0]) except TypeError: N = exemplar._ndim if not L >= 1: raise ValueError("number of holes must be non zero") if not N in (2, 3): raise ValueError("insufficiant coordinate dimension") # Array of pointers to ring geometries geos_holes = (c_void_p * L)() # add to coordinate sequence for l in range(L): geom, ndim = geos_linearring_from_py(ob[l]) geos_holes[l] = cast(geom, c_void_p) else: geos_holes = POINTER(c_void_p)() L = 0 return ( lgeos.GEOSGeom_createPolygon( c_void_p(geos_shell), geos_holes, L ), ndim ) # Test runner def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Shapely-1.3.0/shapely/geometry/proxy.py000066400000000000000000000024421226057120100201510ustar00rootroot00000000000000"""Proxy for coordinates stored outside Shapely geometries """ from shapely.geometry.base import deserialize_wkb, EMPTY from shapely.geos import lgeos class CachingGeometryProxy(object): context = None factory = None __geom__ = EMPTY _gtag = None def __init__(self, context): self.context = context @property def _is_empty(self): return self.__geom__ in [EMPTY, None] def empty(self): if not self._is_empty: lgeos.GEOSGeom_destroy(self.__geom__) self.__geom__ = EMPTY @property def _geom(self): """Keeps the GEOS geometry in synch with the context.""" gtag = self.gtag() if gtag != self._gtag or self._is_empty: self.empty() self.__geom__, n = self.factory(self.context) self._gtag = gtag return self.__geom__ def gtag(self): return hash(repr(self.context)) class PolygonProxy(CachingGeometryProxy): @property def _geom(self): """Keeps the GEOS geometry in synch with the context.""" gtag = self.gtag() if gtag != self._gtag or self._is_empty: self.empty() self.__geom__, n = self.factory(self.context[0], self.context[1]) self._gtag = gtag return self.__geom__ Shapely-1.3.0/shapely/geos.py000066400000000000000000000574611226057120100161050ustar00rootroot00000000000000""" Proxies for the libgeos_c shared lib, GEOS-specific exceptions, and utilities """ import os import re import sys import atexit import logging import threading from ctypes import CDLL, cdll, pointer, c_void_p, c_size_t, c_char_p, string_at from ctypes.util import find_library from . import ftools from .ctypes_declarations import prototype, EXCEPTION_HANDLER_FUNCTYPE # Add message handler to this module's logger LOG = logging.getLogger(__name__) if 'all' in sys.warnoptions: # show GEOS messages in console with: python -W all logging.basicConfig() else: # no handler messages shown class NullHandler(logging.Handler): def emit(self, record): pass LOG.addHandler(NullHandler()) # Find and load the GEOS and C libraries # If this ever gets any longer, we'll break it into separate modules def load_dll(libname, fallbacks=None): lib = find_library(libname) if lib is not None: return CDLL(lib) else: if fallbacks is not None: for name in fallbacks: try: return CDLL(name) except OSError: # move on to the next fallback pass # the end raise OSError( "Could not find library %s or load any of its variants %s" % ( libname, fallbacks or [])) if sys.platform.startswith('linux'): _lgeos = load_dll('geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so']) free = load_dll('c').free free.argtypes = [c_void_p] free.restype = None elif sys.platform == 'darwin': if hasattr(sys, 'frozen'): # .app file from py2app alt_paths = [os.path.join(os.environ['RESOURCEPATH'], '..', 'Frameworks', 'libgeos_c.dylib')] else: alt_paths = [ # The Framework build from Kyng Chaos: "/Library/Frameworks/GEOS.framework/Versions/Current/GEOS", # macports '/opt/local/lib/libgeos_c.dylib', ] _lgeos = load_dll('geos_c', fallbacks=alt_paths) free = load_dll('c').free free.argtypes = [c_void_p] free.restype = None elif sys.platform == 'win32': try: egg_dlls = os.path.abspath(os.path.join(os.path.dirname(__file__), "DLLs")) wininst_dlls = os.path.abspath(os.__file__ + "../../../DLLs") original_path = os.environ['PATH'] os.environ['PATH'] = "%s;%s;%s" % \ (egg_dlls, wininst_dlls, original_path) _lgeos = CDLL("geos.dll") except (ImportError, WindowsError, OSError): raise def free(m): try: cdll.msvcrt.free(m) except WindowsError: # XXX: See http://trac.gispython.org/projects/PCL/ticket/149 pass elif sys.platform == 'sunos5': _lgeos = load_dll('geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so']) free = CDLL('libc.so.1').free free.argtypes = [c_void_p] free.restype = None else: # other *nix systems _lgeos = load_dll('geos_c', fallbacks=['libgeos_c.so.1', 'libgeos_c.so']) free = load_dll('c', fallbacks=['libc.so.6']).free free.argtypes = [c_void_p] free.restype = None def _geos_version(): # extern const char GEOS_DLL *GEOSversion(); GEOSversion = _lgeos.GEOSversion GEOSversion.restype = c_char_p GEOSversion.argtypes = [] #define GEOS_CAPI_VERSION "@VERSION@-CAPI-@CAPI_VERSION@" geos_version_string = GEOSversion() if sys.version_info[0] >= 3: geos_version_string = geos_version_string.decode('ascii') res = re.findall(r'(\d+)\.(\d+)\.(\d+)', geos_version_string) assert len(res) == 2, res geos_version = tuple(int(x) for x in res[0]) capi_version = tuple(int(x) for x in res[1]) return geos_version_string, geos_version, capi_version geos_version_string, geos_version, geos_capi_version = _geos_version() # If we have the new interface, then record a baseline so that we know what # additional functions are declared in ctypes_declarations. if geos_version >= (3, 1, 0): start_set = set(_lgeos.__dict__) # Apply prototypes for the libgeos_c functions prototype(_lgeos, geos_version) # If we have the new interface, automatically detect all function # declarations, and declare their re-entrant counterpart. if geos_version >= (3, 1, 0): end_set = set(_lgeos.__dict__) new_func_names = end_set - start_set for func_name in new_func_names: new_func_name = "%s_r" % func_name if hasattr(_lgeos, new_func_name): new_func = getattr(_lgeos, new_func_name) old_func = getattr(_lgeos, func_name) new_func.restype = old_func.restype if old_func.argtypes is None: # Handle functions that didn't take an argument before, # finishGEOS. new_func.argtypes = [c_void_p] else: new_func.argtypes = [c_void_p] + old_func.argtypes if old_func.errcheck is not None: new_func.errcheck = old_func.errcheck # Handle special case. _lgeos.initGEOS_r.restype = c_void_p _lgeos.initGEOS_r.argtypes = \ [EXCEPTION_HANDLER_FUNCTYPE, EXCEPTION_HANDLER_FUNCTYPE] _lgeos.finishGEOS_r.argtypes = [c_void_p] # Exceptions class ReadingError(Exception): pass class DimensionError(Exception): pass class TopologicalError(Exception): pass class PredicateError(Exception): pass def error_handler(fmt, *args): if sys.version_info[0] >= 3: fmt = fmt.decode('ascii') args = [arg.decode('ascii') for arg in args] LOG.error(fmt, *args) def notice_handler(fmt, args): if sys.version_info[0] >= 3: fmt = fmt.decode('ascii') args = args.decode('ascii') LOG.warning(fmt, args) error_h = EXCEPTION_HANDLER_FUNCTYPE(error_handler) notice_h = EXCEPTION_HANDLER_FUNCTYPE(notice_handler) class WKTReader(object): _lgeos = None _reader = None def __init__(self, lgeos): """Create WKT Reader""" self._lgeos = lgeos self._reader = self._lgeos.GEOSWKTReader_create() def __del__(self): """Destroy WKT Reader""" if self._lgeos is not None: self._lgeos.GEOSWKTReader_destroy(self._reader) self._reader = None self._lgeos = None def read(self, text): """Returns geometry from WKT""" if sys.version_info[0] >= 3: text = text.encode('ascii') geom = self._lgeos.GEOSWKTReader_read(self._reader, c_char_p(text)) if not geom: raise ReadingError("Could not create geometry because of errors " "while reading input.") # avoid circular import dependency from shapely.geometry.base import geom_factory return geom_factory(geom) class WKTWriter(object): _lgeos = None _writer = None # Establish default output settings defaults = {} if geos_version >= (3, 3, 0): defaults['trim'] = True defaults['output_dimension'] = 3 # GEOS' defaults for methods without "get" _trim = False _rounding_precision = -1 _old_3d = False @property def trim(self): """Trimming of unnecessary decimals (default: True)""" return getattr(self, '_trim') @trim.setter def trim(self, value): self._trim = bool(value) self._lgeos.GEOSWKTWriter_setTrim(self._writer, self._trim) @property def rounding_precision(self): """Rounding precision when writing the WKT. A precision of -1 (default) disables it.""" return getattr(self, '_rounding_precision') @rounding_precision.setter def rounding_precision(self, value): self._rounding_precision = int(value) self._lgeos.GEOSWKTWriter_setRoundingPrecision( self._writer, self._rounding_precision) @property def output_dimension(self): """Output dimension, either 2 or 3 (default)""" return self._lgeos.GEOSWKTWriter_getOutputDimension( self._writer) @output_dimension.setter def output_dimension(self, value): self._lgeos.GEOSWKTWriter_setOutputDimension( self._writer, int(value)) @property def old_3d(self): """Show older style for 3D WKT, without 'Z' (default: False)""" return getattr(self, '_old_3d') @old_3d.setter def old_3d(self, value): self._old_3d = bool(value) self._lgeos.GEOSWKTWriter_setOld3D(self._writer, self._old_3d) def __init__(self, lgeos, **settings): """Create WKT Writer Note: writer defaults are set differently for GEOS 3.3.0 and up. For example, with 'POINT Z (1 2 3)': newer: POINT Z (1 2 3) older: POINT (1.0000000000000000 2.0000000000000000) The older formatting can be achieved for GEOS 3.3.0 and up by setting the properties: trim = False output_dimension = 2 """ self._lgeos = lgeos self._writer = self._lgeos.GEOSWKTWriter_create() applied_settings = self.defaults.copy() applied_settings.update(settings) for name in applied_settings: setattr(self, name, applied_settings[name]) def __setattr__(self, name, value): """Limit setting attributes""" if hasattr(self, name): object.__setattr__(self, name, value) else: raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, name)) def __del__(self): """Destroy WKT Writer""" if self._lgeos is not None: self._lgeos.GEOSWKTWriter_destroy(self._writer) self._writer = None self._lgeos = None def write(self, geom): """Returns WKT string for geometry""" if geom is None or geom._geom is None: raise ValueError("Null geometry supports no operations") result = self._lgeos.GEOSWKTWriter_write(self._writer, geom._geom) text = string_at(result) lgeos.GEOSFree(result) if sys.version_info[0] >= 3: return text.decode('ascii') else: return text class WKBReader(object): _lgeos = None _reader = None def __init__(self, lgeos): """Create WKB Reader""" self._lgeos = lgeos self._reader = self._lgeos.GEOSWKBReader_create() def __del__(self): """Destroy WKB Reader""" if self._lgeos is not None: self._lgeos.GEOSWKBReader_destroy(self._reader) self._reader = None self._lgeos = None def read(self, data): """Returns geometry from WKB""" geom = self._lgeos.GEOSWKBReader_read( self._reader, c_char_p(data), c_size_t(len(data))) if not geom: raise ReadingError("Could not create geometry because of errors " "while reading input.") # avoid circular import dependency from shapely import geometry return geometry.base.geom_factory(geom) def read_hex(self, data): """Returns geometry from WKB hex""" if sys.version_info[0] >= 3: data = data.encode('ascii') geom = self._lgeos.GEOSWKBReader_readHEX( self._reader, c_char_p(data), c_size_t(len(data))) if not geom: raise ReadingError("Could not create geometry because of errors " "while reading input.") # avoid circular import dependency from shapely import geometry return geometry.base.geom_factory(geom) class WKBWriter(object): _lgeos = None _writer = None # Establish default output setting defaults = {'output_dimension': 3} @property def output_dimension(self): """Output dimension, either 2 or 3 (default)""" return self._lgeos.GEOSWKBWriter_getOutputDimension(self._writer) @output_dimension.setter def output_dimension(self, value): self._lgeos.GEOSWKBWriter_setOutputDimension( self._writer, int(value)) @property def big_endian(self): """Byte order is big endian, True (default) or False""" return bool(self._lgeos.GEOSWKBWriter_getByteOrder(self._writer)) @big_endian.setter def big_endian(self, value): self._lgeos.GEOSWKBWriter_setByteOrder(self._writer, bool(value)) @property def include_srid(self): """Include SRID, True or False (default)""" return bool(self._lgeos.GEOSWKBWriter_getIncludeSRID(self._writer)) @include_srid.setter def include_srid(self, value): self._lgeos.GEOSWKBWriter_setIncludeSRID(self._writer, bool(value)) def __init__(self, lgeos, **settings): """Create WKB Writer""" self._lgeos = lgeos self._writer = self._lgeos.GEOSWKBWriter_create() applied_settings = self.defaults.copy() applied_settings.update(settings) for name in applied_settings: setattr(self, name, applied_settings[name]) def __setattr__(self, name, value): """Limit setting attributes""" if hasattr(self, name): object.__setattr__(self, name, value) else: raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, name)) def __del__(self): """Destroy WKB Writer""" if self._lgeos is not None: self._lgeos.GEOSWKBWriter_destroy(self._writer) self._writer = None self._lgeos = None def write(self, geom): """Returns WKB byte string for geometry""" if geom is None or geom._geom is None: raise ValueError("Null geometry supports no operations") size = c_size_t() result = self._lgeos.GEOSWKBWriter_write( self._writer, geom._geom, pointer(size)) data = string_at(result, size.value) lgeos.GEOSFree(result) return data def write_hex(self, geom): """Returns WKB hex string for geometry""" if geom is None or geom._geom is None: raise ValueError("Null geometry supports no operations") size = c_size_t() result = self._lgeos.GEOSWKBWriter_writeHEX( self._writer, geom._geom, pointer(size)) data = string_at(result, size.value) lgeos.GEOSFree(result) if sys.version_info[0] >= 3: return data.decode('ascii') else: return data # Errcheck functions for ctypes def errcheck_wkb(result, func, argtuple): '''Returns bytes from a C pointer''' if not result: return None size_ref = argtuple[-1] size = size_ref.contents retval = string_at(result, size.value)[:] lgeos.GEOSFree(result) return retval def errcheck_just_free(result, func, argtuple): '''Returns string from a C pointer''' retval = string_at(result) lgeos.GEOSFree(result) if sys.version_info[0] >= 3: return retval.decode('ascii') else: return retval def errcheck_predicate(result, func, argtuple): '''Result is 2 on exception, 1 on True, 0 on False''' if result == 2: raise PredicateError("Failed to evaluate %s" % repr(func)) return result class LGEOSBase(threading.local): """Proxy for GEOS C API This is a base class. Do not instantiate. """ methods = {} def __init__(self, dll): self._lgeos = dll self.geos_handle = None def __del__(self): """Cleanup GEOS related processes""" if self._lgeos is not None: self._lgeos.finishGEOS() self._lgeos = None self.geos_handle = None class LGEOS300(LGEOSBase): """Proxy for GEOS 3.0.0-CAPI-1.4.1 """ geos_version = (3, 0, 0) geos_capi_version = (1, 4, 0) def __init__(self, dll): super(LGEOS300, self).__init__(dll) self.geos_handle = self._lgeos.initGEOS(notice_h, error_h) keys = list(self._lgeos.__dict__.keys()) for key in keys: setattr(self, key, getattr(self._lgeos, key)) self.GEOSFree = self._lgeos.free # Deprecated self.GEOSGeomToWKB_buf.errcheck = errcheck_wkb self.GEOSGeomToWKT.errcheck = errcheck_just_free self.GEOSRelate.errcheck = errcheck_just_free for pred in ( self.GEOSDisjoint, self.GEOSTouches, self.GEOSIntersects, self.GEOSCrosses, self.GEOSWithin, self.GEOSContains, self.GEOSOverlaps, self.GEOSEquals, self.GEOSEqualsExact, self.GEOSisEmpty, self.GEOSisValid, self.GEOSisSimple, self.GEOSisRing, self.GEOSHasZ): pred.errcheck = errcheck_predicate self.methods['area'] = self.GEOSArea self.methods['boundary'] = self.GEOSBoundary self.methods['buffer'] = self.GEOSBuffer self.methods['centroid'] = self.GEOSGetCentroid self.methods['representative_point'] = self.GEOSPointOnSurface self.methods['convex_hull'] = self.GEOSConvexHull self.methods['distance'] = self.GEOSDistance self.methods['envelope'] = self.GEOSEnvelope self.methods['length'] = self.GEOSLength self.methods['has_z'] = self.GEOSHasZ self.methods['is_empty'] = self.GEOSisEmpty self.methods['is_ring'] = self.GEOSisRing self.methods['is_simple'] = self.GEOSisSimple self.methods['is_valid'] = self.GEOSisValid self.methods['disjoint'] = self.GEOSDisjoint self.methods['touches'] = self.GEOSTouches self.methods['intersects'] = self.GEOSIntersects self.methods['crosses'] = self.GEOSCrosses self.methods['within'] = self.GEOSWithin self.methods['contains'] = self.GEOSContains self.methods['overlaps'] = self.GEOSOverlaps self.methods['equals'] = self.GEOSEquals self.methods['equals_exact'] = self.GEOSEqualsExact self.methods['relate'] = self.GEOSRelate self.methods['difference'] = self.GEOSDifference self.methods['symmetric_difference'] = self.GEOSSymDifference self.methods['union'] = self.GEOSUnion self.methods['intersection'] = self.GEOSIntersection self.methods['simplify'] = self.GEOSSimplify self.methods['topology_preserve_simplify'] = \ self.GEOSTopologyPreserveSimplify class LGEOS310(LGEOSBase): """Proxy for GEOS 3.1.0-CAPI-1.5.0 """ geos_version = (3, 1, 0) geos_capi_version = (1, 5, 0) def __init__(self, dll): super(LGEOS310, self).__init__(dll) self.geos_handle = self._lgeos.initGEOS_r(notice_h, error_h) keys = list(self._lgeos.__dict__.keys()) for key in [x for x in keys if not x.endswith('_r')]: if key + '_r' in keys: reentr_func = getattr(self._lgeos, key + '_r') attr = ftools.partial(reentr_func, self.geos_handle) attr.__name__ = reentr_func.__name__ setattr(self, key, attr) else: setattr(self, key, getattr(self._lgeos, key)) if not hasattr(self, 'GEOSFree'): # GEOS < 3.1.1 self.GEOSFree = self._lgeos.free # Deprecated self.GEOSGeomToWKB_buf.func.errcheck = errcheck_wkb self.GEOSGeomToWKT.func.errcheck = errcheck_just_free self.GEOSRelate.func.errcheck = errcheck_just_free for pred in ( self.GEOSDisjoint, self.GEOSTouches, self.GEOSIntersects, self.GEOSCrosses, self.GEOSWithin, self.GEOSContains, self.GEOSOverlaps, self.GEOSEquals, self.GEOSEqualsExact, self.GEOSisEmpty, self.GEOSisValid, self.GEOSisSimple, self.GEOSisRing, self.GEOSHasZ): pred.func.errcheck = errcheck_predicate self.GEOSisValidReason.func.errcheck = errcheck_just_free self.methods['area'] = self.GEOSArea self.methods['boundary'] = self.GEOSBoundary self.methods['buffer'] = self.GEOSBuffer self.methods['centroid'] = self.GEOSGetCentroid self.methods['representative_point'] = self.GEOSPointOnSurface self.methods['convex_hull'] = self.GEOSConvexHull self.methods['distance'] = self.GEOSDistance self.methods['envelope'] = self.GEOSEnvelope self.methods['length'] = self.GEOSLength self.methods['has_z'] = self.GEOSHasZ self.methods['is_empty'] = self.GEOSisEmpty self.methods['is_ring'] = self.GEOSisRing self.methods['is_simple'] = self.GEOSisSimple self.methods['is_valid'] = self.GEOSisValid self.methods['disjoint'] = self.GEOSDisjoint self.methods['touches'] = self.GEOSTouches self.methods['intersects'] = self.GEOSIntersects self.methods['crosses'] = self.GEOSCrosses self.methods['within'] = self.GEOSWithin self.methods['contains'] = self.GEOSContains self.methods['overlaps'] = self.GEOSOverlaps self.methods['equals'] = self.GEOSEquals self.methods['equals_exact'] = self.GEOSEqualsExact self.methods['relate'] = self.GEOSRelate self.methods['difference'] = self.GEOSDifference self.methods['symmetric_difference'] = self.GEOSSymDifference self.methods['union'] = self.GEOSUnion self.methods['intersection'] = self.GEOSIntersection self.methods['prepared_intersects'] = self.GEOSPreparedIntersects self.methods['prepared_contains'] = self.GEOSPreparedContains self.methods['prepared_contains_properly'] = \ self.GEOSPreparedContainsProperly self.methods['prepared_covers'] = self.GEOSPreparedCovers self.methods['simplify'] = self.GEOSSimplify self.methods['topology_preserve_simplify'] = \ self.GEOSTopologyPreserveSimplify self.methods['cascaded_union'] = self.GEOSUnionCascaded class LGEOS311(LGEOS310): """Proxy for GEOS 3.1.1-CAPI-1.6.0 """ geos_version = (3, 1, 1) geos_capi_version = (1, 6, 0) def __init__(self, dll): super(LGEOS311, self).__init__(dll) class LGEOS320(LGEOS311): """Proxy for GEOS 3.2.0-CAPI-1.6.0 """ geos_version = (3, 2, 0) geos_capi_version = (1, 6, 0) def __init__(self, dll): super(LGEOS320, self).__init__(dll) self.methods['parallel_offset'] = self.GEOSSingleSidedBuffer self.methods['project'] = self.GEOSProject self.methods['project_normalized'] = self.GEOSProjectNormalized self.methods['interpolate'] = self.GEOSInterpolate self.methods['interpolate_normalized'] = \ self.GEOSInterpolateNormalized self.methods['buffer_with_style'] = self.GEOSBufferWithStyle class LGEOS330(LGEOS320): """Proxy for GEOS 3.3.0-CAPI-1.7.0 """ geos_version = (3, 3, 0) geos_capi_version = (1, 7, 0) def __init__(self, dll): super(LGEOS330, self).__init__(dll) # GEOS 3.3.8 from homebrew has, but doesn't advertise # GEOSPolygonize_full. We patch it in explicitly here. key = 'GEOSPolygonize_full' func = getattr(self._lgeos, key + '_r') attr = ftools.partial(func, self.geos_handle) attr.__name__ = func.__name__ setattr(self, key, attr) self.methods['unary_union'] = self.GEOSUnaryUnion self.methods['cascaded_union'] = self.methods['unary_union'] if geos_version >= (3, 3, 0): L = LGEOS330 elif geos_version >= (3, 2, 0): L = LGEOS320 elif geos_version >= (3, 1, 1): L = LGEOS311 elif geos_version >= (3, 1, 0): L = LGEOS310 else: L = LGEOS300 lgeos = L(_lgeos) @atexit.register def cleanup(): lgeos.__del__() Shapely-1.3.0/shapely/impl.py000066400000000000000000000106171226057120100161010ustar00rootroot00000000000000"""Implementation of the intermediary layer between Shapely and GEOS This is layer number 2 from the list below. 1) geometric objects: the Python OO API. 2) implementation map: an abstraction that permits different backends. 3) backend: callable objects that take Shapely geometric objects as arguments and, with GEOS as a backend, translate them to C data structures. 4) GEOS library: algorithms implemented in C++. Shapely 1.2 includes a GEOS backend and it is the default. """ from .ftools import wraps from shapely.algorithms import cga from shapely.coords import BoundsOp from shapely.geos import lgeos from shapely.linref import ProjectOp, InterpolateOp from shapely.predicates import BinaryPredicate, UnaryPredicate from shapely.topology import BinaryRealProperty, BinaryTopologicalOp from shapely.topology import UnaryRealProperty, UnaryTopologicalOp def delegated(func): """A delegated method raises AttributeError in the absence of backend support.""" @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except KeyError: raise AttributeError("Method %r is not supported by %r" % (func.__name__, args[0].impl)) return wrapper # Map geometry methods to their GEOS delegates class BaseImpl(object): def __init__(self, values): self.map = dict(values) def update(self, values): self.map.update(values) def __getitem__(self, key): return self.map[key] def __contains__(self, key): return key in self.map class GEOSImpl(BaseImpl): def __repr__(self): return '' % ( lgeos.geos_capi_version,) IMPL300 = { 'area': (UnaryRealProperty, 'area'), 'distance': (BinaryRealProperty, 'distance'), 'length': (UnaryRealProperty, 'length'), # 'boundary': (UnaryTopologicalOp, 'boundary'), 'bounds': (BoundsOp, None), 'centroid': (UnaryTopologicalOp, 'centroid'), 'representative_point': (UnaryTopologicalOp, 'representative_point'), 'envelope': (UnaryTopologicalOp, 'envelope'), 'convex_hull': (UnaryTopologicalOp, 'convex_hull'), 'buffer': (UnaryTopologicalOp, 'buffer'), # 'difference': (BinaryTopologicalOp, 'difference'), 'intersection': (BinaryTopologicalOp, 'intersection'), 'symmetric_difference': (BinaryTopologicalOp, 'symmetric_difference'), 'union': (BinaryTopologicalOp, 'union'), # 'has_z': (UnaryPredicate, 'has_z'), 'is_empty': (UnaryPredicate, 'is_empty'), 'is_ring': (UnaryPredicate, 'is_ring'), 'is_simple': (UnaryPredicate, 'is_simple'), 'is_valid': (UnaryPredicate, 'is_valid'), # 'relate': (BinaryPredicate, 'relate'), 'contains': (BinaryPredicate, 'contains'), 'crosses': (BinaryPredicate, 'crosses'), 'disjoint': (BinaryPredicate, 'disjoint'), 'equals': (BinaryPredicate, 'equals'), 'intersects': (BinaryPredicate, 'intersects'), 'overlaps': (BinaryPredicate, 'overlaps'), 'touches': (BinaryPredicate, 'touches'), 'within': (BinaryPredicate, 'within'), 'equals_exact': (BinaryPredicate, 'equals_exact'), # First pure Python implementation 'is_ccw': (cga.is_ccw_impl, 'is_ccw'), } IMPL310 = { 'simplify': (UnaryTopologicalOp, 'simplify'), 'topology_preserve_simplify': (UnaryTopologicalOp, 'topology_preserve_simplify'), 'prepared_intersects': (BinaryPredicate, 'prepared_intersects'), 'prepared_contains': (BinaryPredicate, 'prepared_contains'), 'prepared_contains_properly': (BinaryPredicate, 'prepared_contains_properly'), 'prepared_covers': (BinaryPredicate, 'prepared_covers'), } IMPL311 = { } IMPL320 = { 'parallel_offset': (UnaryTopologicalOp, 'parallel_offset'), 'project_normalized': (ProjectOp, 'project_normalized'), 'project': (ProjectOp, 'project'), 'interpolate_normalized': (InterpolateOp, 'interpolate_normalized'), 'interpolate': (InterpolateOp, 'interpolate'), 'buffer_with_style': (UnaryTopologicalOp, 'buffer_with_style'), } def impl_items(defs): return [(k, v[0](v[1])) for k, v in list(defs.items())] imp = GEOSImpl(dict(impl_items(IMPL300))) if lgeos.geos_version >= (3, 1, 0): imp.update(impl_items(IMPL310)) if lgeos.geos_version >= (3, 1, 1): imp.update(impl_items(IMPL311)) if lgeos.geos_version >= (3, 2, 0): imp.update(impl_items(IMPL320)) DefaultImplementation = imp Shapely-1.3.0/shapely/iterops.py000066400000000000000000000031231226057120100166170ustar00rootroot00000000000000""" Iterative forms of operations """ from warnings import warn from ctypes import c_char_p, c_size_t from shapely.geos import lgeos, PredicateError def geos_from_geometry(geom): warn("`geos_from_geometry` is deprecated. Use geometry's `wkb` property " "instead.", DeprecationWarning) data = geom.to_wkb() return lgeos.GEOSGeomFromWKB_buf( c_char_p(data), c_size_t(len(data)) ) class IterOp(object): """A generating non-data descriptor. """ def __init__(self, fn): self.fn = fn def __call__(self, context, iterator, value=True): if context._geom is None: raise ValueError("Null geometry supports no operations") for item in iterator: try: this_geom, ob = item except TypeError: this_geom = item ob = this_geom if not this_geom._geom: raise ValueError("Null geometry supports no operations") retval = self.fn(context._geom, this_geom._geom) if retval == 2: raise PredicateError( "Failed to evaluate %s" % repr(self.fn)) elif bool(retval) == value: yield ob # utilities disjoint = IterOp(lgeos.GEOSDisjoint) touches = IterOp(lgeos.GEOSTouches) intersects = IterOp(lgeos.GEOSIntersects) crosses = IterOp(lgeos.GEOSCrosses) within = IterOp(lgeos.GEOSWithin) contains = IterOp(lgeos.GEOSContains) overlaps = IterOp(lgeos.GEOSOverlaps) equals = IterOp(lgeos.GEOSEquals) Shapely-1.3.0/shapely/linref.py000066400000000000000000000013061226057120100164120ustar00rootroot00000000000000"""Linear referencing """ from shapely.topology import Delegating class LinearRefBase(Delegating): def _validate_line(self, ob): super(LinearRefBase, self)._validate(ob) try: assert ob.geom_type in ['LineString', 'MultiLineString'] except AssertionError: raise TypeError("Only linear types support this operation") class ProjectOp(LinearRefBase): def __call__(self, this, other): self._validate_line(this) self._validate(other) return self.fn(this._geom, other._geom) class InterpolateOp(LinearRefBase): def __call__(self, this, distance): self._validate_line(this) return self.fn(this._geom, distance) Shapely-1.3.0/shapely/ops.py000066400000000000000000000170231226057120100157370ustar00rootroot00000000000000"""Support for various GEOS geometry operations """ import sys if sys.version_info[0] < 3: from itertools import izip else: izip = zip from ctypes import byref, c_void_p from shapely.geos import lgeos from shapely.geometry.base import geom_factory, BaseGeometry from shapely.geometry import asShape, asLineString, asMultiLineString __all__ = ['cascaded_union', 'linemerge', 'operator', 'polygonize', 'polygonize_full', 'transform', 'unary_union'] class CollectionOperator(object): def shapeup(self, ob): if isinstance(ob, BaseGeometry): return ob else: try: return asShape(ob) except ValueError: return asLineString(ob) def polygonize(self, lines): """Creates polygons from a source of lines The source may be a MultiLineString, a sequence of LineString objects, or a sequence of objects than can be adapted to LineStrings. """ source = getattr(lines, 'geoms', None) or lines obs = [self.shapeup(l) for l in source] geom_array_type = c_void_p * len(obs) geom_array = geom_array_type() for i, line in enumerate(obs): geom_array[i] = line._geom product = lgeos.GEOSPolygonize(byref(geom_array), len(obs)) collection = geom_factory(product) for g in collection.geoms: clone = lgeos.GEOSGeom_clone(g._geom) g = geom_factory(clone) g._owned = False yield g def polygonize_full(self, lines): """Creates polygons from a source of lines, returning the polygons and leftover geometries. The source may be a MultiLineString, a sequence of LineString objects, or a sequence of objects than can be adapted to LineStrings. Returns a tuple of objects: (polygons, dangles, cut edges, invalid ring lines). Each are a geometry collection. Dangles are edges which have one or both ends which are not incident on another edge endpoint. Cut edges are connected at both ends but do not form part of polygon. Invalid ring lines form rings which are invalid (bowties, etc). """ source = getattr(lines, 'geoms', None) or lines obs = [self.shapeup(l) for l in source] L = len(obs) subs = (c_void_p * L)() for i, g in enumerate(obs): subs[i] = g._geom collection = lgeos.GEOSGeom_createCollection(5, subs, L) dangles = c_void_p() cuts = c_void_p() invalids = c_void_p() product = lgeos.GEOSPolygonize_full( collection, byref(dangles), byref(cuts), byref(invalids)) return ( geom_factory(product), geom_factory(dangles), geom_factory(cuts), geom_factory(invalids) ) def linemerge(self, lines): """Merges all connected lines from a source The source may be a MultiLineString, a sequence of LineString objects, or a sequence of objects than can be adapted to LineStrings. Returns a LineString or MultiLineString when lines are not contiguous. """ source = None if hasattr(lines, 'type') and lines.type == 'MultiLineString': source = lines elif hasattr(lines, '__iter__'): try: source = asMultiLineString([ls.coords for ls in lines]) except AttributeError: source = asMultiLineString(lines) if source is None: raise ValueError("Cannot linemerge %s" % lines) result = lgeos.GEOSLineMerge(source._geom) return geom_factory(result) def cascaded_union(self, geoms): """Returns the union of a sequence of geometries This is the most efficient method of dissolving many polygons. """ L = len(geoms) subs = (c_void_p * L)() for i, g in enumerate(geoms): subs[i] = g._geom collection = lgeos.GEOSGeom_createCollection(6, subs, L) return geom_factory(lgeos.methods['cascaded_union'](collection)) def unary_union(self, geoms): """Returns the union of a sequence of geometries This method replaces :meth:`cascaded_union` as the prefered method for dissolving many polygons. """ L = len(geoms) subs = (c_void_p * L)() for i, g in enumerate(geoms): subs[i] = g._geom collection = lgeos.GEOSGeom_createCollection(6, subs, L) return geom_factory(lgeos.methods['unary_union'](collection)) operator = CollectionOperator() polygonize = operator.polygonize polygonize_full = operator.polygonize_full linemerge = operator.linemerge cascaded_union = operator.cascaded_union unary_union = operator.unary_union class ValidateOp(object): def __call__(self, this): return lgeos.GEOSisValidReason(this._geom) validate = ValidateOp() def transform(func, geom): """Applies `func` to all coordinates of `geom` and returns a new geometry of the same type from the transformed coordinates. `func` maps x, y, and optionally z to output xp, yp, zp. The input parameters may iterable types like lists or arrays or single values. The output shall be of the same type. Scalars in, scalars out. Lists in, lists out. For example, here is an identity function applicable to both types of input. def id_func(x, y, z=None): return tuple(filter(None, [x, y, z])) g2 = transform(id_func, g1) A partially applied transform function from pyproj satisfies the requirements for `func`. from functools import partial import pyproj project = partial( pyproj.transform, pyproj.Proj(init='espg:4326'), pyproj.Proj(init='epsg:26913')) g2 = transform(project, g1) Lambda expressions such as the one in g2 = transform(lambda x, y, z=None: (x+1.0, y+1.0), g1) also satisfy the requirements for `func`. """ if geom.is_empty: return geom if geom.type in ('Point', 'LineString', 'Polygon'): # First we try to apply func to x, y, z sequences. When func is # optimized for sequences, this is the fastest, though zipping # the results up to go back into the geometry constructors adds # extra cost. try: if geom.type in ('Point', 'LineString'): return type(geom)(zip(*func(*izip(*geom.coords)))) elif geom.type == 'Polygon': shell = type(geom.exterior)( zip(*func(*izip(*geom.exterior.coords)))) holes = list(type(ring)(zip(*func(*izip(*ring.coords)))) for ring in geom.interiors) return type(geom)(shell, holes) # A func that assumes x, y, z are single values will likely raise a # TypeError, in which case we'll try again. except TypeError: if geom.type in ('Point', 'LineString'): return type(geom)([func(*c) for c in geom.coords]) elif geom.type == 'Polygon': shell = type(geom.exterior)( [func(*c) for c in geom.exterior.coords]) holes = list(type(ring)([func(*c) for c in ring.coords]) for ring in geom.interiors) return type(geom)(shell, holes) elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection': return type(geom)([transform(func, part) for part in geom.geoms]) else: raise ValueError('Type %r not recognized' % geom.type) Shapely-1.3.0/shapely/predicates.py000066400000000000000000000011561226057120100172610ustar00rootroot00000000000000""" Support for GEOS spatial predicates """ from shapely.topology import Delegating class BinaryPredicate(Delegating): def __call__(self, this, other, *args): self._validate(this) self._validate(other, stop_prepared=True) return self.fn(this._geom, other._geom, *args) class RelateOp(Delegating): def __call__(self, this, other): self._validate(this) self._validate(other, stop_prepared=True) return self.fn(this._geom, other._geom) class UnaryPredicate(Delegating): def __call__(self, this): self._validate(this) return self.fn(this._geom) Shapely-1.3.0/shapely/prepared.py000066400000000000000000000031101226057120100167300ustar00rootroot00000000000000""" Support for GEOS prepared geometry operations. """ from shapely.geos import lgeos from shapely.impl import DefaultImplementation, delegated class PreparedGeometry(object): """ A geometry prepared for efficient comparison to a set of other geometries. Example: >>> from shapely.geometry import Point, Polygon >>> triangle = Polygon(((0.0, 0.0), (1.0, 1.0), (1.0, -1.0))) >>> p = prep(triangle) >>> p.intersects(Point(0.5, 0.5)) True """ impl = DefaultImplementation def __init__(self, context): self.context = context self.__geom__ = lgeos.GEOSPrepare(self.context._geom) def __del__(self): if self.__geom__ is not None: try: lgeos.GEOSPreparedGeom_destroy(self.__geom__) except AttributeError: pass # lgeos might be empty on shutdown self.__geom__ = None self.context = None @property def _geom(self): return self.__geom__ @delegated def intersects(self, other): return bool(self.impl['prepared_intersects'](self, other)) @delegated def contains(self, other): return bool(self.impl['prepared_contains'](self, other)) @delegated def contains_properly(self, other): return bool(self.impl['prepared_contains_properly'](self, other)) @delegated def covers(self, other): return bool(self.impl['prepared_covers'](self, other)) def prep(ob): """Creates and returns a prepared geometric object.""" return PreparedGeometry(ob) Shapely-1.3.0/shapely/speedups/000077500000000000000000000000001226057120100164115ustar00rootroot00000000000000Shapely-1.3.0/shapely/speedups/__init__.py000066400000000000000000000024231226057120100205230ustar00rootroot00000000000000import warnings from shapely.geometry import linestring, polygon from shapely import coords try: from shapely.speedups import _speedups available = True import_error_msg = None except ImportError: import sys available = False # TODO: This does not appear to do anything useful import_error_msg = sys.exc_info()[1] __all__ = ['available', 'enable', 'disable'] _orig = {} def enable(): if not available: warnings.warn("shapely.speedups not available", RuntimeWarning) return if _orig: return _orig['CoordinateSequence.ctypes'] = coords.CoordinateSequence.ctypes coords.CoordinateSequence.ctypes = property(_speedups.coordseq_ctypes) _orig['geos_linestring_from_py'] = linestring.geos_linestring_from_py linestring.geos_linestring_from_py = _speedups.geos_linestring_from_py _orig['geos_linearring_from_py'] = polygon.geos_linearring_from_py polygon.geos_linearring_from_py = _speedups.geos_linearring_from_py def disable(): if not _orig: return coords.CoordinateSequence.ctypes = _orig['CoordinateSequence.ctypes'] linestring.geos_linestring_from_py = _orig['geos_linestring_from_py'] polygon.geos_linearring_from_py = _orig['geos_linearring_from_py'] _orig.clear() Shapely-1.3.0/shapely/speedups/_speedups.pyx000066400000000000000000000242241226057120100211460ustar00rootroot00000000000000# geos_linestring_from_py was transcribed from shapely.geometry.linestring # geos_linearring_from_py was transcribed from shapely.geometry.polygon # coordseq_ctypes was transcribed from shapely.coords.CoordinateSequence.ctypes # # Copyright (c) 2007, Sean C. Gillies # Transcription to cython: Copyright (c) 2011, Oliver Tonnhofer import ctypes from shapely.geos import lgeos cdef extern from "geos_c.h": ctypedef struct GEOSCoordSequence ctypedef struct GEOSGeometry cdef struct GEOSContextHandle_HS GEOSCoordSequence *GEOSCoordSeq_create_r(GEOSContextHandle_HS *,double, double) GEOSCoordSequence *GEOSGeom_getCoordSeq_r(GEOSContextHandle_HS *, GEOSGeometry *) int GEOSCoordSeq_getSize_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int *) int GEOSCoordSeq_setX_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double) int GEOSCoordSeq_setY_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double) int GEOSCoordSeq_setZ_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double) int GEOSCoordSeq_getX_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double *) int GEOSCoordSeq_getY_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double *) int GEOSCoordSeq_getZ_r(GEOSContextHandle_HS *, GEOSCoordSequence *, int, double *) GEOSGeometry *GEOSGeom_createLineString_r(GEOSContextHandle_HS *, GEOSCoordSequence *) GEOSGeometry *GEOSGeom_createLinearRing_r(GEOSContextHandle_HS *, GEOSCoordSequence *) void GEOSGeom_destroy_r(GEOSContextHandle_HS *, GEOSGeometry *) cdef inline GEOSGeometry *cast_geom(unsigned long geom_addr): return geom_addr cdef inline GEOSContextHandle_HS *cast_handle(unsigned long handle_addr): return handle_addr cdef inline GEOSCoordSequence *cast_seq(unsigned long handle_addr): return handle_addr def destroy(geom): GEOSGeom_destroy_r(cast_handle(lgeos.geos_handle), cast_geom(geom)) def geos_linestring_from_py(ob, update_geom=None, update_ndim=0): cdef double *cp cdef GEOSContextHandle_HS *handle = cast_handle(lgeos.geos_handle) cdef GEOSCoordSequence *cs cdef double dx, dy, dz cdef int i, n, m try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 2 m = array['shape'][0] if m < 2: raise ValueError( "LineStrings must have at least 2 coordinate tuples") try: n = array['shape'][1] except IndexError: raise ValueError( "Input %s is the wrong shape for a LineString" % str(ob)) assert n == 2 or n == 3 # Make pointer to the coordinate array if isinstance(array['data'], ctypes.Array): cp = ctypes.addressof(array['data']) else: cp = array['data'][0] # Create a coordinate sequence if update_geom is not None: cs = GEOSGeom_getCoordSeq_r(handle, cast_geom(update_geom)) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = GEOSCoordSeq_create_r(handle, m, n) # add to coordinate sequence for i in xrange(m): dx = cp[n*i] dy = cp[n*i+1] dz = 0 if n == 3: dz = cp[n*i+2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, i, dx) GEOSCoordSeq_setY_r(handle, cs, i, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, i, dz) except AttributeError: # Fall back on list m = len(ob) if m < 2: raise ValueError( "LineStrings must have at least 2 coordinate tuples") try: n = len(ob[0]) except TypeError: raise ValueError( "Input %s is the wrong shape for a LineString" % str(ob)) assert n == 2 or n == 3 # Create a coordinate sequence if update_geom is not None: cs = GEOSGeom_getCoordSeq_r(handle, cast_geom(update_geom)) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = GEOSCoordSeq_create_r(handle, m, n) # add to coordinate sequence for i in xrange(m): coords = ob[i] dx = coords[0] dy = coords[1] dz = 0 if n == 3: if len(coords) != 3: raise ValueError("Inconsistent coordinate dimensionality") dz = coords[2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, i, dx) GEOSCoordSeq_setY_r(handle, cs, i, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, i, dz) if update_geom is not None: return None else: return GEOSGeom_createLineString_r(handle, cs), n def geos_linearring_from_py(ob, update_geom=None, update_ndim=0): cdef double *cp cdef GEOSContextHandle_HS *handle = cast_handle(lgeos.geos_handle) cdef GEOSCoordSequence *cs cdef double dx, dy, dz cdef int i, n, m, M try: # From array protocol array = ob.__array_interface__ assert len(array['shape']) == 2 m = array['shape'][0] n = array['shape'][1] if m < 3: raise ValueError( "A LinearRing must have at least 3 coordinate tuples") assert n == 2 or n == 3 # Make pointer to the coordinate array if isinstance(array['data'], ctypes.Array): cp = ctypes.addressof(array['data']) else: cp = array['data'][0] # Add closing coordinates to sequence? if cp[0] != cp[m*n-n] or cp[1] != cp[m*n-n+1]: M = m + 1 else: M = m # Create a coordinate sequence if update_geom is not None: cs = GEOSGeom_getCoordSeq_r(handle, cast_geom(update_geom)) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = GEOSCoordSeq_create_r(handle, M, n) # add to coordinate sequence for i in xrange(m): dx = cp[n*i] dy = cp[n*i+1] dz = 0 if n == 3: dz = cp[n*i+2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, i, dx) GEOSCoordSeq_setY_r(handle, cs, i, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, i, dz) # Add closing coordinates to sequence? if M > m: dx = cp[0] dy = cp[1] dz = 0 if n == 3: dz = cp[2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, M-1, dx) GEOSCoordSeq_setY_r(handle, cs, M-1, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, M-1, dz) except AttributeError: # Fall back on list m = len(ob) n = len(ob[0]) if m < 3: raise ValueError( "A LinearRing must have at least 3 coordinate tuples") assert (n == 2 or n == 3) # Add closing coordinates if not provided if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]: M = m + 1 else: M = m # Create a coordinate sequence if update_geom is not None: cs = GEOSGeom_getCoordSeq_r(handle, cast_geom(update_geom)) if n != update_ndim: raise ValueError( "Wrong coordinate dimensions; this geometry has dimensions: %d" \ % update_ndim) else: cs = GEOSCoordSeq_create_r(handle, M, n) # add to coordinate sequence for i in xrange(m): coords = ob[i] dx = coords[0] dy = coords[1] dz = 0 if n == 3: dz = coords[2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, i, dx) GEOSCoordSeq_setY_r(handle, cs, i, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, i, dz) # Add closing coordinates to sequence? if M > m: coords = ob[0] dx = coords[0] dy = coords[1] dz = 0 if n == 3: dz = coords[2] # Because of a bug in the GEOS C API, # always set X before Y GEOSCoordSeq_setX_r(handle, cs, M-1, dx) GEOSCoordSeq_setY_r(handle, cs, M-1, dy) if n == 3: GEOSCoordSeq_setZ_r(handle, cs, M-1, dz) if update_geom is not None: return None else: return GEOSGeom_createLinearRing_r(handle, cs), n def coordseq_ctypes(self): cdef int i, n, m cdef double temp = 0 cdef GEOSContextHandle_HS *handle = cast_handle(lgeos.geos_handle) cdef GEOSCoordSequence *cs cdef double *data_p self._update() n = self._ndim m = self.__len__() array_type = ctypes.c_double * (m * n) data = array_type() cs = cast_seq(self._cseq) data_p = ctypes.addressof(data) for i in xrange(m): GEOSCoordSeq_getX_r(handle, cs, i, &temp) data_p[n*i] = temp GEOSCoordSeq_getY_r(handle, cs, i, &temp) data_p[n*i+1] = temp if n == 3: # TODO: use hasz GEOSCoordSeq_getZ_r(handle, cs, i, &temp) data_p[n*i+2] = temp return data Shapely-1.3.0/shapely/tests/000077500000000000000000000000001226057120100157235ustar00rootroot00000000000000Shapely-1.3.0/shapely/tests/__init__.py000077500000000000000000000064331226057120100200450ustar00rootroot00000000000000import sys from shapely.geos import geos_version_string, lgeos, WKTWriter from shapely import speedups try: import numpy numpy_version = numpy.version.version except ImportError: numpy = False numpy_version = 'not available' # Show some diagnostic information; handy for Travis CI print('Python version: ' + sys.version.replace('\n', ' ')) print('GEOS version: ' + geos_version_string) print('Numpy version: ' + numpy_version) print('Cython speedups: ' + str(speedups.available)) if lgeos.geos_version >= (3, 3, 0): # Remove any WKT writer defaults to pass tests for all versions of GEOS WKTWriter.defaults = {} if sys.version_info[0:2] <= (2, 6): import unittest2 as unittest else: import unittest from . import test_doctests, test_prepared, test_equality, test_geomseq, \ test_point, test_linestring, test_polygon, test_multipoint, \ test_multilinestring, test_multipolygon, test_geointerface, test_locale, \ test_xy, test_persist, test_collection, test_emptiness, test_singularity, \ test_validation, test_mapping, test_delegated, test_dlls, \ test_linear_referencing, test_products_z, test_box, test_speedups, \ test_cga, test_getitem, test_ndarrays, test_pickle, \ test_affinity, test_transform, test_invalid_geometries, test_styles, \ test_operations, test_operators, test_iterops, test_predicates, \ test_linemerge, test_polygonize, test_union def test_suite(): suite = unittest.TestSuite() suite.addTest(test_point.test_suite()) suite.addTest(test_linestring.test_suite()) suite.addTest(test_polygon.test_suite()) suite.addTest(test_multipoint.test_suite()) suite.addTest(test_multilinestring.test_suite()) suite.addTest(test_multipolygon.test_suite()) suite.addTest(test_doctests.test_suite()) suite.addTest(test_prepared.test_suite()) suite.addTest(test_emptiness.test_suite()) suite.addTest(test_equality.test_suite()) suite.addTest(test_geomseq.test_suite()) suite.addTest(test_geointerface.test_suite()) suite.addTest(test_locale.test_suite()) suite.addTest(test_xy.test_suite()) suite.addTest(test_persist.test_suite()) suite.addTest(test_collection.test_suite()) suite.addTest(test_singularity.test_suite()) suite.addTest(test_validation.test_suite()) suite.addTest(test_mapping.test_suite()) suite.addTest(test_delegated.test_suite()) suite.addTest(test_dlls.test_suite()) suite.addTest(test_linear_referencing.test_suite()) suite.addTest(test_products_z.test_suite()) suite.addTest(test_box.test_suite()) suite.addTest(test_speedups.test_suite()) suite.addTest(test_cga.test_suite()) suite.addTest(test_getitem.test_suite()) suite.addTest(test_ndarrays.test_suite()) suite.addTest(test_pickle.test_suite()) suite.addTest(test_affinity.test_suite()) suite.addTest(test_transform.test_suite()) suite.addTest(test_invalid_geometries.test_suite()) suite.addTest(test_styles.test_suite()) suite.addTest(test_operations.test_suite()) suite.addTest(test_operators.test_suite()) suite.addTest(test_iterops.test_suite()) suite.addTest(test_predicates.test_suite()) suite.addTest(test_linemerge.test_suite()) suite.addTest(test_polygonize.test_suite()) suite.addTest(test_union.test_suite()) return suite Shapely-1.3.0/shapely/tests/binascii_hex.txt000066400000000000000000000026161226057120100211160ustar00rootroot00000000000000Round-tripping geometries through hex-encoded binary ==================================================== Hex-encoded binary is the PostGIS geometry representation, and so this is a test of the ability to store Shapely geometries in PostGIS. Point ----- >>> from shapely.geometry import Point >>> point = Point(0.0, 0.0) >>> from binascii import a2b_hex, b2a_hex >>> x = b2a_hex(point.wkb) >>> from shapely import wkb >>> shape = wkb.loads(a2b_hex(x)) >>> shape # doctest: +ELLIPSIS LineString ---------- >>> from shapely.geometry import LineString >>> line = LineString(((0.0, 0.0), (1.0, 1.0))) >>> x = b2a_hex(line.wkb) >>> shape = wkb.loads(a2b_hex(x)) >>> shape # doctest: +ELLIPSIS Polygon ---------- >>> from shapely.geometry import Polygon >>> polygon = Polygon(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))) >>> x = b2a_hex(polygon.wkb) >>> shape = wkb.loads(a2b_hex(x)) >>> shape # doctest: +ELLIPSIS Polygon with hole ----------------- >>> polygon = Polygon(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)), [((0.1,0.1), (0.1,0.2), (0.2,0.2), (0.2,0.1))]) >>> x = b2a_hex(polygon.wkb) >>> shape = wkb.loads(a2b_hex(x)) >>> shape # doctest: +ELLIPSIS Shapely-1.3.0/shapely/tests/rungrind.dist000066400000000000000000000002251226057120100204370ustar00rootroot00000000000000#!/bin/sh #export PYTHONPATH=YOUR_CUSTOM_PATH valgrind --tool=memcheck --leak-check=yes --suppressions=valgrind-python.supp python test_doctests.py Shapely-1.3.0/shapely/tests/test_affinity.py000077500000000000000000000257631226057120100211650ustar00rootroot00000000000000from . import unittest from math import pi from shapely import affinity from shapely.wkt import loads as load_wkt from shapely.geometry import Point class AffineTestCase(unittest.TestCase): def test_affine_params(self): g = load_wkt('LINESTRING(2.4 4.1, 2.4 3, 3 3)') self.assertRaises( TypeError, affinity.affine_transform, g, None) self.assertRaises( TypeError, affinity.affine_transform, g, '123456') self.assertRaises(ValueError, affinity.affine_transform, g, [1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertRaises(AttributeError, affinity.affine_transform, None, [1, 2, 3, 4, 5, 6]) def test_affine_geom_types(self): # identity matrices, which should result with no transformation matrix2d = (1, 0, 0, 1, 0, 0) matrix3d = (1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) # empty in, empty out empty2d = load_wkt('MULTIPOLYGON EMPTY') self.assertTrue(affinity.affine_transform(empty2d, matrix2d).is_empty) def test_geom(g2, g3=None): self.assertFalse(g2.has_z) a2 = affinity.affine_transform(g2, matrix2d) self.assertFalse(a2.has_z) self.assertTrue(g2.equals(a2)) if g3 is not None: self.assertTrue(g3.has_z) a3 = affinity.affine_transform(g3, matrix3d) self.assertTrue(a3.has_z) self.assertTrue(g3.equals(a3)) return pt2d = load_wkt('POINT(12.3 45.6)') pt3d = load_wkt('POINT(12.3 45.6 7.89)') test_geom(pt2d, pt3d) ls2d = load_wkt('LINESTRING(0.9 3.4, 0.7 2, 2.5 2.7)') ls3d = load_wkt('LINESTRING(0.9 3.4 3.3, 0.7 2 2.3, 2.5 2.7 5.5)') test_geom(ls2d, ls3d) test_geom(load_wkt('POLYGON((0.9 2.3, 0.5 1.1, 2.4 0.8, 0.9 2.3), ' '(1.1 1.7, 0.9 1.3, 1.4 1.2, 1.1 1.7), ' '(1.6 1.3, 1.7 1, 1.9 1.1, 1.6 1.3))')) test_geom(load_wkt( 'MULTIPOINT ((-300 300), (700 300), (-800 -1100), (200 -300))')) test_geom(load_wkt( 'MULTILINESTRING((0 0, -0.7 -0.7, 0.6 -1), ' '(-0.5 0.5, 0.7 0.6, 0 -0.6))')) test_geom(load_wkt( 'MULTIPOLYGON(((900 4300, -1100 -400, 900 -800, 900 4300)), ' '((1200 4300, 2300 4400, 1900 1000, 1200 4300)))')) # GeometryCollection fails, since it does not have a good constructor gc = load_wkt('GEOMETRYCOLLECTION(POINT(20 70),' ' POLYGON((60 70, 13 35, 60 -30, 60 70)),' ' LINESTRING(60 70, 50 100, 80 100))') self.assertRaises(TypeError, test_geom, gc) # TODO: fix this def test_affine_2d(self): g = load_wkt('LINESTRING(2.4 4.1, 2.4 3, 3 3)') # custom scale and translate expected2d = load_wkt('LINESTRING(-0.2 14.35, -0.2 11.6, 1 11.6)') matrix2d = (2, 0, 0, 2.5, -5, 4.1) a2 = affinity.affine_transform(g, matrix2d) self.assertTrue(a2.almost_equals(expected2d)) self.assertFalse(a2.has_z) # Make sure a 3D matrix does not make a 3D shape from a 2D input matrix3d = (2, 0, 0, 0, 2.5, 0, 0, 0, 10, -5, 4.1, 100) a3 = affinity.affine_transform(g, matrix3d) self.assertTrue(a3.almost_equals(expected2d)) self.assertFalse(a3.has_z) def test_affine_3d(self): g2 = load_wkt('LINESTRING(2.4 4.1, 2.4 3, 3 3)') g3 = load_wkt('LINESTRING(2.4 4.1 100.2, 2.4 3 132.8, 3 3 128.6)') # custom scale and translate matrix2d = (2, 0, 0, 2.5, -5, 4.1) matrix3d = (2, 0, 0, 0, 2.5, 0, 0, 0, 0.3048, -5, 4.1, 100) # Combinations of 2D and 3D geometries and matrices a22 = affinity.affine_transform(g2, matrix2d) a23 = affinity.affine_transform(g2, matrix3d) a32 = affinity.affine_transform(g3, matrix2d) a33 = affinity.affine_transform(g3, matrix3d) # Check dimensions self.assertFalse(a22.has_z) self.assertFalse(a23.has_z) self.assertTrue(a32.has_z) self.assertTrue(a33.has_z) # 2D equality checks expected2d = load_wkt('LINESTRING(-0.2 14.35, -0.2 11.6, 1 11.6)') expected3d = load_wkt('LINESTRING(-0.2 14.35 130.54096, ' '-0.2 11.6 140.47744, 1 11.6 139.19728)') expected32 = load_wkt('LINESTRING(-0.2 14.35 100.2, ' '-0.2 11.6 132.8, 1 11.6 128.6)') self.assertTrue(a22.almost_equals(expected2d)) self.assertTrue(a23.almost_equals(expected2d)) # Do explicit 3D check of coordinate values for a, e in zip(a32.coords, expected32.coords): for ap, ep in zip(a, e): self.assertAlmostEqual(ap, ep) for a, e in zip(a33.coords, expected3d.coords): for ap, ep in zip(a, e): self.assertAlmostEqual(ap, ep) class TransformOpsTestCase(unittest.TestCase): def test_rotate(self): ls = load_wkt('LINESTRING(240 400, 240 300, 300 300)') # counter-clockwise degrees rls = affinity.rotate(ls, 90) els = load_wkt('LINESTRING(220 320, 320 320, 320 380)') self.assertTrue(rls.equals(els)) # retest with named parameters for the same result rls = affinity.rotate(geom=ls, angle=90, origin='center') self.assertTrue(rls.equals(els)) # clockwise radians rls = affinity.rotate(ls, -pi/2, use_radians=True) els = load_wkt('LINESTRING(320 380, 220 380, 220 320)') self.assertTrue(rls.equals(els)) ## other `origin` parameters # around the centroid rls = affinity.rotate(ls, 90, origin='centroid') els = load_wkt('LINESTRING(182.5 320, 282.5 320, 282.5 380)') self.assertTrue(rls.equals(els)) # around the second coordinate tuple rls = affinity.rotate(ls, 90, origin=ls.coords[1]) els = load_wkt('LINESTRING(140 300, 240 300, 240 360)') self.assertTrue(rls.equals(els)) # around the absolute Point of origin rls = affinity.rotate(ls, 90, origin=Point(0, 0)) els = load_wkt('LINESTRING(-400 240, -300 240, -300 300)') self.assertTrue(rls.equals(els)) def test_scale(self): ls = load_wkt('LINESTRING(240 400 10, 240 300 30, 300 300 20)') # test defaults of 1.0 sls = affinity.scale(ls) self.assertTrue(sls.equals(ls)) # different scaling in different dimensions sls = affinity.scale(ls, 2, 3, 0.5) els = load_wkt('LINESTRING(210 500 5, 210 200 15, 330 200 10)') self.assertTrue(sls.equals(els)) # Do explicit 3D check of coordinate values for a, b in zip(sls.coords, els.coords): for ap, bp in zip(a, b): self.assertEqual(ap, bp) # retest with named parameters for the same result sls = affinity.scale(geom=ls, xfact=2, yfact=3, zfact=0.5, origin='center') self.assertTrue(sls.equals(els)) ## other `origin` parameters # around the centroid sls = affinity.scale(ls, 2, 3, 0.5, origin='centroid') els = load_wkt('LINESTRING(228.75 537.5, 228.75 237.5, 348.75 237.5)') self.assertTrue(sls.equals(els)) # around the second coordinate tuple sls = affinity.scale(ls, 2, 3, 0.5, origin=ls.coords[1]) els = load_wkt('LINESTRING(240 600, 240 300, 360 300)') self.assertTrue(sls.equals(els)) # around some other 3D Point of origin sls = affinity.scale(ls, 2, 3, 0.5, origin=Point(100, 200, 1000)) els = load_wkt('LINESTRING(380 800 505, 380 500 515, 500 500 510)') self.assertTrue(sls.equals(els)) # Do explicit 3D check of coordinate values for a, b in zip(sls.coords, els.coords): for ap, bp in zip(a, b): self.assertEqual(ap, bp) def test_skew(self): ls = load_wkt('LINESTRING(240 400 10, 240 300 30, 300 300 20)') # test default shear angles of 0.0 sls = affinity.skew(ls) self.assertTrue(sls.equals(ls)) # different shearing in x- and y-directions sls = affinity.skew(ls, 15, -30) els = load_wkt('LINESTRING (253.39745962155615 417.3205080756888, ' '226.60254037844385 317.3205080756888, ' '286.60254037844385 282.67949192431126)') self.assertTrue(sls.almost_equals(els)) # retest with radians for the same result sls = affinity.skew(ls, pi/12, -pi/6, use_radians=True) self.assertTrue(sls.almost_equals(els)) # retest with named parameters for the same result sls = affinity.skew(geom=ls, xs=15, ys=-30, origin='center', use_radians=False) self.assertTrue(sls.almost_equals(els)) ## other `origin` parameters # around the centroid sls = affinity.skew(ls, 15, -30, origin='centroid') els = load_wkt('LINESTRING(258.42150697963973 406.49519052838332, ' '231.6265877365273980 306.4951905283833185, ' '291.6265877365274264 271.8541743770057337)') self.assertTrue(sls.almost_equals(els)) # around the second coordinate tuple sls = affinity.skew(ls, 15, -30, origin=ls.coords[1]) els = load_wkt('LINESTRING(266.7949192431123038 400, 240 300, ' '300 265.3589838486224153)') self.assertTrue(sls.almost_equals(els)) # around the absolute Point of origin sls = affinity.skew(ls, 15, -30, origin=Point(0, 0)) els = load_wkt('LINESTRING(347.179676972449101 261.435935394489832, ' '320.3847577293367976 161.4359353944898317, ' '380.3847577293367976 126.7949192431122754)') self.assertTrue(sls.almost_equals(els)) def test_translate(self): ls = load_wkt('LINESTRING(240 400 10, 240 300 30, 300 300 20)') # test default offset of 0.0 tls = affinity.translate(ls) self.assertTrue(tls.equals(ls)) # test all offsets tls = affinity.translate(ls, 100, 400, -10) els = load_wkt('LINESTRING(340 800 0, 340 700 20, 400 700 10)') self.assertTrue(tls.equals(els)) # Do explicit 3D check of coordinate values for a, b in zip(tls.coords, els.coords): for ap, bp in zip(a, b): self.assertEqual(ap, bp) # retest with named parameters for the same result tls = affinity.translate(geom=ls, xoff=100, yoff=400, zoff=-10) self.assertTrue(tls.equals(els)) def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(AffineTestCase), loader.loadTestsFromTestCase(TransformOpsTestCase)]) Shapely-1.3.0/shapely/tests/test_box.py000066400000000000000000000013541226057120100201270ustar00rootroot00000000000000from . import unittest from shapely import geometry class BoxTestCase(unittest.TestCase): def test_ccw(self): b = geometry.box(0, 0, 1, 1, ccw=True) self.assertEqual(b.exterior.coords[0], (1.0, 0.0)) self.assertEqual(b.exterior.coords[1], (1.0, 1.0)) def test_ccw_default(self): b = geometry.box(0, 0, 1, 1) self.assertEqual(b.exterior.coords[0], (1.0, 0.0)) self.assertEqual(b.exterior.coords[1], (1.0, 1.0)) def test_cw(self): b = geometry.box(0, 0, 1, 1, ccw=False) self.assertEqual(b.exterior.coords[0], (0.0, 0.0)) self.assertEqual(b.exterior.coords[1], (0.0, 1.0)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(BoxTestCase) Shapely-1.3.0/shapely/tests/test_cga.py000066400000000000000000000023721226057120100200720ustar00rootroot00000000000000from . import unittest from shapely.geometry.polygon import LinearRing, orient, Polygon class RingOrientationTestCase(unittest.TestCase): def test_ccw(self): ring = LinearRing([(1, 0), (0, 1), (0, 0)]) self.assertTrue(ring.is_ccw) def test_cw(self): ring = LinearRing([(0, 0), (0, 1), (1, 0)]) self.assertFalse(ring.is_ccw) class PolygonOrienterTestCase(unittest.TestCase): def test_no_holes(self): ring = LinearRing([(0, 0), (0, 1), (1, 0)]) polygon = Polygon(ring) self.assertFalse(polygon.exterior.is_ccw) polygon = orient(polygon, 1) self.assertTrue(polygon.exterior.is_ccw) def test_holes(self): polygon = Polygon([(0, 0), (0, 1), (1, 0)], [[(0.5, 0.25), (0.25, 0.5), (0.25, 0.25)]]) self.assertFalse(polygon.exterior.is_ccw) self.assertTrue(polygon.interiors[0].is_ccw) polygon = orient(polygon, 1) self.assertTrue(polygon.exterior.is_ccw) self.assertFalse(polygon.interiors[0].is_ccw) def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(RingOrientationTestCase), loader.loadTestsFromTestCase(PolygonOrienterTestCase)]) Shapely-1.3.0/shapely/tests/test_collection.py000066400000000000000000000015751226057120100214770ustar00rootroot00000000000000from . import unittest from shapely.geometry import LineString from shapely.geometry.collection import GeometryCollection class CollectionTestCase(unittest.TestCase): def test_array_interface(self): m = GeometryCollection() self.assertEqual(len(m), 0) self.assertEqual(m.geoms, []) def test_child_with_deleted_parent(self): # test that we can remove a collection while having # childs around a = LineString([(0, 0), (1, 1), (1, 2), (2, 2)]) b = LineString([(0, 0), (1, 1), (2, 1), (2, 2)]) collection = a.intersection(b) child = collection.geoms[0] # delete parent of child del collection # access geometry, this should not seg fault as 1.2.15 did self.assertIsNotNone(child.wkt) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(CollectionTestCase) Shapely-1.3.0/shapely/tests/test_delegated.py000066400000000000000000000015651226057120100212610ustar00rootroot00000000000000from . import unittest from shapely.geometry import Point from shapely.impl import BaseImpl from shapely.geometry.base import delegated class Geometry(object): impl = BaseImpl({}) @property @delegated def foo(self): return self.impl['foo']() class WrapperTestCase(unittest.TestCase): """When the backend has no support for a method, we get an AttributeError """ def test_delegated(self): self.assertRaises(AttributeError, getattr, Geometry(), 'foo') def test_defaultimpl(self): project_impl = Point.impl.map.pop('project', None) try: self.assertRaises(AttributeError, Point(0, 0).project, 1.0) finally: if project_impl is not None: Point.impl.map['project'] = project_impl def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(WrapperTestCase) Shapely-1.3.0/shapely/tests/test_dlls.py000066400000000000000000000010241226057120100202670ustar00rootroot00000000000000from . import unittest from shapely.geos import load_dll class LoadingTestCase(unittest.TestCase): def test_load(self): self.assertRaises(OSError, load_dll, 'geosh_c') def test_fallbacks(self): load_dll('geos_c', fallbacks=[ '/opt/local/lib/libgeos_c.dylib', # MacPorts '/usr/local/lib/libgeos_c.dylib', # homebrew (Mac OS X) 'libgeos_c.so.1', 'libgeos_c.so']) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(LoadingTestCase) Shapely-1.3.0/shapely/tests/test_doctests.py000066400000000000000000000017311226057120100211660ustar00rootroot00000000000000import os import doctest from . import unittest from glob import glob optionflags = (doctest.REPORT_ONLY_FIRST_FAILURE | doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS) def list_doctests(): print(__file__) source_files = glob(os.path.join(os.path.dirname(__file__), '*.txt')) return [filename for filename in source_files] def open_file(filename, mode='r'): """Helper function to open files from within the tests package.""" return open(os.path.join(os.path.dirname(__file__), filename), mode) def setUp(test): test.globs.update(dict(open_file=open_file,)) def test_suite(): return unittest.TestSuite( [doctest.DocFileSuite(os.path.basename(filename), optionflags=optionflags, setUp=setUp) for filename in list_doctests()]) if __name__ == "__main__": runner = unittest.TextTestRunner(verbosity=1) runner.run(test_suite()) Shapely-1.3.0/shapely/tests/test_emptiness.py000066400000000000000000000026551226057120100213530ustar00rootroot00000000000000from . import unittest from shapely.geometry.base import BaseGeometry import shapely.geometry as sgeom from shapely.geometry.polygon import LinearRing class EmptinessTestCase(unittest.TestCase): def test_empty_base(self): g = BaseGeometry() self.assertTrue(g._is_empty) def test_emptying_point(self): p = sgeom.Point(0, 0) self.assertFalse(p._is_empty) p.empty() self.assertTrue(p._is_empty) def test_none_geom(self): p = BaseGeometry() p._geom = None self.assertTrue(p.is_empty) def test_empty_point(self): self.assertTrue(sgeom.Point().is_empty) def test_empty_multipoint(self): self.assertTrue(sgeom.MultiPoint().is_empty) def test_empty_geometry_collection(self): self.assertTrue(sgeom.GeometryCollection().is_empty) def test_empty_linestring(self): self.assertTrue(sgeom.LineString().is_empty) def test_empty_multilinestring(self): self.assertTrue(sgeom.MultiLineString([]).is_empty) def test_empty_polygon(self): self.assertTrue(sgeom.Polygon().is_empty) def test_empty_multipolygon(self): self.assertTrue(sgeom.MultiPolygon([]).is_empty) def test_empty_linear_ring(self): self.assertTrue(LinearRing().is_empty) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(EmptinessTestCase) if __name__ == '__main__': unittest.main() Shapely-1.3.0/shapely/tests/test_equality.py000066400000000000000000000017131226057120100211730ustar00rootroot00000000000000from . import unittest from shapely import geometry class PointEqualityTestCase(unittest.TestCase): def test_equals_exact(self): p1 = geometry.Point(1.0, 1.0) p2 = geometry.Point(2.0, 2.0) self.assertFalse(p1.equals(p2)) self.assertFalse(p1.equals_exact(p2, 0.001)) def test_almost_equals_default(self): p1 = geometry.Point(1.0, 1.0) p2 = geometry.Point(1.0+1e-7, 1.0+1e-7) # almost equal to 6 places p3 = geometry.Point(1.0+1e-6, 1.0+1e-6) # not almost equal self.assertTrue(p1.almost_equals(p2)) self.assertFalse(p1.almost_equals(p3)) def test_almost_equals(self): p1 = geometry.Point(1.0, 1.0) p2 = geometry.Point(1.1, 1.1) self.assertFalse(p1.equals(p2)) self.assertTrue(p1.almost_equals(p2, 0)) self.assertFalse(p1.almost_equals(p2, 1)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PointEqualityTestCase) Shapely-1.3.0/shapely/tests/test_geointerface.py000066400000000000000000000054131226057120100217720ustar00rootroot00000000000000from . import unittest from shapely.geometry import asShape from shapely.geometry.multipoint import MultiPointAdapter from shapely.geometry.linestring import LineStringAdapter from shapely.geometry.multilinestring import MultiLineStringAdapter from shapely.geometry.polygon import PolygonAdapter from shapely.geometry.multipolygon import MultiPolygonAdapter class GeoThing(object): def __init__(self, d): self.__geo_interface__ = d class GeoInterfaceTestCase(unittest.TestCase): def test_geointerface(self): # Adapt a dictionary d = {"type": "Point", "coordinates": (0.0, 0.0)} shape = asShape(d) self.assertEqual(shape.geom_type, 'Point') self.assertEqual(tuple(shape.coords), ((0.0, 0.0),)) # Adapt an object that implements the geo protocol shape = None thing = GeoThing({"type": "Point", "coordinates": (0.0, 0.0)}) shape = asShape(thing) self.assertEqual(shape.geom_type, 'Point') self.assertEqual(tuple(shape.coords), ((0.0, 0.0),)) # Check line string shape = asShape( {'type': 'LineString', 'coordinates': ((-1.0, -1.0), (1.0, 1.0))}) self.assertIsInstance(shape, LineStringAdapter) self.assertEqual(tuple(shape.coords), ((-1.0, -1.0), (1.0, 1.0))) # polygon shape = asShape( {'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)), ((0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.1), (0.1, 0.1)))} ) self.assertIsInstance(shape, PolygonAdapter) self.assertEqual( tuple(shape.exterior.coords), ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0))) self.assertEqual(len(shape.interiors), 1) # multi point shape = asShape({'type': 'MultiPoint', 'coordinates': ((1.0, 2.0), (3.0, 4.0))}) self.assertIsInstance(shape, MultiPointAdapter) self.assertEqual(len(shape.geoms), 2) # multi line string shape = asShape({'type': 'MultiLineString', 'coordinates': (((0.0, 0.0), (1.0, 2.0)),)}) self.assertIsInstance(shape, MultiLineStringAdapter) self.assertEqual(len(shape.geoms), 1) # multi polygon shape = asShape( {'type': 'MultiPolygon', 'coordinates': [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)), ((0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.1), (0.1, 0.1)) )]}) self.assertIsInstance(shape, MultiPolygonAdapter) self.assertEqual(len(shape.geoms), 1) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(GeoInterfaceTestCase) Shapely-1.3.0/shapely/tests/test_geomseq.py000066400000000000000000000006111226057120100207720ustar00rootroot00000000000000from . import unittest from shapely import geometry class MultiLineTestCase(unittest.TestCase): def test_array_interface(self): m = geometry.MultiLineString([((0, 0), (1, 1)), ((2, 2), (3, 3))]) ai = m.geoms[0].__array_interface__ self.assertEqual(ai['shape'], (2, 2)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(MultiLineTestCase) Shapely-1.3.0/shapely/tests/test_getitem.py000066400000000000000000000126551226057120100210030ustar00rootroot00000000000000from . import unittest from shapely import geometry class CoordsGetItemTestCase(unittest.TestCase): def test_index_2d_coords(self): c = [(float(x), float(-x)) for x in range(4)] g = geometry.LineString(c) for i in range(-4, 4): self.assertTrue(g.coords[i] == c[i]) self.assertRaises(IndexError, lambda: g.coords[4]) self.assertRaises(IndexError, lambda: g.coords[-5]) def test_index_3d_coords(self): c = [(float(x), float(-x), float(x*2)) for x in range(4)] g = geometry.LineString(c) for i in range(-4, 4): self.assertTrue(g.coords[i] == c[i]) self.assertRaises(IndexError, lambda: g.coords[4]) self.assertRaises(IndexError, lambda: g.coords[-5]) def test_index_coords_misc(self): g = geometry.LineString() # empty self.assertRaises(IndexError, lambda: g.coords[0]) self.assertRaises(TypeError, lambda: g.coords[0.0]) def test_slice_2d_coords(self): c = [(float(x), float(-x)) for x in range(4)] g = geometry.LineString(c) self.assertTrue(g.coords[1:] == c[1:]) self.assertTrue(g.coords[:-1] == c[:-1]) self.assertTrue(g.coords[::-1] == c[::-1]) self.assertTrue(g.coords[::2] == c[::2]) self.assertTrue(g.coords[:4] == c[:4]) self.assertTrue(g.coords[4:] == c[4:] == []) def test_slice_3d_coords(self): c = [(float(x), float(-x), float(x*2)) for x in range(4)] g = geometry.LineString(c) self.assertTrue(g.coords[1:] == c[1:]) self.assertTrue(g.coords[:-1] == c[:-1]) self.assertTrue(g.coords[::-1] == c[::-1]) self.assertTrue(g.coords[::2] == c[::2]) self.assertTrue(g.coords[:4] == c[:4]) self.assertTrue(g.coords[4:] == c[4:] == []) class MultiGeomGetItemTestCase(unittest.TestCase): def test_index_multigeom(self): c = [(float(x), float(-x)) for x in range(4)] g = geometry.MultiPoint(c) for i in range(-4, 4): self.assertTrue(g[i].equals(geometry.Point(c[i]))) self.assertRaises(IndexError, lambda: g[4]) self.assertRaises(IndexError, lambda: g[-5]) def test_index_multigeom_misc(self): g = geometry.MultiLineString() # empty self.assertRaises(IndexError, lambda: g[0]) self.assertRaises(TypeError, lambda: g[0.0]) def test_slice_multigeom(self): c = [(float(x), float(-x)) for x in range(4)] g = geometry.MultiPoint(c) self.assertEqual(type(g[:]), type(g)) self.assertEqual(len(g[:]), len(g)) self.assertTrue(g[1:].equals(geometry.MultiPoint(c[1:]))) self.assertTrue(g[:-1].equals(geometry.MultiPoint(c[:-1]))) self.assertTrue(g[::-1].equals(geometry.MultiPoint(c[::-1]))) self.assertTrue(g[4:].is_empty) class LinearRingGetItemTestCase(unittest.TestCase): def test_index_linearring(self): shell = geometry.polygon.LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)]) holes = [geometry.polygon.LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]), geometry.polygon.LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]), geometry.polygon.LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)])] g = geometry.Polygon(shell, holes) for i in range(-3, 3): self.assertTrue(g.interiors[i].equals(holes[i])) self.assertRaises(IndexError, lambda: g.interiors[3]) self.assertRaises(IndexError, lambda: g.interiors[-4]) def test_index_linearring_misc(self): g = geometry.Polygon() # empty self.assertRaises(IndexError, lambda: g.interiors[0]) self.assertRaises(TypeError, lambda: g.interiors[0.0]) def test_slice_linearring(self): shell = geometry.polygon.LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)]) holes = [geometry.polygon.LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]), geometry.polygon.LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]), geometry.polygon.LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)])] g = geometry.Polygon(shell, holes) t = [a.equals(b) for (a, b) in zip(g.interiors[1:], holes[1:])] self.assertTrue(all(t)) t = [a.equals(b) for (a, b) in zip(g.interiors[:-1], holes[:-1])] self.assertTrue(all(t)) t = [a.equals(b) for (a, b) in zip(g.interiors[::-1], holes[::-1])] self.assertTrue(all(t)) t = [a.equals(b) for (a, b) in zip(g.interiors[::2], holes[::2])] self.assertTrue(all(t)) t = [a.equals(b) for (a, b) in zip(g.interiors[:3], holes[:3])] self.assertTrue(all(t)) self.assertTrue(g.interiors[3:] == holes[3:] == []) def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(CoordsGetItemTestCase), loader.loadTestsFromTestCase(MultiGeomGetItemTestCase), loader.loadTestsFromTestCase(LinearRingGetItemTestCase)]) Shapely-1.3.0/shapely/tests/test_invalid_geometries.py000066400000000000000000000020121226057120100232000ustar00rootroot00000000000000'''Test recovery from operation on invalid geometries ''' from . import unittest from shapely.geometry import Polygon from shapely.topology import TopologicalError class InvalidGeometriesTestCase(unittest.TestCase): def test_invalid_intersection(self): # Make a self-intersecting polygon polygon_invalid = Polygon(((0, 0), (1, 1), (1, -1), (0, 1), (0, 0))) self.assertFalse(polygon_invalid.is_valid) # Intersect with a valid polygon polygon = Polygon(((-.5, -.5), (-.5, .5), (.5, .5), (.5, -5))) self.assertTrue(polygon.is_valid) self.assertTrue(polygon_invalid.intersects(polygon)) self.assertRaises(TopologicalError, polygon_invalid.intersection, polygon) self.assertRaises(TopologicalError, polygon.intersection, polygon_invalid) return def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(InvalidGeometriesTestCase)]) Shapely-1.3.0/shapely/tests/test_iterops.py000066400000000000000000000027241226057120100210260ustar00rootroot00000000000000"""Test operator iterations """ from . import unittest from shapely import iterops from shapely.geometry import Point, Polygon class IterOpsTestCase(unittest.TestCase): def test_iterops(self): coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)) polygon = Polygon(coords) points = [Point(0.5, 0.5), Point(2.0, 2.0)] # List of the points contained by the polygon self.assertTrue( all([isinstance(x, Point) for x in iterops.contains(polygon, points, True)])) # 'True' is the default value self.assertTrue( all([isinstance(x, Point) for x in iterops.contains(polygon, points)])) # Test a false value self.assertTrue( all([isinstance(x, Point) for x in iterops.contains(polygon, points, False)])) # If the provided iterator yields tuples, the second value will be # yielded self.assertEqual( list(iterops.contains(polygon, [(p, p.coords[:]) for p in points], False)), [[(2.0, 2.0)]]) # Just to demonstrate that the important thing is that the second # parameter is an iterator: self.assertEqual( list(iterops.contains(polygon, iter((p, p.coords[:]) for p in points))), [[(0.5, 0.5)]]) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(IterOpsTestCase) Shapely-1.3.0/shapely/tests/test_linear_referencing.py000066400000000000000000000060131226057120100231550ustar00rootroot00000000000000from . import unittest from shapely.geos import geos_version from shapely.geometry import Point, LineString, MultiLineString class LinearReferencingTestCase(unittest.TestCase): def setUp(self): self.point = Point(1, 1) self.line1 = LineString(([0, 0], [2, 0])) self.line2 = LineString(([3, 0], [3, 6])) self.multiline = MultiLineString([ list(self.line1.coords), list(self.line2.coords) ]) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line1_project(self): self.assertEqual(self.line1.project(self.point), 1.0) self.assertEqual(self.line1.project(self.point, normalized=True), 0.5) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line2_project(self): self.assertEqual(self.line2.project(self.point), 1.0) self.assertAlmostEqual( self.line2.project(self.point, normalized=True), 0.16666666666, 8) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_multiline_project(self): self.assertEqual(self.multiline.project(self.point), 1.0) self.assertEqual( self.multiline.project(self.point, normalized=True), 0.125) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_not_supported_project(self): with self.assertRaises(TypeError): self.point.buffer(1.0).project(self.point) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_not_on_line_project(self): # Points that aren't on the line project to 0. self.assertEqual(self.line1.project(Point(-10, -10)), 0.0) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line1_interpolate(self): self.assertTrue(self.line1.interpolate(0.5).equals(Point(0.5, 0.0))) self.assertTrue( self.line1.interpolate(0.5, normalized=True).equals(Point(1, 0))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line2_interpolate(self): self.assertTrue(self.line2.interpolate(0.5).equals(Point(3.0, 0.5))) self.assertTrue( self.line2.interpolate(0.5, normalized=True).equals(Point(3, 3))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_multiline_interpolate(self): self.assertTrue(self.multiline.interpolate(0.5).equals(Point(0.5, 0))) self.assertTrue( self.multiline.interpolate(0.5, normalized=True).equals( Point(3.0, 2.0))) @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required') def test_line_ends_interpolate(self): # Distances greater than length of the line or less than # zero yield the line's ends. self.assertTrue(self.line1.interpolate(-1000).equals(Point(0.0, 0.0))) self.assertTrue(self.line1.interpolate(1000).equals(Point(2.0, 0.0))) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(LinearReferencingTestCase) Shapely-1.3.0/shapely/tests/test_linemerge.py000066400000000000000000000030641226057120100213060ustar00rootroot00000000000000from . import unittest from shapely.geometry import LineString, MultiLineString from shapely.ops import linemerge class LineMergeTestCase(unittest.TestCase): def test_linemerge(self): lines = MultiLineString( [((0, 0), (1, 1)), ((2, 0), (2, 1), (1, 1))]) result = linemerge(lines) self.assertIsInstance(result, LineString) self.assertFalse(result.is_ring) self.assertEqual(len(result.coords), 4) self.assertEqual(result.coords[0], (0.0, 0.0)) self.assertEqual(result.coords[3], (2.0, 0.0)) lines2 = MultiLineString( [((0, 0), (1, 1)), ((0, 0), (2, 0), (2, 1), (1, 1))]) result = linemerge(lines2) self.assertTrue(result.is_ring) self.assertEqual(len(result.coords), 5) lines3 = [ LineString(((0, 0), (1, 1))), LineString(((0, 0), (0, 1))), ] result = linemerge(lines3) self.assertFalse(result.is_ring) self.assertEqual(len(result.coords), 3) self.assertEqual(result.coords[0], (0.0, 1.0)) self.assertEqual(result.coords[2], (1.0, 1.0)) lines4 = [ ((0, 0), (1, 1)), ((0, 0), (0, 1)), ] self.assertTrue(result.equals(linemerge(lines4))) lines5 = [ ((0, 0), (1, 1)), ((1, 0), (0, 1)), ] result = linemerge(lines5) self.assertEqual(result.type, 'MultiLineString') def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(LineMergeTestCase) Shapely-1.3.0/shapely/tests/test_linestring.py000066400000000000000000000067111226057120100215170ustar00rootroot00000000000000from . import unittest, numpy from shapely.geometry import LineString, asLineString class LineStringTestCase(unittest.TestCase): def test_linestring(self): # From coordinate tuples line = LineString(((1.0, 2.0), (3.0, 4.0))) self.assertEqual(len(line.coords), 2) self.assertEqual(line.coords[:], [(1.0, 2.0), (3.0, 4.0)]) # From lines copy = LineString(line) self.assertEqual(len(copy.coords), 2) self.assertEqual(copy.coords[:], [(1.0, 2.0), (3.0, 4.0)]) # Bounds self.assertEqual(line.bounds, (1.0, 2.0, 3.0, 4.0)) # Coordinate access self.assertEqual(tuple(line.coords), ((1.0, 2.0), (3.0, 4.0))) self.assertEqual(line.coords[0], (1.0, 2.0)) self.assertEqual(line.coords[1], (3.0, 4.0)) with self.assertRaises(IndexError): line.coords[2] # index out of range # Geo interface self.assertEqual(line.__geo_interface__, {'type': 'LineString', 'coordinates': ((1.0, 2.0), (3.0, 4.0))}) # Coordinate modification line.coords = ((-1.0, -1.0), (1.0, 1.0)) self.assertEqual(line.__geo_interface__, {'type': 'LineString', 'coordinates': ((-1.0, -1.0), (1.0, 1.0))}) # Adapt a coordinate list to a line string coords = [[5.0, 6.0], [7.0, 8.0]] la = asLineString(coords) self.assertEqual(la.coords[:], [(5.0, 6.0), (7.0, 8.0)]) # Test Non-operability of Null geometry l_null = LineString() self.assertEqual(l_null.wkt, 'GEOMETRYCOLLECTION EMPTY') self.assertEqual(l_null.length, 0.0) # Check that we can set coordinates of a null geometry l_null.coords = [(0, 0), (1, 1)] self.assertAlmostEqual(l_null.length, 1.4142135623730951) @unittest.skipIf(not numpy, 'Numpy required') def test_numpy(self): from numpy import array, asarray from numpy.testing import assert_array_equal # Construct from a numpy array line = LineString(array([[0.0, 0.0], [1.0, 2.0]])) self.assertEqual(len(line.coords), 2) self.assertEqual(line.coords[:], [(0.0, 0.0), (1.0, 2.0)]) line = LineString(((1.0, 2.0), (3.0, 4.0))) la = asarray(line) expected = array([[1.0, 2.0], [3.0, 4.0]]) assert_array_equal(la, expected) # Coordinate sequences can be adapted as well la = asarray(line.coords) assert_array_equal(la, expected) # Adapt a Numpy array to a line string a = array([[1.0, 2.0], [3.0, 4.0]]) la = asLineString(a) assert_array_equal(la.context, a) self.assertEqual(la.coords[:], [(1.0, 2.0), (3.0, 4.0)]) # Now, the inverse self.assertEqual(la.__array_interface__, la.context.__array_interface__) pas = asarray(la) assert_array_equal(pas, array([[1.0, 2.0], [3.0, 4.0]])) # From Array.txt a = asarray([[0.0, 0.0], [2.0, 2.0], [1.0, 1.0]]) line = LineString(a) self.assertEqual(line.coords[:], [(0.0, 0.0), (2.0, 2.0), (1.0, 1.0)]) data = line.ctypes self.assertEqual(data[0], 0.0) self.assertEqual(data[5], 1.0) b = asarray(line) assert_array_equal(b, array([[0., 0.], [2., 2.], [1., 1.]])) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase) Shapely-1.3.0/shapely/tests/test_locale.py000066400000000000000000000024371226057120100206010ustar00rootroot00000000000000'''Test locale independence of WKT ''' from . import unittest import sys import locale from shapely.wkt import loads, dumps # Set locale to one that uses a comma as decimal seperator # TODO: try a few other common locales if sys.platform == 'win32': test_locales = { 'Portuguese': 'portuguese_brazil', } else: test_locales = { 'Portuguese': 'pt_BR.UTF-8', } do_test_locale = False def setUpModule(): global do_test_locale for name in test_locales: try: test_locale = test_locales[name] locale.setlocale(locale.LC_ALL, test_locale) do_test_locale = True break except: pass if not do_test_locale: raise unittest.SkipTest('test locale not found') def tearDownModule(): locale.resetlocale() class LocaleTestCase(unittest.TestCase): #@unittest.skipIf(not do_test_locale, 'test locale not found') def test_wkt_locale(self): # Test reading and writing p = loads('POINT (0.0 0.0)') self.assertEqual(p.x, 0.0) self.assertEqual(p.y, 0.0) wkt = dumps(p) self.assertTrue(wkt.startswith('POINT')) self.assertFalse(',' in wkt) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(LocaleTestCase) Shapely-1.3.0/shapely/tests/test_mapping.py000066400000000000000000000005521226057120100207710ustar00rootroot00000000000000from . import unittest from shapely.geometry import Point, mapping class MappingTestCase(unittest.TestCase): def test_point(self): m = mapping(Point(0, 0)) self.assertEqual(m['type'], 'Point') self.assertEqual(m['coordinates'], (0.0, 0.0)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(MappingTestCase) Shapely-1.3.0/shapely/tests/test_multilinestring.py000066400000000000000000000043471226057120100225750ustar00rootroot00000000000000from . import unittest, numpy from shapely.geometry import LineString, MultiLineString, asMultiLineString from shapely.geometry.base import dump_coords class MultiLineStringTestCase(unittest.TestCase): def test_multipoint(self): # From coordinate tuples geom = MultiLineString((((1.0, 2.0), (3.0, 4.0)),)) self.assertIsInstance(geom, MultiLineString) self.assertEqual(len(geom.geoms), 1) self.assertEqual(dump_coords(geom), [[(1.0, 2.0), (3.0, 4.0)]]) # From lines a = LineString(((1.0, 2.0), (3.0, 4.0))) ml = MultiLineString([a]) self.assertEqual(len(ml.geoms), 1) self.assertEqual(dump_coords(ml), [[(1.0, 2.0), (3.0, 4.0)]]) # From another multi-line ml2 = MultiLineString(ml) self.assertEqual(len(ml2.geoms), 1) self.assertEqual(dump_coords(ml2), [[(1.0, 2.0), (3.0, 4.0)]]) # Sub-geometry Access geom = MultiLineString([(((0.0, 0.0), (1.0, 2.0)))]) self.assertIsInstance(geom[0], LineString) self.assertEqual(dump_coords(geom[0]), [(0.0, 0.0), (1.0, 2.0)]) with self.assertRaises(IndexError): # index out of range geom.geoms[1] # Geo interface self.assertEqual(geom.__geo_interface__, {'type': 'MultiLineString', 'coordinates': (((0.0, 0.0), (1.0, 2.0)),)}) @unittest.skipIf(not numpy, 'Numpy required') def test_numpy(self): from numpy import array from numpy.testing import assert_array_equal # Construct from a numpy array geom = MultiLineString([array(((0.0, 0.0), (1.0, 2.0)))]) self.assertIsInstance(geom, MultiLineString) self.assertEqual(len(geom.geoms), 1) self.assertEqual(dump_coords(geom), [[(0.0, 0.0), (1.0, 2.0)]]) # Adapt a sequence of Numpy arrays to a multilinestring a = [array(((1.0, 2.0), (3.0, 4.0)))] geoma = asMultiLineString(a) assert_array_equal(geoma.context, [array([[1., 2.], [3., 4.]])]) self.assertEqual(dump_coords(geoma), [[(1.0, 2.0), (3.0, 4.0)]]) # TODO: is there an inverse? def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(MultiLineStringTestCase) Shapely-1.3.0/shapely/tests/test_multipoint.py000066400000000000000000000051651226057120100215470ustar00rootroot00000000000000from . import unittest, numpy from shapely.geometry import Point, MultiPoint, asMultiPoint from shapely.geometry.base import dump_coords class MultiPointTestCase(unittest.TestCase): def test_multipoint(self): # From coordinate tuples geom = MultiPoint(((1.0, 2.0), (3.0, 4.0))) self.assertEqual(len(geom.geoms), 2) self.assertEqual(dump_coords(geom), [[(1.0, 2.0)], [(3.0, 4.0)]]) # From points geom = MultiPoint((Point(1.0, 2.0), Point(3.0, 4.0))) self.assertEqual(len(geom.geoms), 2) self.assertEqual(dump_coords(geom), [[(1.0, 2.0)], [(3.0, 4.0)]]) # From another multi-point geom2 = MultiPoint(geom) self.assertEqual(len(geom2.geoms), 2) self.assertEqual(dump_coords(geom2), [[(1.0, 2.0)], [(3.0, 4.0)]]) # Sub-geometry Access self.assertIsInstance(geom.geoms[0], Point) self.assertEqual(geom.geoms[0].x, 1.0) self.assertEqual(geom.geoms[0].y, 2.0) with self.assertRaises(IndexError): # index out of range geom.geoms[2] # Geo interface self.assertEqual(geom.__geo_interface__, {'type': 'MultiPoint', 'coordinates': ((1.0, 2.0), (3.0, 4.0))}) # Adapt a coordinate list to a line string coords = [[5.0, 6.0], [7.0, 8.0]] geoma = asMultiPoint(coords) self.assertEqual(dump_coords(geoma), [[(5.0, 6.0)], [(7.0, 8.0)]]) @unittest.skipIf(not numpy, 'Numpy required') def test_numpy(self): from numpy import array, asarray from numpy.testing import assert_array_equal # Construct from a numpy array geom = MultiPoint(array([[0.0, 0.0], [1.0, 2.0]])) self.assertIsInstance(geom, MultiPoint) self.assertEqual(len(geom.geoms), 2) self.assertEqual(dump_coords(geom), [[(0.0, 0.0)], [(1.0, 2.0)]]) # Geo interface (cont.) geom = MultiPoint((Point(1.0, 2.0), Point(3.0, 4.0))) assert_array_equal(array(geom), array([[1., 2.], [3., 4.]])) # Adapt a Numpy array to a multipoint a = array([[1.0, 2.0], [3.0, 4.0]]) geoma = asMultiPoint(a) assert_array_equal(geoma.context, array([[1., 2.], [3., 4.]])) self.assertEqual(dump_coords(geoma), [[(1.0, 2.0)], [(3.0, 4.0)]]) # Now, the inverse self.assertEqual(geoma.__array_interface__, geoma.context.__array_interface__) pas = asarray(geoma) assert_array_equal(pas, array([[1., 2.], [3., 4.]])) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(MultiPointTestCase) Shapely-1.3.0/shapely/tests/test_multipolygon.py000066400000000000000000000055231226057120100221030ustar00rootroot00000000000000from . import unittest from shapely.geometry import Polygon, MultiPolygon, asMultiPolygon from shapely.geometry.base import dump_coords class MultiPolygonTestCase(unittest.TestCase): def test_multipolygon(self): # From coordinate tuples geom = MultiPolygon( [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)), [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))])]) self.assertIsInstance(geom, MultiPolygon) self.assertEqual(len(geom.geoms), 1) self.assertEqual( dump_coords(geom), [[(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0), [(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)]]]) # Or from polygons p = Polygon(((0, 0), (0, 1), (1, 1), (1, 0)), [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) geom = MultiPolygon([p]) self.assertEqual(len(geom.geoms), 1) self.assertEqual( dump_coords(geom), [[(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0), [(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)]]]) # Or from another multi-polygon geom2 = MultiPolygon(geom) self.assertEqual(len(geom2.geoms), 1) self.assertEqual( dump_coords(geom2), [[(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0), [(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)]]]) # Sub-geometry Access self.assertIsInstance(geom.geoms[0], Polygon) self.assertEqual( dump_coords(geom.geoms[0]), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0), [(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)]]) with self.assertRaises(IndexError): # index out of range geom.geoms[1] # Geo interface self.assertEqual( geom.__geo_interface__, {'type': 'MultiPolygon', 'coordinates': [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)))]}) # Adapter coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) holes_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))] mpa = asMultiPolygon([(coords, holes_coords)]) self.assertEqual(len(mpa.geoms), 1) self.assertEqual(len(mpa.geoms[0].exterior.coords), 5) self.assertEqual(len(mpa.geoms[0].interiors), 1) self.assertEqual(len(mpa.geoms[0].interiors[0].coords), 5) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(MultiPolygonTestCase) Shapely-1.3.0/shapely/tests/test_ndarrays.py000066400000000000000000000030711226057120100211600ustar00rootroot00000000000000# Tests of support for Numpy ndarrays. See # https://github.com/sgillies/shapely/issues/26 for discussion. # Requires numpy. import sys if sys.version_info[0] >= 3: from functools import reduce from . import unittest from shapely import geometry try: import numpy except ImportError: numpy = False class TransposeTestCase(unittest.TestCase): @unittest.skipIf(not numpy, 'numpy not installed') def test_multipoint(self): a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]]) t = a.T s = geometry.asMultiPoint(t) coords = reduce(lambda x, y: x + y, [list(g.coords) for g in s]) self.assertEqual( coords, [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)] ) @unittest.skipIf(not numpy, 'numpy not installed') def test_linestring(self): a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]]) t = a.T s = geometry.asLineString(t) self.assertEqual( list(s.coords), [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)] ) @unittest.skipIf(not numpy, 'numpy not installed') def test_polygon(self): a = numpy.array([[1.0, 1.0, 2.0, 2.0, 1.0], [3.0, 4.0, 4.0, 3.0, 3.0]]) t = a.T s = geometry.asPolygon(t) self.assertEqual( list(s.exterior.coords), [(1.0, 3.0), (1.0, 4.0), (2.0, 4.0), (2.0, 3.0), (1.0, 3.0)] ) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(TransposeTestCase) Shapely-1.3.0/shapely/tests/test_operations.py000066400000000000000000000045541226057120100215270ustar00rootroot00000000000000from . import unittest from shapely.geometry import Point, Polygon, MultiPoint, GeometryCollection from shapely.wkt import loads class OperationsTestCase(unittest.TestCase): def test_operations(self): point = Point(0.0, 0.0) # General geometry self.assertEqual(point.area, 0.0) self.assertEqual(point.length, 0.0) self.assertAlmostEqual(point.distance(Point(-1.0, -1.0)), 1.4142135623730951) # Topology operations # Envelope self.assertIsInstance(point.envelope, Point) # Intersection self.assertIsInstance(point.intersection(Point(-1, -1)), GeometryCollection) # Buffer self.assertIsInstance(point.buffer(10.0), Polygon) self.assertIsInstance(point.buffer(10.0, 32), Polygon) # Simplify p = loads('POLYGON ((120 120, 121 121, 122 122, 220 120, 180 199, ' '160 200, 140 199, 120 120))') expected = loads('POLYGON ((120 120, 140 199, 160 200, 180 199, ' '220 120, 120 120))') s = p.simplify(10.0, preserve_topology=False) self.assertTrue(s.equals_exact(expected, 0.001)) p = loads('POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200),' '(120 120, 220 120, 180 199, 160 200, 140 199, 120 120))') expected = loads( 'POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200),' '(120 120, 220 120, 180 199, 160 200, 140 199, 120 120))') s = p.simplify(10.0, preserve_topology=True) self.assertTrue(s.equals_exact(expected, 0.001)) # Convex Hull self.assertIsInstance(point.convex_hull, Point) # Differences self.assertIsInstance(point.difference(Point(-1, 1)), Point) self.assertIsInstance(point.symmetric_difference(Point(-1, 1)), MultiPoint) # Boundary self.assertIsInstance(point.boundary, GeometryCollection) # Union self.assertIsInstance(point.union(Point(-1, 1)), MultiPoint) self.assertIsInstance(point.representative_point(), Point) self.assertIsInstance(point.centroid, Point) # Relate self.assertEqual(point.relate(Point(-1, -1)), 'FF0FFF0F2') def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(OperationsTestCase) Shapely-1.3.0/shapely/tests/test_operators.py000066400000000000000000000010501226057120100213460ustar00rootroot00000000000000from . import unittest from shapely.geometry import Point class OperatorsTestCase(unittest.TestCase): def test_point(self): point = Point(0, 0) point2 = Point(-1, 1) self.assertTrue(point.union(point2).equals(point | point2)) self.assertTrue((point & point2).is_empty) self.assertTrue(point.equals(point - point2)) self.assertTrue( point.symmetric_difference(point2).equals(point ^ point2)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(OperatorsTestCase) Shapely-1.3.0/shapely/tests/test_persist.py000066400000000000000000000013771226057120100210350ustar00rootroot00000000000000"""Persistence tests """ from . import unittest import pickle from shapely import wkb, wkt from shapely.geometry import Point class PersistTestCase(unittest.TestCase): def test_pickle(self): p = Point(0.0, 0.0) data = pickle.dumps(p) q = pickle.loads(data) self.assertTrue(q.equals(p)) def test_wkb(self): p = Point(0.0, 0.0) bytes = wkb.dumps(p) pb = wkb.loads(bytes) self.assertTrue(pb.equals(p)) def test_wkt(self): p = Point(0.0, 0.0) text = wkt.dumps(p) self.assertTrue(text.startswith('POINT')) pt = wkt.loads(text) self.assertTrue(pt.equals(p)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PersistTestCase) Shapely-1.3.0/shapely/tests/test_pickle.py000066400000000000000000000011021226057120100205750ustar00rootroot00000000000000from . import unittest from shapely import geometry import sys if sys.version_info[0] >= 3: from pickle import dumps, loads, HIGHEST_PROTOCOL else: from cPickle import dumps, loads, HIGHEST_PROTOCOL class TwoDeeTestCase(unittest.TestCase): def test_linestring(self): l = geometry.LineString(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0))) self.assertEqual(l._ndim, 2) s = dumps(l, HIGHEST_PROTOCOL) t = loads(s) self.assertEqual(t._ndim, 2) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(TwoDeeTestCase) Shapely-1.3.0/shapely/tests/test_point.py000066400000000000000000000105661226057120100204750ustar00rootroot00000000000000from . import unittest, numpy from shapely.geometry import Point, asPoint from shapely.geos import DimensionError class LineStringTestCase(unittest.TestCase): def test_point(self): # Test 2D points p = Point(1.0, 2.0) self.assertEqual(p.x, 1.0) self.assertEqual(p.y, 2.0) self.assertEqual(p.coords[:], [(1.0, 2.0)]) self.assertEqual(str(p), p.wkt) self.assertFalse(p.has_z) with self.assertRaises(DimensionError): p.z # Check 3D p = Point(1.0, 2.0, 3.0) self.assertEqual(p.coords[:], [(1.0, 2.0, 3.0)]) self.assertEqual(str(p), p.wkt) self.assertTrue(p.has_z) self.assertEqual(p.z, 3.0) # From coordinate sequence p = Point((3.0, 4.0)) self.assertEqual(p.coords[:], [(3.0, 4.0)]) # From another point q = Point(p) self.assertEqual(q.coords[:], [(3.0, 4.0)]) # Coordinate access self.assertEqual(p.x, 3.0) self.assertEqual(p.y, 4.0) self.assertEqual(tuple(p.coords), ((3.0, 4.0),)) self.assertEqual(p.coords[0], (3.0, 4.0)) with self.assertRaises(IndexError): # index out of range p.coords[1] # Bounds self.assertEqual(p.bounds, (3.0, 4.0, 3.0, 4.0)) # Geo interface self.assertEqual(p.__geo_interface__, {'type': 'Point', 'coordinates': (3.0, 4.0)}) # Modify coordinates p.coords = (2.0, 1.0) self.assertEqual(p.__geo_interface__, {'type': 'Point', 'coordinates': (2.0, 1.0)}) # Alternate method p.coords = ((0.0, 0.0),) self.assertEqual(p.__geo_interface__, {'type': 'Point', 'coordinates': (0.0, 0.0)}) # Adapt a coordinate list to a point coords = [3.0, 4.0] pa = asPoint(coords) self.assertEqual(pa.coords[0], (3.0, 4.0)) self.assertEqual(pa.distance(p), 5.0) # Move the coordinates and watch the distance change coords[0] = 1.0 self.assertEqual(pa.coords[0], (1.0, 4.0)) self.assertAlmostEqual(pa.distance(p), 4.123105625617661) # Test Non-operability of Null geometry p_null = Point() self.assertEqual(p_null.wkt, 'GEOMETRYCOLLECTION EMPTY') self.assertEqual(p_null.coords[:], []) self.assertEqual(p_null.area, 0.0) # Check that we can set coordinates of a null geometry p_null.coords = (1, 2) self.assertEqual(p_null.coords[:], [(1.0, 2.0)]) @unittest.skipIf(not numpy, 'Numpy required') def test_numpy(self): from numpy import array, asarray from numpy.testing import assert_array_equal # Construct from a numpy array p = Point(array([1.0, 2.0])) self.assertEqual(p.coords[:], [(1.0, 2.0)]) # Adapt a Numpy array to a point a = array([1.0, 2.0]) pa = asPoint(a) assert_array_equal(pa.context, array([1.0, 2.0])) self.assertEqual(pa.coords[:], [(1.0, 2.0)]) # Now, the inverse self.assertEqual(pa.__array_interface__, pa.context.__array_interface__) pas = asarray(pa) assert_array_equal(pas, array([1.0, 2.0])) # Adapt a coordinate list to a point coords = [3.0, 4.0] pa = asPoint(coords) coords[0] = 1.0 # Now, the inverse (again?) self.assertIsNotNone(pa.__array_interface__) pas = asarray(pa) assert_array_equal(pas, array([1.0, 4.0])) # From Array.txt p = Point(0.0, 0.0, 1.0) coords = p.coords[0] self.assertEqual(coords, (0.0, 0.0, 1.0)) self.assertIsNotNone(p.ctypes) # Convert to Numpy array, passing through Python sequence a = asarray(coords) self.assertEqual(a.ndim, 1) self.assertEqual(a.size, 3) self.assertEqual(a.shape, (3,)) # Convert to Numpy array, passing through a ctypes array b = asarray(p) self.assertEqual(b.size, 3) self.assertEqual(b.shape, (3,)) assert_array_equal(b, array([0.0, 0.0, 1.0])) # Make a point from a Numpy array a = asarray([1.0, 1.0, 0.0]) p = Point(*list(a)) self.assertEqual(p.coords[:], [(1.0, 1.0, 0.0)]) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(LineStringTestCase) Shapely-1.3.0/shapely/tests/test_polygon.py000066400000000000000000000161231226057120100210260ustar00rootroot00000000000000"""Polygons and Linear Rings """ from . import unittest, numpy from shapely.wkb import loads as load_wkb from shapely.geometry import Point, Polygon, asPolygon from shapely.geometry.polygon import LinearRing, asLinearRing from shapely.geometry.base import dump_coords class PolygonTestCase(unittest.TestCase): def test_polygon(self): # Initialization # Linear rings won't usually be created by users, but by polygons coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)) ring = LinearRing(coords) self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], ring.coords[-1]) self.assertTrue(ring.is_ring) # Coordinate modification ring.coords = ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0)) self.assertEqual( ring.__geo_interface__, {'type': 'LinearRing', 'coordinates': ((0.0, 0.0), (0.0, 2.0), (2.0, 2.0), (2.0, 0.0), (0.0, 0.0))}) # Test ring adapter coords = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]] ra = asLinearRing(coords) self.assertTrue(ra.wkt.upper().startswith('LINEARRING')) self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]) coords[3] = [2.0, -1.0] self.assertEqual(dump_coords(ra), [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)]) # Construct a polygon, exterior ring only polygon = Polygon(coords) self.assertEqual(len(polygon.exterior.coords), 5) # Ring Access self.assertIsInstance(polygon.exterior, LinearRing) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) self.assertEqual(len(polygon.interiors), 0) # Create a new polygon from WKB data = polygon.wkb polygon = None ring = None polygon = load_wkb(data) ring = polygon.exterior self.assertEqual(len(ring.coords), 5) self.assertEqual(ring.coords[0], ring.coords[4]) self.assertEqual(ring.coords[0], (0., 0.)) self.assertTrue(ring.is_ring) polygon = None # Interior rings (holes) polygon = Polygon(coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(len(polygon.interiors[0].coords), 5) with self.assertRaises(IndexError): # index out of range polygon.interiors[1] # Coordinate getters and setters raise exceptions self.assertRaises(NotImplementedError, polygon._get_coords) with self.assertRaises(NotImplementedError): polygon.coords # Geo interface self.assertEqual( polygon.__geo_interface__, {'type': 'Polygon', 'coordinates': (((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (2.0, -1.0), (0.0, 0.0)), ((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)))}) # Adapter hole_coords = [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))] pa = asPolygon(coords, hole_coords) self.assertEqual(len(pa.exterior.coords), 5) self.assertEqual(len(pa.interiors), 1) self.assertEqual(len(pa.interiors[0].coords), 5) # Test Non-operability of Null rings r_null = LinearRing() self.assertEqual(r_null.wkt, 'GEOMETRYCOLLECTION EMPTY') self.assertEqual(r_null.length, 0.0) # Check that we can set coordinates of a null geometry r_null.coords = [(0, 0), (1, 1), (1, 0)] self.assertAlmostEqual(r_null.length, 3.414213562373095) # Error handling with self.assertRaises(ValueError): # A LinearRing must have at least 3 coordinate tuples Polygon([[1, 2], [2, 3]]) @unittest.skipIf(not numpy, 'Numpy required') def test_numpy(self): from numpy import array, asarray from numpy.testing import assert_array_equal a = asarray(((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.))) polygon = Polygon(a) self.assertEqual(len(polygon.exterior.coords), 5) self.assertEqual(dump_coords(polygon.exterior), [(0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)]) self.assertEqual(len(polygon.interiors), 0) b = asarray(polygon.exterior) self.assertEqual(b.shape, (5, 2)) assert_array_equal( b, array([(0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)])) def test_dimensions(self): # Background: see http://trac.gispython.org/lab/ticket/168 # http://lists.gispython.org/pipermail/community/2008-August/001859.html coords = ((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 0.0, 0.0)) polygon = Polygon(coords) self.assertEqual(polygon._ndim, 3) gi = polygon.__geo_interface__ self.assertEqual( gi['coordinates'], (((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 0.0, 0.0), (0.0, 0.0, 0.0)),)) e = polygon.exterior self.assertEqual(e._ndim, 3) gi = e.__geo_interface__ self.assertEqual( gi['coordinates'], ((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 0.0, 0.0), (0.0, 0.0, 0.0))) def test_attribute_chains(self): # Attribute Chaining # See also ticket #151. p = Polygon(((0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0))) self.assertEqual( list(p.boundary.coords), [(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0), (0.0, 0.0)]) ec = list(Point(0.0, 0.0).buffer(1.0, 1).exterior.coords) self.assertIsInstance(ec, list) # TODO: this is a poor test # Test chained access to interiors p = Polygon( ((0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)), [((-0.25, 0.25), (-0.25, 0.75), (-0.75, 0.75), (-0.75, 0.25))] ) self.assertEqual(p.area, 0.75) """Not so much testing the exact values here, which are the responsibility of the geometry engine (GEOS), but that we can get chain functions and properties using anonymous references. """ self.assertEqual( list(p.interiors[0].coords), [(-0.25, 0.25), (-0.25, 0.75), (-0.75, 0.75), (-0.75, 0.25), (-0.25, 0.25)]) xy = list(p.interiors[0].buffer(1).exterior.coords)[0] self.assertEqual(len(xy), 2) # Test multiple operators, boundary of a buffer ec = list(p.buffer(1).boundary.coords) self.assertIsInstance(ec, list) # TODO: this is a poor test def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PolygonTestCase) Shapely-1.3.0/shapely/tests/test_polygonize.py000077500000000000000000000031661226057120100215440ustar00rootroot00000000000000from . import unittest from shapely.geos import geos_version from shapely.geometry import Point, LineString, Polygon from shapely.geometry.base import dump_coords from shapely.ops import polygonize, polygonize_full class PolygonizeTestCase(unittest.TestCase): def test_polygonize(self): lines = [ LineString(((0, 0), (1, 1))), LineString(((0, 0), (0, 1))), LineString(((0, 1), (1, 1))), LineString(((1, 1), (1, 0))), LineString(((1, 0), (0, 0))), LineString(((5, 5), (6, 6))), Point(0, 0), ] result = list(polygonize(lines)) self.assertTrue(all([isinstance(x, Polygon) for x in result])) @unittest.skipIf(geos_version < (3, 3, 0), 'GEOS 3.3.0 required') def test_polygonize_full(self): lines2 = [ ((0, 0), (1, 1)), ((0, 0), (0, 1)), ((0, 1), (1, 1)), ((1, 1), (1, 0)), ((1, 0), (0, 0)), ((5, 5), (6, 6)), ((1, 1), (100, 100)), ] result2, dangles, cuts, invalids = polygonize_full(lines2) self.assertEqual(len(result2), 2) self.assertTrue(all([isinstance(x, Polygon) for x in result2])) self.assertEqual(list(dangles.geoms), []) self.assertTrue(all([isinstance(x, LineString) for x in cuts.geoms])) self.assertEqual( dump_coords(cuts), [[(1.0, 1.0), (100.0, 100.0)], [(5.0, 5.0), (6.0, 6.0)]]) self.assertEqual(list(invalids.geoms), []) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PolygonizeTestCase) Shapely-1.3.0/shapely/tests/test_predicates.py000066400000000000000000000020201226057120100214510ustar00rootroot00000000000000"""Test GEOS predicates """ from . import unittest from shapely.geometry import Point class PredicatesTestCase(unittest.TestCase): def test_binary_predicates(self): point = Point(0.0, 0.0) self.assertTrue(point.disjoint(Point(-1.0, -1.0))) self.assertFalse(point.touches(Point(-1.0, -1.0))) self.assertFalse(point.crosses(Point(-1.0, -1.0))) self.assertFalse(point.within(Point(-1.0, -1.0))) self.assertFalse(point.contains(Point(-1.0, -1.0))) self.assertFalse(point.equals(Point(-1.0, -1.0))) self.assertFalse(point.touches(Point(-1.0, -1.0))) self.assertTrue(point.equals(Point(0.0, 0.0))) def test_unary_predicates(self): point = Point(0.0, 0.0) self.assertFalse(point.is_empty) self.assertTrue(point.is_valid) self.assertTrue(point.is_simple) self.assertFalse(point.is_ring) self.assertFalse(point.has_z) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PredicatesTestCase) Shapely-1.3.0/shapely/tests/test_prepared.py000066400000000000000000000022301226057120100211330ustar00rootroot00000000000000from . import unittest from shapely.geos import geos_version from shapely import prepared from shapely import geometry class PreparedGeometryTestCase(unittest.TestCase): @unittest.skipIf(geos_version < (3, 1, 0), 'GEOS 3.1.0 required') def test_prepared(self): polygon = geometry.Polygon([ (0, 0), (1, 0), (1, 1), (0, 1) ]) p = prepared.PreparedGeometry(polygon) self.assertTrue(p.contains(geometry.Point(0.5, 0.5))) self.assertFalse(p.contains(geometry.Point(0.5, 1.5))) @unittest.skipIf(geos_version < (3, 1, 0), 'GEOS 3.1.0 required') def test_op_not_allowed(self): p = prepared.PreparedGeometry(geometry.Point(0.0, 0.0).buffer(1.0)) self.assertRaises(ValueError, geometry.Point(0.0, 0.0).union, p) @unittest.skipIf(geos_version < (3, 1, 0), 'GEOS 3.1.0 required') def test_predicate_not_allowed(self): p = prepared.PreparedGeometry(geometry.Point(0.0, 0.0).buffer(1.0)) self.assertRaises(ValueError, geometry.Point(0.0, 0.0).contains, p) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(PreparedGeometryTestCase) Shapely-1.3.0/shapely/tests/test_products_z.py000066400000000000000000000010051226057120100215240ustar00rootroot00000000000000from . import unittest from shapely.geometry import LineString class ProductZTestCase(unittest.TestCase): def test_line_intersection(self): line1 = LineString([(0, 0, 0), (1, 1, 1)]) line2 = LineString([(0, 1, 1), (1, 0, 0)]) interxn = line1.intersection(line2) self.assertTrue(interxn.has_z) self.assertEqual(interxn._ndim, 3) self.assertTrue(0.0 <= interxn.z <= 1.0) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(ProductZTestCase) Shapely-1.3.0/shapely/tests/test_singularity.py000066400000000000000000000007621226057120100217130ustar00rootroot00000000000000from . import unittest from shapely.geometry import Polygon class PolygonTestCase(unittest.TestCase): def test_polygon_3(self): p = (1.0, 1.0) poly = Polygon([p, p, p]) self.assertEqual(poly.bounds, (1.0, 1.0, 1.0, 1.0)) def test_polygon_5(self): p = (1.0, 1.0) poly = Polygon([p, p, p, p, p]) self.assertEqual(poly.bounds, (1.0, 1.0, 1.0, 1.0)) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(PolygonTestCase) Shapely-1.3.0/shapely/tests/test_speedups.py000066400000000000000000000023011226057120100211600ustar00rootroot00000000000000from . import unittest from shapely import speedups from shapely.geometry import LineString, Polygon class SpeedupsTestCase(unittest.TestCase): def setUp(self): self.assertFalse(speedups._orig) if speedups.available: speedups.enable() self.assertTrue(speedups._orig) def tearDown(self): if speedups.available: self.assertTrue(speedups._orig) speedups.disable() self.assertFalse(speedups._orig) @unittest.skipIf(not speedups.available, 'speedups not available') def test_create_linestring(self): ls = LineString([(0, 0), (1, 0), (1, 2)]) self.assertEqual(ls.length, 3) @unittest.skipIf(not speedups.available, 'speedups not available') def test_create_polygon(self): p = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]) self.assertEqual(p.length, 8) @unittest.skipIf(not speedups.available, 'speedups not available') def test_create_polygon_from_linestring(self): ls = LineString([(0, 0), (2, 0), (2, 2), (0, 2)]) p = Polygon(ls) self.assertEqual(p.length, 8) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(SpeedupsTestCase) Shapely-1.3.0/shapely/tests/test_styles.py000066400000000000000000000010531226057120100206560ustar00rootroot00000000000000from . import unittest from shapely.geometry import CAP_STYLE, JOIN_STYLE class StylesTest(unittest.TestCase): def test_cap(self): self.assertEqual(CAP_STYLE.round, 1) self.assertEqual(CAP_STYLE.flat, 2) self.assertEqual(CAP_STYLE.square, 3) def test_join(self): self.assertEqual(JOIN_STYLE.round, 1) self.assertEqual(JOIN_STYLE.mitre, 2) self.assertEqual(JOIN_STYLE.bevel, 3) def test_suite(): return unittest.TestSuite([ unittest.TestLoader().loadTestsFromTestCase(StylesTest)]) Shapely-1.3.0/shapely/tests/test_transform.py000066400000000000000000000053031226057120100213500ustar00rootroot00000000000000from . import unittest from shapely import geometry from shapely.ops import transform class IdentityTestCase(unittest.TestCase): """New geometry/coordseq method 'xy' makes numpy interop easier""" def func(self, x, y, z=None): return tuple([c for c in [x, y, z] if c]) def test_empty(self): g = geometry.Point() h = transform(self.func, g) self.assertTrue(h.is_empty) def test_point(self): g = geometry.Point(0, 1) h = transform(self.func, g) self.assertEqual(h.geom_type, 'Point') self.assertEqual(list(h.coords), [(0, 1)]) def test_line(self): g = geometry.LineString(((0, 1), (2, 3))) h = transform(self.func, g) self.assertEqual(h.geom_type, 'LineString') self.assertEqual(list(h.coords), [(0, 1), (2, 3)]) def test_polygon(self): g = geometry.Point(0, 1).buffer(1.0) h = transform(self.func, g) self.assertEqual(h.geom_type, 'Polygon') self.assertAlmostEqual(g.area, h.area) def test_multipolygon(self): g = geometry.MultiPoint([(0, 1), (0, 4)]).buffer(1.0) h = transform(self.func, g) self.assertEqual(h.geom_type, 'MultiPolygon') self.assertAlmostEqual(g.area, h.area) class LambdaTestCase(unittest.TestCase): """New geometry/coordseq method 'xy' makes numpy interop easier""" def test_point(self): g = geometry.Point(0, 1) h = transform(lambda x, y, z=None: (x+1.0, y+1.0), g) self.assertEqual(h.geom_type, 'Point') self.assertEqual(list(h.coords), [(1.0, 2.0)]) def test_line(self): g = geometry.LineString(((0, 1), (2, 3))) h = transform(lambda x, y, z=None: (x+1.0, y+1.0), g) self.assertEqual(h.geom_type, 'LineString') self.assertEqual(list(h.coords), [(1.0, 2.0), (3.0, 4.0)]) def test_polygon(self): g = geometry.Point(0, 1).buffer(1.0) h = transform(lambda x, y, z=None: (x+1.0, y+1.0), g) self.assertEqual(h.geom_type, 'Polygon') self.assertAlmostEqual(g.area, h.area) self.assertAlmostEqual(h.centroid.x, 1.0) self.assertAlmostEqual(h.centroid.y, 2.0) def test_multipolygon(self): g = geometry.MultiPoint([(0, 1), (0, 4)]).buffer(1.0) h = transform(lambda x, y, z=None: (x+1.0, y+1.0), g) self.assertEqual(h.geom_type, 'MultiPolygon') self.assertAlmostEqual(g.area, h.area) self.assertAlmostEqual(h.centroid.x, 1.0) self.assertAlmostEqual(h.centroid.y, 3.5) def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(IdentityTestCase), loader.loadTestsFromTestCase(LambdaTestCase)]) Shapely-1.3.0/shapely/tests/test_union.py000066400000000000000000000046261226057120100204740ustar00rootroot00000000000000from . import unittest import random from itertools import islice from shapely.geos import geos_version from shapely.ftools import partial from shapely.geometry import Point, MultiPolygon from shapely.ops import cascaded_union, unary_union def halton(base): """Returns an iterator over an infinite Halton sequence""" def value(index): result = 0.0 f = 1.0 / base i = index while i > 0: result += f * (i % base) i = i // base f = f / base return result i = 1 while i > 0: yield value(i) i += 1 class UnionTestCase(unittest.TestCase): def test_cascaded_union(self): # Use a partial function to make 100 points uniformly distributed # in a 40x40 box centered on 0,0. r = partial(random.uniform, -20.0, 20.0) points = [Point(r(), r()) for i in range(100)] # Buffer the points, producing 100 polygon spots spots = [p.buffer(2.5) for p in points] # Perform a cascaded union of the polygon spots, dissolving them # into a collection of polygon patches u = cascaded_union(spots) self.assertTrue(u.geom_type in ('Polygon', 'MultiPolygon')) def setUp(self): # Instead of random points, use deterministic, pseudo-random Halton # sequences for repeatability sake. self.coords = zip( list(islice(halton(5), 20, 120)), list(islice(halton(7), 20, 120)), ) @unittest.skipIf(geos_version < (3, 3, 0), 'GEOS 3.3.0 required') def test_unary_union(self): patches = [Point(xy).buffer(0.05) for xy in self.coords] u = unary_union(patches) self.assertEqual(u.geom_type, 'MultiPolygon') self.assertAlmostEqual(u.area, 0.71857254056) @unittest.skipIf(geos_version < (3, 3, 0), 'GEOS 3.3.0 required') def test_unary_union_multi(self): # Test of multipart input based on comment by @schwehr at # https://github.com/Toblerity/Shapely/issues/47#issuecomment-21809308 patches = MultiPolygon([Point(xy).buffer(0.05) for xy in self.coords]) self.assertAlmostEqual(unary_union(patches).area, 0.71857254056) self.assertAlmostEqual(unary_union([patches, patches]).area, 0.71857254056) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(UnionTestCase) Shapely-1.3.0/shapely/tests/test_validation.py000066400000000000000000000005341226057120100214700ustar00rootroot00000000000000from . import unittest from shapely.geometry import Point from shapely.validation import explain_validity class ValidationTestCase(unittest.TestCase): def test_valid(self): self.assertEqual(explain_validity(Point(0, 0)), 'Valid Geometry') def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(ValidationTestCase) Shapely-1.3.0/shapely/tests/test_xy.py000066400000000000000000000007611226057120100200000ustar00rootroot00000000000000from . import unittest from shapely import geometry class XYTestCase(unittest.TestCase): """New geometry/coordseq method 'xy' makes numpy interop easier""" def test_arrays(self): x, y = geometry.LineString(((0, 0), (1, 1))).xy self.assertEqual(len(x), 2) self.assertEqual(list(x), [0.0, 1.0]) self.assertEqual(len(y), 2) self.assertEqual(list(y), [0.0, 1.0]) def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(XYTestCase) Shapely-1.3.0/shapely/tests/threading_test.py000066400000000000000000000020101226057120100212720ustar00rootroot00000000000000import threading from binascii import b2a_hex def main(): num_threads = 10 use_threads = True if not use_threads: # Run core code runShapelyBuilding() else: threads = [threading.Thread(target=runShapelyBuilding, name=str(i), args=(i,)) for i in range(num_threads)] for t in threads: t.start() for t in threads: t.join() def runShapelyBuilding(num): print("%s: Running shapely tests on wkb" % num) import shapely.geos print("%s GEOS Handle: %s" % (num, shapely.geos.lgeos.geos_handle)) import shapely.wkt import shapely.wkb p = shapely.wkt.loads("POINT (0 0)") print("%s WKT: %s" % (num, shapely.wkt.dumps(p))) wkb = shapely.wkb.dumps(p) print("%s WKB: %s" % (num, b2a_hex(wkb))) for i in range(10): shapely.wkb.loads(wkb) print("%s GEOS Handle: %s" % (num, shapely.geos.lgeos.geos_handle)) print("Done %s" % num) if __name__ == '__main__': main() Shapely-1.3.0/shapely/tests/valgrind-python.supp000066400000000000000000000073531226057120100217710ustar00rootroot00000000000000# # This is a valgrind suppression file that should be used when using valgrind. # # Here's an example of running valgrind: # # cd python/dist/src # valgrind --tool=memcheck --suppressions=Misc/valgrind-python.supp \ # ./python -E -tt ./Lib/test/regrtest.py -u bsddb,network # # You must edit Objects/obmalloc.c and uncomment Py_USING_MEMORY_DEBUGGER # to use the preferred suppressions with Py_ADDRESS_IN_RANGE. # # If you do not want to recompile Python, you can uncomment # suppressions for PyObject_Free and PyObject_Realloc. # # See Misc/README.valgrind for more information. # all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Addr4 fun:Py_ADDRESS_IN_RANGE } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Value4 fun:Py_ADDRESS_IN_RANGE } { ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value Memcheck:Cond fun:Py_ADDRESS_IN_RANGE } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Addr4 fun:PyObject_Free } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Value4 fun:PyObject_Free } { ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value Memcheck:Cond fun:PyObject_Free } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Addr4 fun:PyObject_Realloc } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Value4 fun:PyObject_Realloc } { ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value Memcheck:Cond fun:PyObject_Realloc } ### ### All the suppressions below are for errors that occur within libraries ### that Python uses. The problems to not appear to be related to Python's ### use of the libraries. ### { GDBM problems, see test_gdbm Memcheck:Param write(buf) fun:write fun:gdbm_open } ### ### These occur from somewhere within the SSL, when running ### test_socket_sll. They are too general to leave on by default. ### ###{ ### somewhere in SSL stuff ### Memcheck:Cond ### fun:memset ###} ###{ ### somewhere in SSL stuff ### Memcheck:Value4 ### fun:memset ###} ### ###{ ### somewhere in SSL stuff ### Memcheck:Cond ### fun:MD5_Update ###} ### ###{ ### somewhere in SSL stuff ### Memcheck:Value4 ### fun:MD5_Update ###} # # All of these problems come from using test_socket_ssl # { from test_socket_ssl Memcheck:Cond fun:BN_bin2bn } { from test_socket_ssl Memcheck:Cond fun:BN_num_bits_word } { from test_socket_ssl Memcheck:Value4 fun:BN_num_bits_word } { from test_socket_ssl Memcheck:Cond fun:BN_mod_exp_mont_word } { from test_socket_ssl Memcheck:Cond fun:BN_mod_exp_mont } { from test_socket_ssl Memcheck:Param write(buf) fun:write obj:/usr/lib/libcrypto.so.0.9.7 } { from test_socket_ssl Memcheck:Cond fun:RSA_verify } { from test_socket_ssl Memcheck:Value4 fun:RSA_verify } { from test_socket_ssl Memcheck:Value4 fun:DES_set_key_unchecked } { from test_socket_ssl Memcheck:Value4 fun:DES_encrypt2 } { from test_socket_ssl Memcheck:Cond obj:/usr/lib/libssl.so.0.9.7 } { from test_socket_ssl Memcheck:Value4 obj:/usr/lib/libssl.so.0.9.7 } { from test_socket_ssl Memcheck:Cond fun:BUF_MEM_grow_clean } { from test_socket_ssl Memcheck:Cond fun:memcpy fun:ssl3_read_bytes } { from test_socket_ssl Memcheck:Cond fun:SHA1_Update } { from test_socket_ssl Memcheck:Value4 fun:SHA1_Update } # some extra lxml specific (?) suppressions.. { Test Memcheck:Param sigaction(act) fun:__libc_sigaction } { ld Memcheck:Cond obj:/lib/ld-2.6.so obj:/lib/ld-2.6.so obj:* } { ld Memcheck:Addr4 obj:/lib/ld-2.6.so obj:/lib/ld-2.6.so obj:* } Shapely-1.3.0/shapely/topology.py000066400000000000000000000042431226057120100170120ustar00rootroot00000000000000""" Intermediaries supporting GEOS topological operations These methods all take Shapely geometries and other Python objects and delegate to GEOS functions via ctypes. These methods return ctypes objects that should be recast by the caller. """ from ctypes import byref, c_double from shapely.geos import TopologicalError, lgeos class Validating(object): def _validate(self, ob, stop_prepared=False): if ob is None or ob._geom is None: raise ValueError("Null geometry supports no operations") if stop_prepared and not hasattr(ob, 'type'): raise ValueError("Prepared geometries cannot be operated on") class Delegating(Validating): def __init__(self, name): self.fn = lgeos.methods[name] class BinaryRealProperty(Delegating): def __call__(self, this, other): self._validate(this) self._validate(other, stop_prepared=True) d = c_double() retval = self.fn(this._geom, other._geom, byref(d)) return d.value class UnaryRealProperty(Delegating): def __call__(self, this): self._validate(this) d = c_double() retval = self.fn(this._geom, byref(d)) return d.value class BinaryTopologicalOp(Delegating): def __call__(self, this, other, *args): self._validate(this) self._validate(other, stop_prepared=True) product = self.fn(this._geom, other._geom, *args) if product is None: if not this.is_valid: raise TopologicalError( "The operation '%s' produced a null geometry. Likely cause is invalidity of the geometry %s" % (self.fn.__name__, repr(this))) elif not other.is_valid: raise TopologicalError( "The operation '%s' produced a null geometry. Likely cause is invalidity of the 'other' geometry %s" % (self.fn.__name__, repr(other))) else: raise TopologicalError( "This operation produced a null geometry. Reason: unknown") return product class UnaryTopologicalOp(Delegating): def __call__(self, this, *args): self._validate(this) return self.fn(this._geom, *args) Shapely-1.3.0/shapely/validation.py000066400000000000000000000002541226057120100172660ustar00rootroot00000000000000# TODO: allow for implementations using other than GEOS import sys from shapely.geos import lgeos def explain_validity(ob): return lgeos.GEOSisValidReason(ob._geom) Shapely-1.3.0/shapely/wkb.py000066400000000000000000000017361226057120100157250ustar00rootroot00000000000000"""Load/dump geometries using the well-known binary (WKB) format """ from shapely import geos # Pickle-like convenience functions def loads(data, hex=False): """Load a geometry from a WKB byte string, or hex-encoded string if ``hex=True``. """ reader = geos.WKBReader(geos.lgeos) if hex: return reader.read_hex(data) else: return reader.read(data) def load(fp, hex=False): """Load a geometry from an open file.""" data = fp.read() return loads(data, hex=hex) def dumps(ob, hex=False, **kw): """Dump a WKB representation of a geometry to a byte string, or a hex-encoded string if ``hex=True``. See available keyword output settings in ``shapely.geos.WKBWriter``.""" writer = geos.WKBWriter(geos.lgeos, **kw) if hex: return writer.write_hex(ob) else: return writer.write(ob) def dump(ob, fp, hex=False, **kw): """Dump a geometry to an open file.""" fp.write(dumps(ob, hex=hex, **kw)) Shapely-1.3.0/shapely/wkt.py000066400000000000000000000012421226057120100157370ustar00rootroot00000000000000"""Load/dump geometries using the well-known text (WKT) format """ from shapely import geos # Pickle-like convenience functions def loads(data): """Load a geometry from a WKT string.""" return geos.WKTReader(geos.lgeos).read(data) def load(fp): """Load a geometry from an open file.""" data = fp.read() return loads(data) def dumps(ob, **kw): """Dump a WKT representation of a geometry to a string. See available keyword output settings in ``shapely.geos.WKTWriter``. """ return geos.WKTWriter(geos.lgeos, **kw).write(ob) def dump(ob, fp, **settings): """Dump a geometry to an open file.""" fp.write(dumps(ob, **settings)) Shapely-1.3.0/tools/000077500000000000000000000000001226057120100142545ustar00rootroot00000000000000Shapely-1.3.0/tools/README.txt000066400000000000000000000000001226057120100157400ustar00rootroot00000000000000