Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No Shapely geometry can be created from null value #820

Closed
gnthibault opened this issue Jan 21, 2020 · 5 comments
Closed

No Shapely geometry can be created from null value #820

gnthibault opened this issue Jan 21, 2020 · 5 comments

Comments

@gnthibault
Copy link

gnthibault commented Jan 21, 2020

Expected behavior and actual behavior.

Expected behaviour: no error
Actual behaviour:

TopologyException: assigned depths do not match at 882.50000000000011 1241.5
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-69-fe56313cbba3> in <module>
----> 1 line.parallel_offset(distance=2.5, side='left')

~/anaconda3/lib/python3.6/site-packages/shapely/geometry/linestring.py in parallel_offset(self, distance, side, resolution, join_style, mitre_limit)
    144         try:
    145             return geom_factory(self.impl['parallel_offset'](
--> 146                 self, distance, resolution, join_style, mitre_limit, side))
    147         except OSError:
    148             raise TopologicalError()

~/anaconda3/lib/python3.6/site-packages/shapely/geometry/base.py in geom_factory(g, parent)
     74     # Abstract geometry factory for use with topological methods below
     75     if not g:
---> 76         raise ValueError("No Shapely geometry can be created from null value")
     77     ob = BaseGeometry()
     78     geom_type = geometry_type_name(g)

ValueError: No Shapely geometry can be created from null value

Steps to reproduce the problem.

import shapely
line = shapely.geometry.linestring.LineString([(884.0, 1240.0),(883.0, 1239.0),(882.0, 1239.0),(881.0, 1240.0)])                                                                                   
line.parallel_offset(distance=2.5, side='left') 

The weird thing is that the problem does not show if distance=2.499999999999 or distance=2.5000000000001

Operating system

Distributor ID: Ubuntu
Description: Ubuntu 16.04.6 LTS
Release: 16.04
Codename: xenial

Shapely version and provenance

Shapely==1.6.4.post2 installed from PyPI using pip

@sgillies
Copy link
Contributor

@gnthibault would you be willing to try to reproduce the problem using shapely==1.7a3 and shapely==1.7b1? I have a feeling this is an upstream bug that has been fixed.

@Jeremiah-England
Copy link
Contributor

Jeremiah-England commented Oct 6, 2020

I can reproduce this with python 3.8.2, shapely==1.7.1 on a WSL using Ubuntu 20.04.1,

from shapely.geometry import LineString
line = LineString([(884.0, 1240.0),(883.0, 1239.0),(882.0, 1239.0),(881.0, 1240.0)])
print(line.parallel_offset(distance=2.5, side='left').wkt)
TopologyException: assigned depths do not match at 882.50000000000011 1241.5
Traceback (most recent call last):
  File "shapely_890.py", line 3, in <module>
    print(line.parallel_offset(distance=2.5, side='left').to_wkt())
  File "/home/jengland/.local/lib/python3.8/site-packages/shapely/geometry/linestring.py", line 145, in parallel_offset
    return geom_factory(self.impl['parallel_offset'](
  File "/home/jengland/.local/lib/python3.8/site-packages/shapely/geometry/base.py", line 78, in geom_factory
    raise ValueError("No Shapely geometry can be created from null value")
ValueError: No Shapely geometry can be created from null value

It does not happen for 2.5000000000001, but it does for 2.50000000000001.

@Jeremiah-England
Copy link
Contributor

Jeremiah-England commented Nov 24, 2020

I ran into another example of this issue, only it has a different topology exception underneath:

import shapely.wkt
shapely.wkt.loads('LINESTRING (12 20, 60 68, 111 114, 151 159, 210 218)').parallel_offset(3)
TopologyException: found non-noded intersection between LINESTRING (25.1837 28.941, 25.1837 28.941) and LINESTRING (25.1837 28.941, 25.1837 28.941) at 25.183658239422783 28.941017552303521

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-21-df893580dce5> in <module>
----> 1 shapely.wkt.loads('LINESTRING (12 20, 60 68, 111 114, 151 159, 210 218)').parallel_offset(3)

~/.local/lib/python3.8/site-packages/shapely/geometry/linestring.py in parallel_offset(self, distance, side, resolution, join_style, mitre_limit)
    143                 'Cannot compute offset from zero-length line segment')
    144         try:
--> 145             return geom_factory(self.impl['parallel_offset'](
    146                 self, distance, resolution, join_style, mitre_limit, side))
    147         except OSError:

~/.local/lib/python3.8/site-packages/shapely/geometry/base.py in geom_factory(g, parent)
     76     # Abstract geometry factory for use with topological methods below
     77     if not g:
---> 78         raise ValueError("No Shapely geometry can be created from null value")
     79     ob = BaseGeometry()
     80     geom_type = geometry_type_name(g)

ValueError: No Shapely geometry can be created from null value

This is a different issue in GEOS than the one @gnthibault found. I can mine more of them with the following script pretty easily:

Script
# took my machine about 7 minutes to run
from shapely.geometry import LineString
import random

for _ in range(100000):
    x = [i*20 + random.randint(0, 10) for i in range(5)]
    y = [i*20 + random.randint(0, 10) for i in range(5)]
    ls = LineString(zip(x, y))
    try:
        for d in range(10):
            ls.parallel_offset(d)
    except:
        print(ls.wkt)
        print(d)

Out of 100,000 LineStrings, I got 7 of these topology exceptions. However, I got none of OP's.

It appears that OP's has been reported in the geos tracker here: https://trac.osgeo.org/geos/ticket/682 (another assigned depths do not match... error). But I couldn't find any OffsetCurve tickets that referenced a found non-noded intersection error.

@jorisvandenbossche
Copy link
Member

With latest main branch, we correctly raise the GEOS error instead of the confusing "No Shapely geometry can be created from null value" error:

>>> from shapely.geometry import LineString
>>> line = LineString([(884.0, 1240.0),(883.0, 1239.0),(882.0, 1239.0),(881.0, 1240.0)])
>>> line.parallel_offset(distance=2.5, side='left')
...
GEOSException: TopologyException: assigned depths do not match at 882.50000000000011 1241.5

So I think we label / close this as an upstream GEOS issue?

@jorisvandenbossche
Copy link
Member

In addition, with GEOS 3.11, this now works without exception:

>>> from shapely.geometry import LineString
>>> line = LineString([(884.0, 1240.0),(883.0, 1239.0),(882.0, 1239.0),(881.0, 1240.0)])
>>> line.parallel_offset(distance=2.5, side='left')
<LINESTRING (885.768 1238.232, 884.768 1237.232, 884.586 1237.067, 884.389 1...>

GEOS 3.11 will be included in the shapely 2.0 wheels (and with conda you also already use this with shapely 1.8.5).

Closing as fixed upstream in GEOS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants