Repository: Toblerity/Shapely (python)

Issue:
ops.substring skips coordinates
## Expected behavior and actual behavior.

Substring appears to skip route points. Blue is the original line; red is the substring.
![image](https://user-images.githubusercontent.com/15164633/74991684-ec0afe80-5403-11ea-8889-fe5f4c2e1a8c.png)

## Steps to reproduce the problem.

```py
from shapely.geometry import shape, LineString
from shapely.ops import substring
import json

# json_str defined at end of issue
line = shape(json.loads(json_str))
orig_pct = .7
dest_pct = .8
cut_line = substring(line, orig_pct, dest_pct, normalized=True)
```
Visualizing `cut_line` shows a straight line as in the above screenshot.

But there are indeed coordinates in between `orig_pct`, `dest_pct`:
```py
dists = [0]
for i in range(2, len(line.coords)):
    length = LineString(line.coords[:i]).length
    dists.append(length / line.length)

len([x for x in dists if x >= orig_pct and x <= dest_pct])
# 51
```
It appears there are 51 coordinates between `.7` and `.8`, so I'm assuming this is a bug, or it's not clear to me why those coordinates are skipped.

## Operating system

Mac OS X 10.15.3

## Shapely version and provenance

1.7.0; installed from pip

```py
json_str = '{"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]]}'
```

Pull request description:
Fix substring for complex geometries
Closes #848

This appears to work correctly with the example provided in #848

![image](https://user-images.githubusercontent.com/15164633/74994805-46a85880-540c-11ea-9205-2911a4b12f9e.png)

I haven't yet been able to come up with a simple test for this. I tried simple stuff like
```json
[0, 0], [2, 0], [0, 0]
```
but `substring(line, 3, 4)` currently works correctly on that. Do you have any suggestions for a simple geometry that currently fails that could be included in a test?

Patch:
diff --git a/.travis.yml b/.travis.yml
index 9f071fe..de4f1a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -70,17 +70,17 @@ matrix:
         NUMPY=0
     - python: "3.8"
       env:
-        GEOSVERSION="3.8.0"
+        GEOSVERSION="3.8.1"
         SPEEDUPS=1
         NUMPY=1
     - python: "3.8"
       env:
-        GEOSVERSION="3.8.0"
+        GEOSVERSION="3.8.1"
         SPEEDUPS=0
         NUMPY=1
     - python: "3.8"
       env:
-        GEOSVERSION="3.8.0"
+        GEOSVERSION="3.8.1"
         SPEEDUPS=0
         NUMPY=0
     - python: "3.8-dev"
diff --git a/CHANGES.txt b/CHANGES.txt
index 7321d93..42f0890 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,14 @@
 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).
+
 1.7.0 (2020-01-28)
 ------------------
 
diff --git a/appveyor.yml b/appveyor.yml
index dd3816d..01b15d2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,7 +3,7 @@ platform: x64
 
 environment:
   global:
-    GEOSVERSION: "3.8.0"
+    GEOSVERSION: "3.8.1"
 
   matrix:
 #    - PYTHON: "C:\\Python27"
@@ -41,6 +41,19 @@ environment:
       ARCH: x64
       COMPILER: msvc2017
 
+
+install:
+  # If there is a newer build queued for the same PR, cancel this one.
+  # The AppVeyor 'rollout builds' option is supposed to serve the same
+  # purpose but it is problematic because it tends to cancel builds pushed
+  # directly to master instead of just PR builds (or the converse).
+  # credits: JuliaLang developers.
+  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
+        https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
+        Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
+          throw "There are newer queued builds for this pull request, failing early." }
+
+
 build_script:
   - set _INITPATH=%PATH%
 
@@ -58,13 +71,13 @@ build_script:
   - set GEOSINSTALL=C:\projects\deps\geos-%GEOSVERSION%-%COMPILER%-%ARCH%
   - set CYTHONPF=C:\\projects\\deps\\geos-%GEOSVERSION%-%COMPILER%-%ARCH%
   - ps: 'Write-Host "Checking GEOS build $env:GEOSINSTALL" -ForegroundColor Magenta'
