A Case of Missing Prefixes: ArcGIS ...Geometries

Blog Post created by bixb0012 Champion on Jun 10, 2017

In Semantic Overloading, I touch on one of the main motivations for writing the Tilting at Globes blog:

I believe semantics are important in all aspects of life.  Whether in law, medicine, science, business, information technology, or any other field; having a common language doesn't do much good if there isn't a common understanding of the words that make up the language.  Since languages evolve, maintaining a common understanding of words over time is a continual challenge.


Ideally, a common understanding would mean a word or term has a single meaning, and that singular meaning is known and understood by all that use the word or term.  Unfortunately, reality isn't always ideal, and sometimes the context of the word or term plays a large part in its meaning.  For example, how the term "large-scale" is applied to maps can seem counter intuitive to how it is applied to actions, events, and typical objects.  When one understands that map scale applies to the representation of data in the map, i.e., the ratio of distance in the map to distance on the ground, it helps explain why "large-scale" maps cover small geographic areas instead of large geographic areas.  Sure, a large-scale map could cover a large geographic area if printed on an enormous medium, but I am assuming typical print sizes.


Moving from maps to geometries, I bring up a case of spatial operators in What's Within:  When (Esri != Clementini) = ? .  In the blog post, I point out how the answer to whether one geometry is "within" another geometry can depend on whom you ask, or more accurately, whose definition of "within" is used to answer the question.  Often times, the qualifiers are either incomplete or left off of the answers entirely, and we end up relying on context to fill in the gaps.


In addition to how geometries relate to each other, there are even different contexts for understanding the structure of geometries or geometry types.  Esri's current-generation ArcGIS Geometry Object Model has been around since the release of ArcMap 8.0.  Although the model has evolved some over time, it is not significantly different than when it was released in 1999.  I am not clear on the history of Esri's ST_Geometry storage type, but I know it has been around since at least the ArcGIS 9.x days.  Even operating within a context of Esri geometry types, dropping qualifiers can lead to ambiguity at times.  It can be argued that Esri's REST API represents a 3rd Esri geometry model, but adding that geometry model into this blog post doesn't change the observations and conclusions.


Instead of diving into object model diagrams and reference documentation, let's look at an example of how ArcGIS and ST_Geometry types differ in terms of structure.   Below is an image of, and the code to create, four geometries in a SQLite database using Esri's ST_Geometry type.  Each geometry is attributed with both its ST_Geometry and ArcGIS geometry type.


ArcMap layout with ST_Geometry sample geometries


import arcpy
import os
import sqlite3
from itertools import chain

# Define geometry samples
PCSCode = 3857
geoms = [
    ("poly", "polygon", "POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))"),
    ("multipoly", "multipolygon", ("MULTIPOLYGON(((15 0, 25 0, 25 10, 15 10, 15 0)),"
                                           "((18 13, 18 18, 24 18, 24 13, 18 13)))")),
    ("line", "linestring", "LINESTRING(3 13, 3 18)"),
    ("multiline", "multilinestring", "MULTILINESTRING((6 13, 9 13),(9 14, 9 17))")

# Define SQLite database initialization parameters
sqlitedb = r"D:\tmp\test.sqlite" # path to SQLite DB
st_geometry_dll = r"DatabaseSupport\SQLite\Windows32\stgeometry_sqlite.dll"
st_geometry_dll = os.path.join(arcpy.GetInstallInfo()["InstallDir"],
sql_stmts = [[
        "SELECT load_extension('%s','SDE_SQL_funcs_init');" % st_geometry_dll
        ("CREATE TABLE %s "
           "(id integer primary key autoincrement not null, "
             "stgeom_type text, arcgis_type text);" % table)
        for table, geom_type, WKT in geoms
        ("SELECT AddGeometryColumn "
           "(null, '%s', 'geom', %s, '%s', 2, 'null');" % (table, PCSCode, geom_type))
        for table, geom_type, WKT in geoms
        ("INSERT INTO %s "
           "(geom) VALUES (st_geometry('%s', %s));" % (table, WKT, PCSCode))
        for table, geom_type, WKT in geoms
        ("UPDATE %s "
           "SET stgeom_type = st_geometrytype(geom);" % table)
        for table, geom_type, WKT in geoms

# Create SQLite database and setup tables
arcpy.CreateSQLiteDatabase_management(sqlitedb, "ST_GEOMETRY")
conn = sqlite3.Connection(sqlitedb)
cur = conn.cursor()
for sql in chain(*sql_stmts):
del cur, conn

# Populate ArcGIS geometry type
for table, geom_type, WKT in geoms:
    with arcpy.da.UpdateCursor(
        os.path.join(sqlitedb, table),
        ["shape@", "arcgis_type"]
    ) as cur:
        for shape, _ in cur:
            cur.updateRow([shape, shape.type])
del cur


A few observations:

  • ArcGIS has a single polyline geometry type, ST_Geometry has ST_LINESTRING and ST_MULTILINESTRING types.
  • ArcGIS has a single polygon geometry type, ST_Geometry has ST_POLYGON and ST_MULTIPOLYGON types.
  • Whereas ArcGIS has point and multipoint there is no multi- prefix when working with polyline and polygon.


If the ST_Geometry types look familiar to those who work with open standards, it isn't coincidence.  The documentation on How is ST_Geometry implemented?—Help | ArcGIS Desktop states in several places that ST_Geometry "is a high-performance storage type that includes ISO- and OGC-compliant SQL access to spatial data."  There are several ISO- and OGC- standards when it comes to geometries, and the "SQL access to spatial data" part of the statement is actually quite important as a qualifier.


ISO- and OGC-compliance is fairly broad across various geometry models or storage types, e.g., Microsoft's STGeometry, Oracle's SDO_GEOM,  PostGIS/PostgreSQL ST_Geometry, and others.  The OGC/OpenGIS geometry object model is described in OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture.  Instead of embedding a geometry class hierarchy diagram or listing all of the geometry types, I will share there are LineString and MultiLineString types as well as a Polygon and MultiPolygon types.


All of this leads to a point, and yes I do have a point, that ArcGIS polyline and polygon types are basically multi-types, just with the multi- prefix missing.  Worse yet, most of the ArcGIS documentation abstracts the user even further from the structure of the ArcGIS Geometry Object Model.  Instead of polylines having paths and polygons having rings, which they do, everything just has "parts."  I touch on this problem of "parts" in The Single Multipart:  Polygons With Interior Boundaries:

The problem with the ArcPy Geometry classes, at least one of them, is that Esri replaced multiple, specific geometry components with a single generic one, the "part."  By abstracting geometries and rings with parts, not only did they deviate from geospatial standards and norms, they created the sideshow-worthy multi-part single-part polygon.


Whether it is missing prefixes or the ubiquitous part, understanding the nuances of the implementation and documentation of the ArcGIS Geometry Object Model can help one understand how ArcGIS software, including ArcPy, interacts with other geometry types.