Repository: Toblerity/Shapely
Pull request #867 (2020-03-14 20:36:24)

strtree docstrings
Here are some docstrings for the strtree module. They're in the numpydoc style. Even though shapely does not do that yet, @sgillies mentioned that sometime he would like to take them in that direction. I guess my thinking is that it can be done incrementally. You can checkout the auto generated documentation from them here: https://jeremiah-england.github.io/shapely/test-numpydocs/docs/build/index.html 

Let me know if you see any issues. One question that may to come up is that ugly
```rst
.. autoclass:: STRtree
    :members:
```  
in the middle of the module docstring. I'm auto generating the class documentation in the middle of the module docstring so the reference goes at the end. I'm not super attached to that if someone wants me to change it though. 

doctest and rst check out. 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/29357872/badge)](https://coveralls.io/builds/29357872)

Coverage remained the same at 80.988% when pulling **e4516602754f2235cd6f9ff7f06b5662376a63aa on Jeremiah-England:strtree-docstrings** into **d8ff5de8baee6bbbd8465c92197764cdaaa6395a on Toblerity:master**.


Patch:
diff --git a/.travis.yml b/.travis.yml
index de4f1a7..eb2c630 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -111,6 +111,9 @@ install:
   - pip install -v -e .[all]
 
 script:
+  - export LD_LIBRARY_PATH=$HOME/geosinstall/geos-$GEOSVERSION/lib
+  - export DYLD_LIBRARY_PATH=$HOME/geosinstall/geos-$GEOSVERSION/lib
+  - python -c "from shapely.geos import geos_version; print(geos_version)"
   - python -m pytest --cov shapely --cov-report term-missing "${SPEEDUPS_FLAG}"
 
 after_success:
diff --git a/CHANGES.txt b/CHANGES.txt
index 6662cca..42f0890 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,7 @@ Changes
 1.7.1 (TBD)
 -----------
 
+- Fix bug in concatenation of function argtypes (#866).
 - Improved documentation of STRtree usage (#857).
 - Improved handling for empty list or list of lists in GeoJSON coordinates
   (#852).
diff --git a/shapely/__init__.py b/shapely/__init__.py
index ffede83..9c6de1a 100644
--- a/shapely/__init__.py
+++ b/shapely/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "1.7.1dev"
+__version__ = "1.8dev"
diff --git a/shapely/geos.py b/shapely/geos.py
index d5a67d2..5b80c55 100644
--- a/shapely/geos.py
+++ b/shapely/geos.py
@@ -221,7 +221,7 @@ if geos_version >= (3, 1, 0):
                 # finishGEOS.
                 new_func.argtypes = [c_void_p]
             else:
-                new_func.argtypes = [c_void_p] + old_func.argtypes
+                new_func.argtypes = [c_void_p] + list(old_func.argtypes)
             if old_func.errcheck is not None:
                 new_func.errcheck = old_func.errcheck
 
diff --git a/shapely/ops.py b/shapely/ops.py
index 953fcd9..914b16e 100644
--- a/shapely/ops.py
+++ b/shapely/ops.py
@@ -10,6 +10,7 @@ else:
 
 from ctypes import byref, c_void_p, c_double
 
+from shapely.prepared import prep
 from shapely.geos import lgeos
 from shapely.geometry.base import geom_factory, BaseGeometry, BaseMultipartGeometry
 from shapely.geometry import asShape, asLineString, asMultiLineString, Point, MultiPoint,\
@@ -340,6 +341,11 @@ class SplitOp(object):
 
         union = poly.boundary.union(splitter)
 
+        # greatly improves split performance for big geometries with many
+        # holes (the following contains checks) with minimal overhead
+        # for common cases
+        poly = prep(poly)
+
         # some polygonized geometries may be holes, we do not want them
         # that's why we test if the original polygon (poly) contains
         # an inner point of polygonized geometry (pg)
@@ -498,39 +504,43 @@ def substring(geom, start_dist, end_dist, normalized=False):
     """
 
     assert(isinstance(geom, LineString))
-    
+
     # Filter out cases in which to return a point
     if start_dist == end_dist:
         return geom.interpolate(start_dist, normalized)
     elif not normalized and start_dist >= geom.length and end_dist >= geom.length:
         return geom.interpolate(geom.length, normalized)
     elif not normalized and -start_dist >= geom.length and -end_dist >= geom.length:
-        return geom.interpolate(0, normalized)                    
+        return geom.interpolate(0, normalized)
     elif normalized and start_dist >= 1 and end_dist >= 1:
-        return geom.interpolate(1, normalized)  
+        return geom.interpolate(1, normalized)
     elif normalized and -start_dist >= 1 and -end_dist >= 1:
         return geom.interpolate(0, normalized)
 
     start_point = geom.interpolate(start_dist, normalized)
     end_point = geom.interpolate(end_dist, normalized)
-    
+
     min_dist = min(start_dist, end_dist)
     max_dist = max(start_dist, end_dist)
     if normalized:
         min_dist *= geom.length
         max_dist *= geom.length
-    
+
     if start_dist < end_dist:
         vertex_list = [(start_point.x, start_point.y)]
     else:
         vertex_list = [(end_point.x, end_point.y)]
+
     coords = list(geom.coords)
-    for p in coords:
-        pd = geom.project(Point(p))
-        if min_dist < pd < max_dist:
-            vertex_list.append(p)
-        elif pd >= max_dist:
+    current_distance = 0
+    for p1, p2 in zip(coords, coords[1:]):
+        if min_dist < current_distance < max_dist:
+            vertex_list.append(p1)
+        elif current_distance >= max_dist:
             break
+
+        current_distance += ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
+
     if start_dist < end_dist:
         vertex_list.append((end_point.x, end_point.y))
     else:
diff --git a/shapely/strtree.py b/shapely/strtree.py
index 00dea7c..4b2f482 100644
--- a/shapely/strtree.py
+++ b/shapely/strtree.py
@@ -1,35 +1,74 @@
+"""
+strtree
+=======
+
+Index geometry objects for efficient lookup of nearby or
+nearest neighbors. Home of the `STRtree` class which is
+an interface to the query-only GEOS R-tree packed using
+the Sort-Tile-Recursive algorithm [1]_.
+
+.. autoclass:: STRtree
+    :members:
+
+References
+----------
+  .. [1]  Leutenegger, Scott & Lopez, Mario & Edgington, Jeffrey. (1997).
+     "STR: A Simple and Efficient Algorithm for R-Tree Packing." Proc.
+     VLDB Conf. 497-506. 10.1109/ICDE.1997.582015.
+     https://www.cs.odu.edu/~mln/ltrs-pdfs/icase-1997-14.pdf
+"""
+
 from shapely.geos import lgeos
 import ctypes
 
 class STRtree:
     """
-    STRtree is an R-tree spatial index that is created using the
-    Sort-Tile-Recursive algorithm.
-    
-    STRtree takes a sequence of geometry objects as initialization
-    parameter. Once created, it is immutable. The query method can
-    be used to make spatial queries over the objects on the index.
-
-    >>> from shapely.geometry import Polygon
-    >>> polys = [ Polygon(((0, 0), (1, 0), (1, 1))), Polygon(((0, 1), (0, 0), (1, 0))), Polygon(((100, 100), (101, 100), (101, 101))) ]
-    >>> s = STRtree(polys)
+    An STRtree is a spatial index; specifically, an R-tree created
+    using the Sort-Tile-Recursive algorithm.
+
+    Pass a list of geometry objects to the `STRtree` constructor to
+    create a spatial index. References to these indexed objects are
+    kept and stored in the R-tree. You can query them with another
+    geometric object.
+
+    The `STRtree` is query-only, meaning that once created
+    you cannot add or remove geometries.
+
+    *New in version 1.4.0*.
+
+    Parameters
+    ----------
+    geoms : sequence of geometry objects
+        geometry objects to be indexed
+
+    Examples
+    --------
+
+    Creating an index of pologons:
+
+    >>> from shapely.strtree import STRtree
+    >>> from shapely.geometry import Polygon, Point
+    >>>
+    >>> polys = [Polygon(((0, 0), (1, 0), (1, 1))),
+    ...          Polygon(((0, 1), (0, 0), (1, 0))),
+    ...          Polygon(((100, 100), (101, 100), (101, 101)))]
+    >>> tree = STRtree(polys)
     >>> query_geom = Polygon(((-1, -1), (2, 0), (2, 2), (-1, 2)))
-    >>> result = s.query(query_geom)
+    >>> result = tree.query(query_geom)
     >>> polys[0] in result
     True
     >>> polys[1] in result
     True
     >>> polys[2] in result
     False
-    >>> # Test empty tree
-    >>> s = STRtree([])
-    >>> s.query(query_geom)
+
+    Behavior if an `STRtree` is created empty:
+
+    >>> tree = STRtree([])
+    >>> tree.query(Point(0, 0))
     []
-    >>> # Test tree with one object
-    >>> s = STRtree([polys[0]])
-    >>> result = s.query(query_geom)
-    >>> polys[0] in result
-    True
+    >>> print(tree.nearest(Point(0, 0)))
+    None
     """
 
     def __init__(self, geoms):
@@ -50,8 +89,58 @@ class STRtree:
             self._tree_handle = None
 
     def query(self, geom):
-        """Returns a list of objects on the index whose extents
-        intersect the given geometry's extents.
+        """
+        Search the index for geometry objects whose extents
+        intersect the extent of the given object.
+
+        Parameters
+        ----------
+        geom : geometry object
+            The query geometry
+
+        Returns
+        -------
+        list of geometry objects
+            All the geometry objects in the index whose extents
+            intersect the extent of `geom`.
+
+        Note
+        ----
+        A geometry object's "extent" is its the minimum xy bounding
+        rectangle.
+
+        Examples
+        --------
+
+        A buffer around a point can be used to control the extent
+        of the query.
+
+        >>> from shapely.strtree import STRtree
+        >>> from shapely.geometry import Point
+        >>> points = [Point(i, i) for i in range(10)]
+        >>> tree = STRtree(points)
+        >>> query_geom = Point(2,2).buffer(0.99)
+        >>> [o.wkt for o in tree.query(query_geom)]
+        ['POINT (2 2)']
+        >>> query_geom = Point(2, 2).buffer(1.0)
+        >>> [o.wkt for o in tree.query(query_geom)]
+        ['POINT (1 1)', 'POINT (2 2)', 'POINT (3 3)']
+
+        A subsequent search through the returned subset using the
+        desired binary predicate (eg. intersects, crosses, contains,
+        overlaps) may be necessary to further filter the results
+        according to their specific spatial relationships.
+
+        >>> [o.wkt for o in tree.query(query_geom) if o.intersects(query_geom)]
+        ['POINT (2 2)']
+
+        To get the original indices of the returned objects, create an
+        auxiliary dictionary. But use the geometry *ids* as keys since
+        the shapely geometry objects themselves are not hashable.
+
+        >>> index_by_id = dict((id(pt), i) for i, pt in enumerate(points))
+        >>> [(index_by_id[id(pt)], pt.wkt) for pt in tree.query(Point(2,2).buffer(1.0))]
+        [(1, 'POINT (1 1)'), (2, 'POINT (2 2)'), (3, 'POINT (3 3)')]
         """
         if self._n_geoms == 0:
             return []
@@ -67,9 +156,41 @@ class STRtree:
         return result
 
     def nearest(self, geom):
+        """
+        Get the nearest object in the index to a geometry object.
+
+        Parameters
+        ----------
+        geom : geometry object
+            The query geometry
+
+        Returns
+        -------
+        geometry object
+            The nearest geometry object in the index to `geom`.
+
+            Will always only return *one* object even if several
+            in the index are the minimum distance away.
+
+            `None` if the index is empty.
+
+        Examples
+        --------
+        >>> from shapely.strtree import STRtree
+        >>> from shapely.geometry import Point
+        >>> tree = STRtree([Point(i, i) for i in range(10)])
+        >>> tree.nearest(Point(2.2, 2.2)).wkt
+        'POINT (2 2)'
+
+        Will only return one object:
+
+        >>> tree = STRtree ([Point(0, 0), Point(0, 0)])
+        >>> tree.nearest(Point(0, 0)).wkt
+        'POINT (0 0)'
+        """
         if self._n_geoms == 0:
             return None
-        
+
         envelope = geom.envelope
 
         def callback(item1, item2, distance, userdata):
@@ -80,12 +201,12 @@ class STRtree:
                 lgeos.GEOSDistance(geom1._geom, geom2._geom, dist)
                 return 1
             except:
-                return 0 
-        
+                return 0
+
         item = lgeos.GEOSSTRtree_nearest_generic(self._tree_handle, ctypes.py_object(geom), envelope._geom, \
             lgeos.GEOSDistanceCallback(callback), None)
         result = ctypes.cast(item, ctypes.py_object).value
-        
+
         return result
 
 if __name__ == "__main__":


Test patch:
diff --git a/tests/test_substring.py b/tests/test_substring.py
index 8917753..8634594 100644
--- a/tests/test_substring.py
+++ b/tests/test_substring.py
@@ -1,7 +1,9 @@
+import json
+
 from . import unittest
 from shapely.ops import substring
 from shapely.geos import geos_version
-from shapely.geometry import Point, LineString
+from shapely.geometry import Point, LineString, shape
 
 
 class SubstringTestCase(unittest.TestCase):
@@ -10,27 +12,27 @@ class SubstringTestCase(unittest.TestCase):
         self.point = Point(1, 1)
         self.line1 = LineString(([0, 0], [2, 0]))
         self.line2 = LineString(([3, 0], [3, 6], [4.5, 6]))
-  
+
     @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required')
     def test_return_startpoint(self):
         self.assertTrue(substring(self.line1, -500, -600).equals(Point(0, 0)))
         self.assertTrue(substring(self.line1, -500, -500).equals(Point(0, 0)))
         self.assertTrue(substring(self.line1, -1, -1.1, True).equals(Point(0, 0)))
-        self.assertTrue(substring(self.line1, -1.1, -1.1, True).equals(Point(0, 0)))               
+        self.assertTrue(substring(self.line1, -1.1, -1.1, True).equals(Point(0, 0)))
 
     @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required')
     def test_return_endpoint(self):
         self.assertTrue(substring(self.line1, 500, 600).equals(Point(2, 0)))
         self.assertTrue(substring(self.line1, 500, 500).equals(Point(2, 0)))
-        self.assertTrue(substring(self.line1, 1, 1.1, True).equals(Point(2, 0)))   
+        self.assertTrue(substring(self.line1, 1, 1.1, True).equals(Point(2, 0)))
         self.assertTrue(substring(self.line1, 1.1, 1.1, True).equals(Point(2, 0)))
 
     @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required')
     def test_return_midpoint(self):
-        self.assertTrue(substring(self.line1, 0.5, 0.5).equals(Point(0.5, 0)))        
+        self.assertTrue(substring(self.line1, 0.5, 0.5).equals(Point(0.5, 0)))
         self.assertTrue(substring(self.line1, -0.5, -0.5).equals(Point(1.5, 0)))
-        self.assertTrue(substring(self.line1, 0.5, 0.5, True).equals(Point(1, 0)))        
-        self.assertTrue(substring(self.line1, -0.5, -0.5, True).equals(Point(1, 0)))       
+        self.assertTrue(substring(self.line1, 0.5, 0.5, True).equals(Point(1, 0)))
+        self.assertTrue(substring(self.line1, -0.5, -0.5, True).equals(Point(1, 0)))
 
     @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required')
     def test_return_startsubstring(self):
@@ -75,7 +77,15 @@ class SubstringTestCase(unittest.TestCase):
     def test_return_substring_issue682(self):
         assert list(substring(self.line2, 0.1, 0).coords) == [(3.0, 0.1), (3.0, 0.0)]
 
+    @unittest.skipIf(geos_version < (3, 2, 0), 'GEOS 3.2.0 required')
+    def test_return_substring_issue848(self):
+        line = shape(json.loads(data_issue_848))
+        cut_line = substring(line, 0.7, 0.8, normalized=True)
+        assert len(cut_line.coords) == 53
 
 def test_suite():
     loader = unittest.TestLoader()
     return loader.loadTestsFromTestCase(SubstringTestCase)
+
+
+data_issue_848 = '{"type": "LineString", "coordinates": [[-87.71314, 41.96793], [-87.71312, 41.96667], [-87.71311, 41.96643], [-87.7131, 41.96635], [-87.71309, 41.9663], [-87.71303, 41.96621], [-87.71298, 41.96615], [-87.71292, 41.96611], [-87.7128, 41.96607], [-87.71268, 41.96605], [-87.71255, 41.96605], [-87.7124, 41.96605], [-87.71219, 41.96605], [-87.71173, 41.96606], [-87.71108, 41.96607], [-87.71027, 41.96607], [-87.70884, 41.96609], [-87.70763, 41.96611], [-87.70645, 41.96612], [-87.70399, 41.96613], [-87.70267, 41.96614], [-87.70166, 41.96615], [-87.70075, 41.96615], [-87.69954, 41.96615], [-87.69873, 41.96616], [-87.69789, 41.96618], [-87.69675, 41.9662], [-87.69502, 41.96621], [-87.69411, 41.96621], [-87.69145, 41.96623], [-87.69026, 41.96624], [-87.68946, 41.96625], [-87.6885, 41.96625], [-87.68718, 41.96628], [-87.68545, 41.96631], [-87.68399, 41.96632], [-87.68271, 41.96635], [-87.68159, 41.96636], [-87.68034, 41.96638], [-87.67863, 41.96641], [-87.67766, 41.96642], [-87.67741, 41.96641], [-87.67722, 41.9664], [-87.67695, 41.96638], [-87.67665, 41.96632], [-87.67638, 41.96623], [-87.67613, 41.96612], [-87.67589, 41.96596], [-87.6757, 41.96579], [-87.67557, 41.96565], [-87.67544, 41.96547], [-87.67539, 41.96536], [-87.6753, 41.96519], [-87.67524, 41.96503], [-87.67523, 41.96491], [-87.67522, 41.96477], [-87.67521, 41.96457], [-87.6752, 41.96434], [-87.67519, 41.96371], [-87.67517, 41.96175], [-87.67513, 41.96077], [-87.67505, 41.95798], [-87.67501, 41.95666], [-87.67497, 41.95513], [-87.67496, 41.95452], [-87.67491, 41.95392], [-87.67487, 41.95302], [-87.67485, 41.95202], [-87.67484, 41.95101], [-87.67479, 41.94959], [-87.67476, 41.94859], [-87.67474, 41.94703], [-87.67468, 41.94596], [-87.67466, 41.94513], [-87.67463, 41.94494], [-87.67457, 41.94474], [-87.6745, 41.94455], [-87.67442, 41.94438], [-87.6743, 41.94424], [-87.67419, 41.94414], [-87.67405, 41.94404], [-87.67386, 41.94393], [-87.67367, 41.94386], [-87.67348, 41.9438], [-87.67334, 41.94376], [-87.67311, 41.94373], [-87.67289, 41.9437], [-87.67263, 41.94369], [-87.67234, 41.94369], [-87.6715, 41.9437], [-87.67088, 41.94371], [-87.66938, 41.94373], [-87.66749, 41.94377], [-87.66585, 41.94378], [-87.66508, 41.94379], [-87.66361, 41.94381], [-87.6591, 41.94391], [-87.65767, 41.94391], [-87.65608, 41.94393], [-87.6555, 41.94394], [-87.65521, 41.94394], [-87.65503, 41.94393], [-87.65488, 41.9439], [-87.6547, 41.94386], [-87.65454, 41.9438], [-87.65441, 41.94375], [-87.65425, 41.94364], [-87.6541, 41.94351], [-87.654, 41.94342], [-87.65392, 41.94331], [-87.65382, 41.94319], [-87.65375, 41.94306], [-87.65367, 41.94292], [-87.65361, 41.9428], [-87.65355, 41.94269], [-87.65351, 41.94257], [-87.65347, 41.94238], [-87.65345, 41.94218], [-87.65338, 41.93975], [-87.65337, 41.93939], [-87.65337, 41.93893], [-87.65336, 41.93865], [-87.65333, 41.93763], [-87.65331, 41.93717], [-87.65328, 41.93627], [-87.65327, 41.93603], [-87.65323, 41.93532], [-87.65322, 41.93491], [-87.6532, 41.93445], [-87.65314, 41.93312], [-87.65313, 41.93273], [-87.6531, 41.93218], [-87.65307, 41.93151], [-87.65305, 41.9309], [-87.65302, 41.9303], [-87.65299, 41.92951], [-87.65296, 41.9287], [-87.65295, 41.92842], [-87.65294, 41.92768], [-87.65292, 41.92715], [-87.65289, 41.92599], [-87.65288, 41.92537], [-87.65287, 41.92505], [-87.65282, 41.92352], [-87.65276, 41.92172], [-87.65274, 41.92113], [-87.65264, 41.91822], [-87.65264, 41.91808], [-87.65262, 41.91763], [-87.65261, 41.91718], [-87.65255, 41.91563], [-87.6525, 41.91406], [-87.65242, 41.91377], [-87.65234, 41.91362], [-87.65223, 41.91351], [-87.65208, 41.91339], [-87.65183, 41.91322], [-87.65093, 41.9126], [-87.65017, 41.91203], [-87.64985, 41.9118], [-87.64971, 41.91171], [-87.64957, 41.91164], [-87.64948, 41.9116], [-87.64939, 41.91158], [-87.6492, 41.91153], [-87.649, 41.9115], [-87.64883, 41.9115], [-87.64863, 41.9115], [-87.64792, 41.91151], [-87.64781, 41.9115], [-87.64768, 41.91146], [-87.64756, 41.91139], [-87.64745, 41.91122], [-87.6474, 41.91112], [-87.64739, 41.91101], [-87.64738, 41.91086], [-87.64736, 41.91071], [-87.64734, 41.91061], [-87.64728, 41.91051], [-87.64718, 41.91044], [-87.64709, 41.9104], [-87.64697, 41.91036], [-87.64682, 41.91034], [-87.64664, 41.91033], [-87.64646, 41.91033], [-87.6458, 41.91034], [-87.64523, 41.91034], [-87.64348, 41.91036], [-87.64255, 41.91039], [-87.641, 41.9104], [-87.64038, 41.9104], [-87.63975, 41.9104], [-87.6393, 41.91041], [-87.63814, 41.91042], [-87.63798, 41.91041], [-87.63787, 41.91039], [-87.63771, 41.91034], [-87.63757, 41.91027], [-87.63746, 41.91021], [-87.63736, 41.91011], [-87.6373, 41.90999], [-87.63727, 41.90986], [-87.63726, 41.90973], [-87.63725, 41.90951], [-87.63723, 41.90874], [-87.63718, 41.90758], [-87.63713, 41.90607], [-87.63711, 41.90543], [-87.63702, 41.90381], [-87.63702, 41.90368], [-87.63701, 41.90334], [-87.63699, 41.90322], [-87.63694, 41.90312], [-87.63688, 41.90299], [-87.63682, 41.90292], [-87.63671, 41.90279], [-87.63659, 41.90265], [-87.63653, 41.90255], [-87.63649, 41.90245], [-87.63646, 41.90235], [-87.63647, 41.90221], [-87.63647, 41.90211], [-87.6365, 41.90202], [-87.63653, 41.9019], [-87.63659, 41.90177], [-87.63666, 41.90156], [-87.63669, 41.90143], [-87.6367, 41.90131], [-87.6367, 41.90119], [-87.63664, 41.90029], [-87.63664, 41.90008], [-87.63662, 41.89975], [-87.63658, 41.89892], [-87.63657, 41.89867], [-87.63654, 41.89761], [-87.63654, 41.89738], [-87.63649, 41.89726], [-87.63641, 41.89715], [-87.63634, 41.89708], [-87.63623, 41.89699], [-87.63595, 41.89677], [-87.63583, 41.89667], [-87.63574, 41.89654], [-87.63569, 41.89645], [-87.63568, 41.89633], [-87.63565, 41.89542], [-87.63563, 41.89434], [-87.6356, 41.89327], [-87.63558, 41.89261], [-87.63554, 41.89147], [-87.63553, 41.89051], [-87.63548, 41.8903], [-87.6354, 41.89021], [-87.63533, 41.89012], [-87.63524, 41.89007], [-87.63508, 41.89001], [-87.63493, 41.88997], [-87.63475, 41.88994], [-87.63462, 41.88991], [-87.63447, 41.88989], [-87.63436, 41.88984], [-87.63425, 41.88979], [-87.63414, 41.8897], [-87.63407, 41.88962], [-87.63402, 41.88952], [-87.63399, 41.88943], [-87.63397, 41.88897], [-87.63396, 41.88707], [-87.63391, 41.88572], [-87.63389, 41.88441], [-87.63385, 41.8827], [-87.63384, 41.88144], [-87.63378, 41.88014], [-87.63374, 41.87872], [-87.63369, 41.87726], [-87.63369, 41.87706], [-87.63365, 41.87695], [-87.63359, 41.87691], [-87.63353, 41.87688], [-87.63345, 41.87686], [-87.63338, 41.87685], [-87.63263, 41.87685], [-87.63173, 41.87686], [-87.62925, 41.87689], [-87.62821, 41.87691], [-87.62757, 41.87693], [-87.6265, 41.87696], [-87.62635, 41.87696], [-87.62603, 41.87697], [-87.62605, 41.87831], [-87.6261, 41.87951], [-87.62616, 41.88203], [-87.62619, 41.88322], [-87.62622, 41.88443], [-87.62626, 41.88534], [-87.62625, 41.88552], [-87.62625, 41.88557], [-87.62627, 41.88562], [-87.6263, 41.88566], [-87.62635, 41.88569], [-87.62642, 41.88572], [-87.6265, 41.88573], [-87.62655, 41.88574], [-87.62661, 41.88574], [-87.62683, 41.88574], [-87.62784, 41.88574], [-87.62887, 41.88574], [-87.62948, 41.88574], [-87.62982, 41.88574], [-87.62992, 41.88574], [-87.63011, 41.88574], [-87.6302, 41.88574], [-87.63089, 41.88574], [-87.63204, 41.88574], [-87.63285, 41.88573], [-87.63391, 41.88572], [-87.63396, 41.88707], [-87.63397, 41.88897], [-87.63399, 41.88943], [-87.63402, 41.88952], [-87.63407, 41.88962], [-87.63414, 41.8897], [-87.63425, 41.88979], [-87.63436, 41.88984], [-87.63447, 41.88989], [-87.63462, 41.88991], [-87.63475, 41.88994], [-87.63493, 41.88997], [-87.63508, 41.89001], [-87.63524, 41.89007], [-87.63533, 41.89012], [-87.6354, 41.89021], [-87.63548, 41.8903], [-87.63553, 41.89051], [-87.63554, 41.89147], [-87.63558, 41.89261], [-87.6356, 41.89327], [-87.63563, 41.89434], [-87.63565, 41.89542], [-87.63568, 41.89633], [-87.63569, 41.89645], [-87.63574, 41.89654], [-87.63583, 41.89667], [-87.63595, 41.89677], [-87.63623, 41.89699], [-87.63634, 41.89708], [-87.63641, 41.89715], [-87.63649, 41.89726], [-87.63654, 41.89738], [-87.63654, 41.89761], [-87.63657, 41.89867], [-87.63658, 41.89892], [-87.63662, 41.89975], [-87.63664, 41.90008], [-87.63664, 41.90029], [-87.6367, 41.90119], [-87.6367, 41.90131], [-87.63669, 41.90143], [-87.63666, 41.90156], [-87.63659, 41.90177], [-87.63653, 41.9019], [-87.6365, 41.90202], [-87.63647, 41.90211], [-87.63647, 41.90221], [-87.63646, 41.90235], [-87.63649, 41.90245], [-87.63653, 41.90255], [-87.63659, 41.90265], [-87.63671, 41.90279], [-87.63682, 41.90292], [-87.63688, 41.90299], [-87.63694, 41.90312], [-87.63699, 41.90322], [-87.63701, 41.90334], [-87.63702, 41.90368], [-87.63702, 41.90381], [-87.63711, 41.90543], [-87.63713, 41.90607], [-87.63718, 41.90758], [-87.63723, 41.90874], [-87.63725, 41.90951], [-87.63726, 41.90973], [-87.63727, 41.90986], [-87.6373, 41.90999], [-87.63736, 41.91011], [-87.63746, 41.91021], [-87.63757, 41.91027], [-87.63771, 41.91034], [-87.63787, 41.91039], [-87.63798, 41.91041], [-87.63814, 41.91042], [-87.6393, 41.91041], [-87.63975, 41.9104], [-87.64038, 41.9104], [-87.641, 41.9104], [-87.64255, 41.91039], [-87.64348, 41.91036], [-87.64523, 41.91034], [-87.6458, 41.91034], [-87.64646, 41.91033], [-87.64664, 41.91033], [-87.64682, 41.91034], [-87.64697, 41.91036], [-87.64709, 41.9104], [-87.64718, 41.91044], [-87.64728, 41.91051], [-87.64734, 41.91061], [-87.64736, 41.91071], [-87.64738, 41.91086], [-87.64739, 41.91101], [-87.6474, 41.91112], [-87.64745, 41.91122], [-87.64756, 41.91139], [-87.64768, 41.91146], [-87.64781, 41.9115], [-87.64792, 41.91151], [-87.64863, 41.9115], [-87.64883, 41.9115], [-87.649, 41.9115], [-87.6492, 41.91153], [-87.64939, 41.91158], [-87.64948, 41.9116], [-87.64957, 41.91164], [-87.64971, 41.91171], [-87.64985, 41.9118], [-87.65017, 41.91203], [-87.65093, 41.9126], [-87.65183, 41.91322], [-87.65208, 41.91339], [-87.65223, 41.91351], [-87.65234, 41.91362], [-87.65242, 41.91377], [-87.6525, 41.91406], [-87.65255, 41.91563], [-87.65261, 41.91718], [-87.65262, 41.91763], [-87.65264, 41.91808], [-87.65264, 41.91822], [-87.65274, 41.92113], [-87.65276, 41.92172], [-87.65282, 41.92352], [-87.65287, 41.92505], [-87.65288, 41.92537], [-87.65289, 41.92599], [-87.65292, 41.92715], [-87.65294, 41.92768], [-87.65295, 41.92842], [-87.65296, 41.9287], [-87.65299, 41.92951], [-87.65302, 41.9303], [-87.65305, 41.9309], [-87.65307, 41.93151], [-87.6531, 41.93218], [-87.65313, 41.93273], [-87.65314, 41.93312], [-87.6532, 41.93445], [-87.65322, 41.93491], [-87.65323, 41.93532], [-87.65327, 41.93603], [-87.65328, 41.93627], [-87.65331, 41.93717], [-87.65333, 41.93763], [-87.65336, 41.93865], [-87.65337, 41.93893], [-87.65337, 41.93939], [-87.65338, 41.93975], [-87.65345, 41.94218], [-87.65347, 41.94238], [-87.65351, 41.94257], [-87.65355, 41.94269], [-87.65361, 41.9428], [-87.65367, 41.94292], [-87.65375, 41.94306], [-87.65382, 41.94319], [-87.65392, 41.94331], [-87.654, 41.94342], [-87.6541, 41.94351], [-87.65425, 41.94364], [-87.65441, 41.94375], [-87.65454, 41.9438], [-87.6547, 41.94386], [-87.65488, 41.9439], [-87.65503, 41.94393], [-87.65521, 41.94394], [-87.6555, 41.94394], [-87.65608, 41.94393], [-87.65767, 41.94391], [-87.6591, 41.94391], [-87.66361, 41.94381], [-87.66508, 41.94379], [-87.66585, 41.94378], [-87.66749, 41.94377], [-87.66938, 41.94373], [-87.67088, 41.94371], [-87.6715, 41.9437], [-87.67234, 41.94369], [-87.67263, 41.94369], [-87.67289, 41.9437], [-87.67311, 41.94373], [-87.67334, 41.94376], [-87.67348, 41.9438], [-87.67367, 41.94386], [-87.67386, 41.94393], [-87.67405, 41.94404], [-87.67419, 41.94414], [-87.6743, 41.94424], [-87.67442, 41.94438], [-87.6745, 41.94455], [-87.67457, 41.94474], [-87.67463, 41.94494], [-87.67466, 41.94513], [-87.67468, 41.94596], [-87.67474, 41.94703], [-87.67476, 41.94859], [-87.67479, 41.94959], [-87.67484, 41.95101], [-87.67485, 41.95202], [-87.67487, 41.95302], [-87.67491, 41.95392], [-87.67496, 41.95452], [-87.67497, 41.95513], [-87.67501, 41.95666], [-87.67505, 41.95798], [-87.67513, 41.96077], [-87.67517, 41.96175], [-87.67519, 41.96371], [-87.6752, 41.96434], [-87.67521, 41.96457], [-87.67522, 41.96477], [-87.67523, 41.96491], [-87.67524, 41.96503], [-87.6753, 41.96519], [-87.67539, 41.96536], [-87.67544, 41.96547], [-87.67557, 41.96565], [-87.6757, 41.96579], [-87.67589, 41.96596], [-87.67613, 41.96612], [-87.67638, 41.96623], [-87.67665, 41.96632], [-87.67695, 41.96638], [-87.67722, 41.9664], [-87.67741, 41.96641], [-87.67766, 41.96642], [-87.67863, 41.96641], [-87.68034, 41.96638], [-87.68159, 41.96636], [-87.68271, 41.96635], [-87.68399, 41.96632], [-87.68545, 41.96631], [-87.68718, 41.96628], [-87.6885, 41.96625], [-87.68946, 41.96625], [-87.69026, 41.96624], [-87.69145, 41.96623], [-87.69411, 41.96621], [-87.69502, 41.96621], [-87.69675, 41.9662], [-87.69789, 41.96618], [-87.69873, 41.96616], [-87.69954, 41.96615], [-87.70075, 41.96615], [-87.70166, 41.96615], [-87.70267, 41.96614], [-87.70399, 41.96613], [-87.70645, 41.96612], [-87.70763, 41.96611], [-87.70884, 41.96609], [-87.71027, 41.96607], [-87.71108, 41.96607], [-87.71173, 41.96606], [-87.71219, 41.96605], [-87.7124, 41.96605], [-87.71255, 41.96605], [-87.71268, 41.96605], [-87.7128, 41.96607], [-87.71292, 41.96611], [-87.71298, 41.96615], [-87.71303, 41.96621], [-87.71309, 41.9663], [-87.7131, 41.96635], [-87.71311, 41.96643], [-87.71312, 41.96667], [-87.71314, 41.96793]]}'