Converts Oracle SDO_GEOMETRY into spatial objects which implements the __geo_interface__ protocol (GeoJSON like dict). Supports also WKT conversion.
Project description
Library for converting Oracle SDO GEOMETRY into spatial objects which implements the __geo_interface__ protocol (GeoJSON like dict).
Supported geometry types are : Point, Linestring, Polygon, MultiPoint, MultiLinestring, MultiPolygon and Collection.
Converted geometry can be used directly by other packages that support __geo_interface__ like Shapely or GeoPandas.
Kamutils provides a WKT representation (Well Known Text) of the converted geometry.
Kamutils allows geometry conversion for database versions that does not implement SDO_UTIL methods like TO_WKTGEOMETRY or TO_JSON / TO_GEOJSON, or implement them partially.
For example, you may encounter an error 3D geometries are not supported by geometry WKB/WKT generation with method SDO_UTIL.TO_WKTGEOMETRY if you have 3D geometry with X,Y,Z coordinates.
Kamutils includes other miscellaneous utilities.
Table of Contents
Oracle SDO GEOMETRY conversion
- Example 1 : read and convert geometry with convert_from_sdo_geometry()
- Example 2 : interoperability
- Example 3 : conversion to ArcGis geometry
- Classes and fonctions
- Geometry types
- Error codes
- Limitations
License
Kamutils is licensed under CeCILL-B license, a BSD-like french/european license.
License in English : https://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
License in French : https://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.html
Requirements
Kamutils has been tested with :
- Python 3.7
- oracledb 1.1.1
Dependencies : none
Oracle SDO GEOMETRY conversion
Example 1 : read and convert geometry with convert_from_sdo_geometry()
import oracledb
from kamutils.spatial import convert_from_sdo_geometry
oracledb.init_oracle_client()
connection = oracledb.connect(user="Test", password="********", dsn="MY_DSN")
with connection.cursor() as cursor:
cursor.execute("select geometry, ID from MY_BASE.MY_TABLE where ID='l1'")
row = cursor.fetchone()
if row:
spatial_object = convert_from_sdo_geometry(row[0])
if spatial_object.error is None:
print('converted object :')
print(spatial_object)
print('srid :',spatial_object.srid)
print('error :',spatial_object.error)
print('to WKT:')
print(spatial_object.wkt())
else:
print(spatial_object.error)
print('id :',spatial_object.error.id)
print('msg :',spatial_object.error.msg)
output :
converted object :
<SpatialObject - type:LineString srid:None {'type': 'LineString', 'coordinates': [(10.0, 25.0, 0.0), (20.0, 30.0, 0.0), (25.0, 25.0, 0.0), (30.0, 30.0, 0.0)], 'measures': None}>
srid : None
error : None
to WKT:
LINESTRING Z(10.0 25.0 0.0,20.0 30.0 0.0,25.0 25.0 0.0,30.0 30.0 0.0)
output in case of error :
Error 2 : Unknown geometry : SDO_GTYPE = 0
id : 2
msg : Unknown geometry : SDO_GTYPE = 0
Example 2 : interoperability
. . .
spo = convert_from_sdo_geometry(row[0])
import json
print('json dump :')
print(json.dumps(spo.__geo_interface__))
print()
from shapely import geometry
obj=geometry.shape(spo)
print('shapely :')
print(type(obj))
print(obj)
print()
import geojson
obj=geojson.mapping.to_mapping(spo)
print('geojson :')
print(type(obj))
print(obj)
print()
import plpygis
obj=plpygis.Geometry.shape(spo)
print('plpygis :')
print(type(obj))
print(obj)
output :
json dump :
{"type": "LineString", "coordinates": [[10.0, 25.0, 0.0], [20.0, 30.0, 0.0], [25.0, 25.0, 0.0], [30.0, 30.0, 0.0]]}
shapely :
<class 'shapely.geometry.linestring.LineString'>
LINESTRING Z (10 25 0, 20 30 0, 25 25 0, 30 30 0)
geojson :
<class 'dict'>
{'type': 'LineString', 'coordinates': [(10.0, 25.0, 0.0), (20.0, 30.0, 0.0), (25.0, 25.0, 0.0), (30.0, 30.0, 0.0)]}
plpygis :
<class 'plpygis.geometry.LineString'>
01020000800400000000000000000024400000000000003940000000000000000000000000000034400000000000003e4
000000000000000000000000000003940000000000000394000000000000000000000000000003e400000000000003e40
0000000000000000
Example 3 : conversion to ArcGis geometry
import arcpy
. . .
spo = convert_from_sdo_geometry(row[0])
if spo.srid is None:
# supposing you know the actual coordinates system of the source geometry
srid = KNOWN_SRID
else:
srid = spo.srid
arcpy_geom = arcpy.FromWKT(spo.wkt(), arcpy.SpatialReference(srid))
Classes and fonctions
Function convert_from_sdo_geometry
Module : kamutils.spatial
Converts a SDO_GEOMETRY object and returns a SpatialObject instance.
Class SpatialObject
Module : kamutils.spatial
Properties :
type: returns the geometry type (see Geometry types constants)srid: returns the srid (Spatial Reference IDentifier) wich identifies the coordinate system of the geometry. If not defined, returnNoneerror: returns the conversion error if any orNone.
erroris an instance of classError__geo_interface__: returns a GeoJSON dict representation of the geometry. The geometry is not converted to EPSG:4326 regardless of its srid.is_valid: returnsTrueif the geometry is valid, i.e. there is no conversion error,Falsein other cases
Methods :
wkt(): returns the WKT representation of the geometrygeometries(): returns an iterator over all sub-objects in case of a collection (flattening all sub-collections). If theSpatialObjectis not a collection, the iterator returns the object itself.
Class Error
Module : kamutils.exceptions
Attributes :
id: returns the error id (see Error codes)msg: returns the error message
Geometry types
To import Geometry types constants :
from kamutils.spatial import GEOMETRY_TYPE
Constant list :
| Constant name | Value |
|---|---|
| GEOMETRY_TYPE.POINT | 1 |
| GEOMETRY_TYPE.LINESTRING | 2 |
| GEOMETRY_TYPE.POLYGON | 3 |
| GEOMETRY_TYPE.COLLECTION | 4 |
| GEOMETRY_TYPE.MULTIPOINT | 5 |
| GEOMETRY_TYPE.MULTILINESTRING | 6 |
| GEOMETRY_TYPE.MULTIPOLYGON | 7 |
Error codes
To import Error codes constants :
from kamutils.exceptions import ERROR
Constant list :
| Constant name | Value |
|---|---|
| ERROR.EXCEPTION | -1 |
| ERROR.INVALID_SDO_GEOMETRY | 1 |
| ERROR.UNKNOW_TYPE | 2 |
| ERROR.UNSUPPORTED_GEOMETRY | 3 |
| ERROR.INVALID_GEOMETRY | 4 |
Limitations
The following geometry types are partially supported :
| SDO_ETYPE | SDO_INTERPRETATION | Type (*) | Limitation |
|---|---|---|---|
| 1 | 0 | Oriented point | The point is converted but the orientation is ignored |
| 1 | > 1 | Point cluster | Converted to Multipoint |
| 2 | 2 | Line string made up of circular arcs | Circular arcs are transformed into straight line segments connecting the arc's coordinates |
| 4 | > 1 | Compound line string with vertices connected by straight line segments or by circular arcs | Circular arcs are transformed into straight line segments connecting the arc's coordinates |
| 1003 2003 |
2 | Polygon made up of a connected sequence of circular arcs | Circular arcs are transformed into straight line segments connecting the arc's coordinates |
| 1005 2005 |
Compound polygon with some vertices connected by straight line segments and some by circular arcs | Circular arcs are transformed into straight line segments connecting the arc's coordinates |
* From Oracle SDO_GEOMETRY Object Type - Values and Semantics in SDO_ELEM_INFO
The following geometry types are not supported by the current version. They produce an error UNSUPPORTED_GEOMETRY.
| SDO_ETYPE | SDO_INTERPRETATION | Type (*) |
|---|---|---|
| 0 | Geometry types not supported by Oracle Spatial | |
| 2 | 3 | NURBS curve |
| 1003 | 3 | Optimized rectangle |
| 1003 | 4 | Circle |
| 1007 | 1 | Solid |
| 1007 | 3 | Solid of type 'optimized box' |
| 1008 | Multi Solid | |
| 2003 | 3 | Optimized rectangle |
| 2003 | 4 | Circle |
Other utilities
RangeSet
RangeSet creates a set of intervals to categorize values in different levels.
RangeSet support numeric values for ranges.
Example :
from kamutils.analyse import RangeSet
s = RangeSet(1,2,5)
print('RangeSet(1,2,5)','\n')
print("Levels :")
for (level,range) in s:
print(level,':',range.label)
print()
for v in [1, 1.5, 2, 2.1, 12]:
r = s.level(v)
print("Level of {:>4}".format(v),":",r," ",s.label(r))
print()
print("Number of intervals :",len(s))
print("Last level :",s.last_level(),'\n')
# ranges can be defined with just the upper bound of each interval like above
# or with lower and upper bounds defined, or a combination or both
s = RangeSet(1,(2,4),5,6,7,(7,9),11)
print('RangeSet(1,(2,4),5,6,7,(7,9),11)','\n')
print("Levels :")
# RangetSet is iterable. ranges are always enumerated in ascending order
for (level,range) in s:
print(level,':',range.label)
print()
for v in [0, 1.5, 2]:
r = s.level(v)
print("Level of {:>4}".format(v),":",r," ",s.label(r))
print()
print("Number of intervals :",len(s))
print("Last level :",s.last_level(),'\n')
print("Content of this range set :")
print(s)
output :
RangeSet(1,2,5)
Levels :
0 : <= 1
1 : 1]..2]
2 : 2]..5]
3 : > 5
Level of 1 : 0 <= 1
Level of 1.5 : 1 1]..2]
Level of 2 : 1 1]..2]
Level of 2.1 : 2 2]..5]
Level of 12 : 3 > 5
Number of intervals : 4
Last level : 3
RangeSet(1,(2,4),5,6,7,(7,9),11)
Levels :
0 : <= 1
1 : 1]..[2
2 : [2..4]
3 : 4]..5]
4 : 5]..6]
5 : 6]..7]
6 : 7]..9]
7 : 9]..11]
8 : > 11
Level of 0 : 0 <= 1
Level of 1.5 : 1 1]..[2
Level of 2 : 2 [2..4]
Number of intervals : 9
Last level : 8
Content of this range set :
0:{'lower_bound': None, 'ex_lower_bound': False, 'upper_bound': 1, 'ex_upper_bound': False, 'label': '<= 1', 'custom_label': False}
1:{'lower_bound': 1, 'ex_lower_bound': True, 'upper_bound': 2, 'ex_upper_bound': True, 'label': '1]..[2', 'custom_label': False}
2:{'lower_bound': 2, 'ex_lower_bound': False, 'upper_bound': 4, 'ex_upper_bound': False, 'label': '[2..4]', 'custom_label': False}
3:{'lower_bound': 4, 'ex_lower_bound': True, 'upper_bound': 5, 'ex_upper_bound': False, 'label': '4]..5]', 'custom_label': False}
4:{'lower_bound': 5, 'ex_lower_bound': True, 'upper_bound': 6, 'ex_upper_bound': False, 'label': '5]..6]', 'custom_label': False}
5:{'lower_bound': 6, 'ex_lower_bound': True, 'upper_bound': 7, 'ex_upper_bound': False, 'label': '6]..7]', 'custom_label': False}
6:{'lower_bound': 7, 'ex_lower_bound': True, 'upper_bound': 9, 'ex_upper_bound': False, 'label': '7]..9]', 'custom_label': False}
7:{'lower_bound': 9, 'ex_lower_bound': True, 'upper_bound': 11, 'ex_upper_bound': False, 'label': '9]..11]', 'custom_label': False}
8:{'lower_bound': 11, 'ex_lower_bound': True, 'upper_bound': None, 'ex_upper_bound': False, 'label': '> 11', 'custom_label': False}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kamutils-1.1.0.tar.gz.
File metadata
- Download URL: kamutils-1.1.0.tar.gz
- Upload date:
- Size: 30.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.8.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
178247a476642d2ecb72852b989232e8d1a4dde95829594cd2fc189d5a07ae5f
|
|
| MD5 |
382271dcecf14e8b880d1a89f28682c3
|
|
| BLAKE2b-256 |
fdd3c35210ed20bbded27ce4d25b0f81f601451dfcefb850e497b257136ecac4
|
File details
Details for the file kamutils-1.1.0-py3-none-any.whl.
File metadata
- Download URL: kamutils-1.1.0-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.8.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60c6633b02e0ffac7e81b868a5c969bc18372b91abf38298fbcc39a8dd84a613
|
|
| MD5 |
f4c14544617082cd65d0d01b77e3845e
|
|
| BLAKE2b-256 |
77f417fe0497075c8bc302aed361a30517e74750a17e3ff03ead6d9285da144e
|