-  - call c:\projects\shapely\ci\appveyor\build_geos.cmd
+  - call %APPVEYOR_BUILD_FOLDER%\ci\appveyor\build_geos.cmd
 
   # - ps: 'Push-AppveyorArtifact $env:GEOSINSTALL\bin\geos.dll'
   # - ps: 'Push-AppveyorArtifact $env:GEOSINSTALL\bin\geos_c.dll'
 
   - ps: 'Write-Host "Copying and checking geos_c.dll" -ForegroundColor Magenta'
-  - cd C:\projects\shapely
+  - cd %APPVEYOR_BUILD_FOLDER%
   - dir
   - if %ARCH%==x86 ( set CPDIR=DLLs_x86_VC9 )
   - if %ARCH%==x64 ( set CPDIR=DLLs_AMD64_VC9 )
diff --git a/ci/travis/install_geos.sh b/ci/travis/install_geos.sh
index 852224a..424d028 100755
--- a/ci/travis/install_geos.sh
+++ b/ci/travis/install_geos.sh
@@ -13,17 +13,9 @@ function build_geos {
     echo "Building geos-$GEOSVERSION"
     mkdir build
     cd build
-    # disable building tests to speed up compilation
-    if [ "$GEOSVERSION" = "master" ] || dpkg --compare-versions "$GEOSVERSION" "gt" "3.8.0"; then
-        BUILD_TESTING=BUILD_TESTING
-    else
-        # cmake variable used for older GEOS releases
-        BUILD_TESTING=GEOS_ENABLE_TESTS
-        # note that this intentially also catches GEOS "3.8.0"
-        # see https://trac.osgeo.org/geos/ticket/1006
-    fi
-    cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$GEOSINSTVERSION -D$BUILD_TESTING=OFF ..
+    cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$GEOSINSTVERSION ..
     make -j 2
+    ctest .
     make install
 }
 
diff --git a/docs/manual.rst b/docs/manual.rst
index 6f3ba75..c83db2d 100644
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -1008,7 +1008,7 @@ A ring with an undesired orientation can be reversed like this:
 
 .. attribute:: object.is_ring
 
-  Returns ``True`` if the feature is closed. A closed feature's `boundary`
+  Returns ``True`` if the feature is a closed and simple ``LineString``. A closed feature's `boundary`
   coincides with the empty set.
 
 .. code-block:: pycon
@@ -1676,23 +1676,35 @@ linestring feature (right).
   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'. Left and right is determined by following the direction of given 
-  geometric points of the LineString. The resolution of the offset around 
-  each vertex of the object is parameterized as in the buffer method.
+  The `distance` parameter must be a positive float value.
 
-  The join style is for outside corners between line segments. Accepted integer
+  The `side` parameter may be 'left' or 'right'. Left and right are determined
+  by following the direction of the given geometric points of the LineString.
+  Right hand offsets are returned in the reverse direction of the original
+  LineString or LineRing, while left side offsets flow in the same direction.
+
+  The `resolution` of the offset around each vertex of the object is
+  parameterized as in the :meth:`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.
+  Severely mitered corners can be controlled by the `mitre_limit` parameter
+  (spelled in British English, en-gb). The corners of a parallel line will
+  be further from the original than most places with the mitre join style. The
+  ratio of this further distance to the specified `distance` is the miter ratio.
+  Corners with a ratio which exceed the limit will be beveled.
 
-.. note::
+  .. note::
 
-  This method is only available for `LinearRing` and `LineString`  objects.
+    This method may sometimes return a `MultiLineString` where a simple
+    `LineString` was expected; for example, an offset to a slightly
+    curved LineString.
+
+  .. note::
+
+    This method is only available for `LinearRing` and `LineString`  objects.
 
 .. plot:: code/parallel_offset.py
 
@@ -2300,9 +2312,9 @@ The :func:`~shapely.ops.substring` function in `shapely.ops` returns a line segm
     Negative distance values are taken as measured in the reverse
     direction from the end of the geometry. Out-of-range index
     values are handled by clamping them to the valid range of values.
-    
+
     If the start distance equals the end distance, a point is being returned.
-    
+
     If the normalized arg is True, the distance will be interpreted as a
     fraction of the geometry's length.
 
@@ -2409,37 +2421,61 @@ STR-packed R-tree
 
 Shapely provides an interface to the query-only GEOS R-tree packed using the
 Sort-Tile-Recursive algorithm. Pass a list of geometry objects to the STRtree
-constructor to create an R-tree that you can query with another geometric object.
+constructor to create a spatial index that you can query with another geometric
+object. Query-only means that once created, the `STRtree` is immutable. You
+cannot add or remove geometries.
 
 .. class:: strtree.STRtree(geometries)
 
   The `STRtree` constructor takes a sequence of geometric objects.
 
-  These are copied and stored in the R-tree.
+  References to these geometric objects are kept and stored in the R-tree.
 
   `New in version 1.4.0`.
 
-The `query` method on `STRtree` returns a list of all geometries in the tree that
-intersect the provided geometry argument. If you want to match geometries of a
-more specific spatial relationship (eg. crosses, contains, overlaps), consider
-performing the query on the R-tree, followed by a manual search through the
-returned subset using the desired binary predicate.
+  .. method:: strtree.query(goem)
 
-Query-only means that once created, the R-tree is immutable. You cannot 
-add or remove geometries.
+    Returns a list of all geometries in the `strtree` whose extents intersect the
+    extent of `geom`. This means that 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.
 
-.. code-block:: pycon
+    .. code-block:: pycon
 
-  >>> from shapely.geometry import Point
-  >>> from shapely.strtree import STRtree
-  >>> points = [Point(i, i) for i in range(10)]
-  >>> tree = STRtree(points)
-  >>> tree.query(Point(2,2).buffer(0.99))
-  >>> [o.wkt for o in tree.query(Point(2,2).buffer(0.99))]
-  ['POINT (2 2)']
-  >>> [o.wkt for o in tree.query(Point(2,2).buffer(1.0))]
-  ['POINT (1 1)', 'POINT (2 2)', 'POINT (3 3)']
+      >>> from shapely.strtree import STRtree
+      >>> 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)']
+      >>> [o.wkt for o in tree.query(query_geom) if o.intersects(query_geom)]
+      ['POINT (2 2)']
+
+    .. note::
+      To get the original indexes of the query results, create an auxiliary
+      dictionary. But use the geometry `ids` as keys since the shapely geometries
+      themselves are not hashable.
+
+      .. code-block:: pycon
+
+        >>> 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)')]
+
+
+  .. method:: strtree.nearest(geom)
+
+    Returns the nearest geometry in `strtree` to `geom`.
+
+    .. code-block:: pycon
 
+      >>> tree = STRtree([Point(i, i) for i in range(10)])
+      >>> tree.nearest(Point(2.2, 2.2)).wkt
+      'Point (2 2)'
 
 Interoperation
 ==============
diff --git a/environment.yml b/environment.yml
index 1715107..18982df 100644
--- a/environment.yml
+++ b/environment.yml
@@ -1,11 +1,8 @@
 name: _shapely
 channels:
 - defaults
-- conda-forge
 dependencies:
-- python>=3.5
-- cython
-- descartes
-- geos>=3.3
+- python==3.6.*
+- geos==3.8.*
 - matplotlib
-- numpy>=1.9
+- descartes
diff --git a/shapely/__init__.py b/shapely/__init__.py
index 14d9d2f..9c6de1a 100644
--- a/shapely/__init__.py
+++ b/shapely/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "1.7.0"
+__version__ = "1.8dev"
diff --git a/shapely/algorithms/polylabel.py b/shapely/algorithms/polylabel.py
index 08382f1..b4e7f4b 100644
--- a/shapely/algorithms/polylabel.py
+++ b/shapely/algorithms/polylabel.py
@@ -47,7 +47,9 @@ class Cell(object):
         boundary.
         """
         inside = polygon.contains(self.centroid)
-        distance = self.centroid.distance(LineString(polygon.exterior.coords))
+        distance = self.centroid.distance(polygon.exterior)
+        for interior in polygon.interiors:
+            distance = min(distance, self.centroid.distance(interior))
         if inside:
             return distance
         return -distance
diff --git a/shapely/geometry/base.py b/shapely/geometry/base.py
index fcfeabd..ec23a71 100644
--- a/shapely/geometry/base.py
+++ b/shapely/geometry/base.py
@@ -538,56 +538,75 @@ class BaseGeometry(object):
     def buffer(self, distance, resolution=16, quadsegs=None,
                cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.round,
                mitre_limit=5.0, single_sided=False):
-        """Returns a geometry with an envelope at a distance from the object's
-        envelope
+        """Get a geometry that represents all points within a distance
+        of this geometry.
+
+        A positive distance produces a dilation, a negative distance an
+        erosion. A very small or zero distance may sometimes be used to
+        "tidy" a polygon.
 
         Parameters
-        ==========
-        distance: float
-            The distance to buffer around the object. A negative distance has a "shrink" effect.
-            A zero distance may be used to "tidy" a polygon.
-        resolution: int, optional
-            The resolution of the buffer around each vertex of the object.
-        quadsegs: int, optional
-            Sets the number of line segments used to approximate an angle fillet.
-            Note: the use of a `quadsegs` parameter is deprecated and will be gone from
-            the next major release.
-        cap_style: int, optional
-            The styles of caps are: CAP_STYLE.round (1), CAP_STYLE.flat (2), and
-            CAP_STYLE.square (3).
-        join_style: int, optional
-            The styles of joins between offset segments are: JOIN_STYLE.round (1),
-            JOIN_STYLE.mitre (2), and JOIN_STYLE.bevel (3).
-        mitre_limit: float, optional
-            The mitre limit ratio is used for very sharp corners. The mitre ratio
-            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 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.
-        single_side: bool, optional
-            The side used is determined by the sign of the buffer distance:
+        ----------
+        distance : float
+            The distance to buffer around the object.
+        resolution : int, optional
+            The resolution of the buffer around each vertex of the
+            object.
+        quadsegs : int, optional
+            Sets the number of line segments used to approximate an
+            angle fillet.  Note: the use of a `quadsegs` parameter is
+            deprecated and will be gone from the next major release.
+        cap_style : int, optional
+            The styles of caps are: CAP_STYLE.round (1), CAP_STYLE.flat
+            (2), and CAP_STYLE.square (3).
+        join_style : int, optional
+            The styles of joins between offset segments are:
+            JOIN_STYLE.round (1), JOIN_STYLE.mitre (2), and
+            JOIN_STYLE.bevel (3).
+        mitre_limit : float, optional
+            The mitre limit ratio is used for very sharp corners. The
+            mitre ratio 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 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.
+        single_side : bool, optional
+            The side used is determined by the sign of the buffer
+            distance:
+
                 a positive distance indicates the left-hand side
                 a negative distance indicates the right-hand side
-            The single-sided buffer of point geometries is the same as the regular buffer.
-            The End Cap Style for single-sided buffers is always ignored, and forced to the
-            equivalent of CAP_FLAT.
-
-        Example:
-
-          >>> 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=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=CAP_STYLE.square).area
-          4.0
+
+            The single-sided buffer of point geometries is the same as
+            the regular buffer.  The End Cap Style for single-sided
+            buffers is always ignored, and forced to the equivalent of
+            CAP_FLAT.
+
+        Returns
+        -------
+        Geometry
+
+        Notes
+        -----
+        The return value is a strictly two-dimensional geometry. All
+        Z coordinates of the original geometry will be ignored.
+
+        Examples
+        --------
+        >>> 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=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=CAP_STYLE.square).area
+        4.0
+
         """
         if quadsegs is not None:
             warn(
@@ -596,6 +615,7 @@ class BaseGeometry(object):
             res = quadsegs
         else:
             res = resolution
+
         if mitre_limit == 0.0:
             raise ValueError(
                 'Cannot compute offset from zero-length line segment')
diff --git a/shapely/geometry/geo.py b/shapely/geometry/geo.py
index ce2a602..c78d355 100644
--- a/shapely/geometry/geo.py
+++ b/shapely/geometry/geo.py
@@ -1,7 +1,6 @@
 """
 Geometry factories based on the geo interface
 """
-
 from .point import Point, asPoint
 from .linestring import LineString, asLineString
 from .polygon import Polygon, asPolygon
@@ -10,6 +9,47 @@ from .multilinestring import MultiLineString, asMultiLineString
 from .multipolygon import MultiPolygon, MultiPolygonAdapter
 from .collection import GeometryCollection
 
+# numpy is an optional dependency
+try:
+    import numpy as np
+except ImportError:
+    _has_numpy = False
+else:
+    _has_numpy = True
+
+
+def _is_coordinates_empty(coordinates):
+    """Helper to identify if coordinates or subset of coordinates are empty"""
+
+    if coordinates is None:
+        return True
+
+    is_numpy_array = _has_numpy and isinstance(coordinates, np.ndarray)
+    if isinstance(coordinates, (list, tuple)) or is_numpy_array:
+        if len(coordinates) == 0:
+            return True
+        return all(map(_is_coordinates_empty, coordinates))
+    else:
+        return False
+
+
+def _empty_shape_for_no_coordinates(geom_type):
+    """Return empty counterpart for geom_type"""
+    if geom_type == 'point':
+        return Point()
+    elif geom_type == 'multipoint':
+        return MultiPoint()
+    elif geom_type == 'linestring':
+        return LineString()
+    elif geom_type == 'multilinestring':
+        return MultiLineString()
+    elif geom_type == 'polygon':
+        return Polygon()
+    elif geom_type == 'multipolygon':
+        return MultiPolygon()
+    else:
+        raise ValueError("Unknown geometry type: %s" % geom_type)
+
 
 def box(minx, miny, maxx, maxy, ccw=True):
     """Returns a rectangular polygon with configurable normal vector"""
@@ -18,6 +58,7 @@ def box(minx, miny, maxx, maxy, ccw=True):
         coords = coords[::-1]
     return Polygon(coords)
 
+
 def shape(context):
     """Returns a new, independent geometry with coordinates *copied* from the
     context.
@@ -27,15 +68,14 @@ def shape(context):
     else:
         ob = context
     geom_type = ob.get("type").lower()
-    if geom_type == "point":
+    if 'coordinates' in ob and _is_coordinates_empty(ob['coordinates']):
+        return _empty_shape_for_no_coordinates(geom_type)
+    elif geom_type == "point":
         return Point(ob["coordinates"])
     elif geom_type == "linestring":
         return LineString(ob["coordinates"])
     elif geom_type == "polygon":
-        if not ob["coordinates"]:
-            return Polygon()
-        else:
-            return Polygon(ob["coordinates"][0], ob["coordinates"][1:])
+        return Polygon(ob["coordinates"][0], ob["coordinates"][1:])
     elif geom_type == "multipoint":
         return MultiPoint(ob["coordinates"])
     elif geom_type == "multilinestring":
@@ -48,6 +88,7 @@ def shape(context):
     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.
@@ -80,6 +121,7 @@ def asShape(context):
     else:
         raise ValueError("Unknown geometry type: %s" % geom_type)
 
+
 def mapping(ob):
     """Returns a GeoJSON-like mapping"""
     return ob.__geo_interface__
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 eff851f..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:
@@ -573,6 +583,25 @@ def clip_by_rect(geom, xmin, ymin, xmax, ymax):
 
 
 def orient(geom, sign=1.0):
+    """A properly oriented copy of the given geometry.
+
+    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 rings will
+    be oriented counter-clockwise.
+
+    Parameters
+    ----------
+    geom : Geometry
+        The original geometry. May be a Polygon, MultiPolygon, or
+        GeometryCollection.
+    sign : float, optional.
+        The sign of the result's signed area.
+
+    Returns
+    -------
+    Geometry
+
+    """
     if isinstance(geom, BaseMultipartGeometry):
         return geom.__class__(
             list(
diff --git a/shapely/strtree.py b/shapely/strtree.py
index 733b0c4..00dea7c 100644
--- a/shapely/strtree.py
+++ b/shapely/strtree.py
@@ -3,10 +3,12 @@ import ctypes
 
 class STRtree:
     """
-    STRtree is an R-tree that is created using the Sort-Tile-Recursive
-    algorithm. STRtree takes a sequence of geometry objects as initialization
-    parameter. After initialization the query method can be used to make a
-    spatial query over those objects.
+    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))) ]
@@ -48,6 +50,9 @@ 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.
+        """
         if self._n_geoms == 0:
             return []
 


Test patch:
diff --git a/tests/test_collection.py b/tests/test_collection.py
index 1e6f0a6..c87fd7a 100644
--- a/tests/test_collection.py
+++ b/tests/test_collection.py
@@ -63,6 +63,19 @@ class CollectionTestCase(unittest.TestCase):
         self.assertEqual(len(m), 0)
         self.assertEqual(m.geoms, [])
 
+    def test_empty_coordinates(self):
+
+        d = {"type": "GeometryCollection", "geometries": [
+            {"type": "Point", "coordinates": ()},
+            {"type": "LineString", "coordinates": (())}
+        ]}
+
+        # shape
+        m = shape(d)
+        self.assertEqual(m.geom_type, "GeometryCollection")
+        self.assertEqual(len(m), 0)
+        self.assertEqual(m.geoms, [])
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(CollectionTestCase)
diff --git a/tests/test_polylabel.py b/tests/test_polylabel.py
index 84eab12..fd89f66 100644
--- a/tests/test_polylabel.py
+++ b/tests/test_polylabel.py
@@ -70,6 +70,19 @@ class PolylabelTestCase(unittest.TestCase):
         label = polylabel(polygon)
         self.assertEqual(label.coords[:], [(32.722025, -117.201875)])
 
+    def test_polygon_with_hole(self):
+        """
+        Finds pole of inaccessibility for a polygon with a hole
+        https://github.com/Toblerity/Shapely/issues/817
+        """
+        polygon = Polygon(
+            shell=[(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)],
+            holes=[[(2, 2), (6, 2), (6, 6), (2, 6), (2, 2)]],
+        )
+        label = polylabel(polygon, 0.05)
+        self.assertAlmostEqual(label.x, 7.65625)
+        self.assertAlmostEqual(label.y, 7.65625)
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromTestCase(PolylabelTestCase)
diff --git a/tests/test_shape.py b/tests/test_shape.py
new file mode 100644
index 0000000..6b7f3aa
--- /dev/null
+++ b/tests/test_shape.py
@@ -0,0 +1,30 @@
+import pytest
+
+from shapely.geometry import shape, Polygon
+
+
+@pytest.mark.parametrize(
+    "geom",
+    [{"type": "Polygon", "coordinates": None}, {"type": "Polygon", "coordinates": []}],
+)
+def test_polygon_no_coords(geom):
+    assert shape(geom) == Polygon()
+
+
+def test_polygon_empty_np_array():
+    np = pytest.importorskip("numpy")
+    geom = {"type": "Polygon", "coordinates": np.array([])}
+    assert shape(geom) == Polygon()
+
+
+def test_polygon_with_coords_list():
+    geom = {"type": "Polygon", "coordinates": [[[5, 10], [10, 10], [10, 5]]]}
+    obj = shape(geom)
+    assert obj == Polygon([(5, 10), (10, 10), (10, 5)])
+
+
+def test_polygon_not_empty_np_array():
+    np = pytest.importorskip("numpy")
+    geom = {"type": "Polygon", "coordinates": np.array([[[5, 10], [10, 10], [10, 5]]])}
+    obj = shape(geom)
+    assert obj == Polygon([(5, 10), (10, 10), (10, 5)])
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]]}'