Пример #1
0
 def _update(self):
     if self.__p__.is_empty:
         self._ndim = None
         self._cseq = None
     else:
         self._ndim = self.__p__._ndim
         self._cseq = lgeos.GEOSGeom_getCoordSeq(self.__p__._geom)
Пример #2
0
 def __setstate__(self, state):
     """WKB doesn't differentiate between LineString and LinearRing so we
     need to move the coordinate sequence into the correct geometry type"""
     super(LinearRing, self).__setstate__(state)
     cs = lgeos.GEOSGeom_getCoordSeq(self.__geom__)
     cs_clone = lgeos.GEOSCoordSeq_clone(cs)
     lgeos.GEOSGeom_destroy(self.__geom__)
     self.__geom__ = lgeos.GEOSGeom_createLinearRing(cs_clone)
Пример #3
0
def geos_geom_from_py(ob, create_func=None):
    """Helper function for geos_*_from_py functions in each geom type.

    If a create_func is specified the coodinate sequence is cloned and a new
    geometry is created with it, otherwise the geometry is cloned directly.
    This behaviour is useful for converting between LineString and LinearRing
    objects.
    """
    if create_func is None:
        geom = lgeos.GEOSGeom_clone(ob._geom)
    else:
        cs = lgeos.GEOSGeom_getCoordSeq(ob._geom)
        cs = lgeos.GEOSCoordSeq_clone(cs)
        geom = create_func(cs)
    N = lgeos.GEOSGeom_getCoordinateDimension(geom)
    return geom, N
Пример #4
0
 def _ctypes(self):
     if not self._ctypes_data:
         temp = c_double()
         n = self._ndim
         m = len(self.geoms)
         array_type = c_double * (m * n)
         data = array_type()
         for i in range(m):
             g = self.geoms[i]._geom
             cs = lgeos.GEOSGeom_getCoordSeq(g)
             lgeos.GEOSCoordSeq_getX(cs, 0, byref(temp))
             data[n*i] = temp.value
             lgeos.GEOSCoordSeq_getY(cs, 0, byref(temp))
             data[n*i+1] = temp.value
             if n == 3: # TODO: use hasz
                 lgeos.GEOSCoordSeq_getZ(cs, 0, byref(temp))
                 data[n*i+2] = temp.value
         self._ctypes_data = data
     return self._ctypes_data
Пример #5
0
def geos_point_from_py(ob, update_geom=None, update_ndim=0):
    """Create a GEOS geom from an object that is a Point, a coordinate sequence
    or that provides the array interface.

    Returns the GEOS geometry and the number of its dimensions.
    """
    if isinstance(ob, Point):
        return geos_geom_from_py(ob)

    # Accept either (x, y) or [(x, y)]
    if not hasattr(ob, '__getitem__'):  # Iterators, e.g. Python 3 zip
        ob = list(ob)

    if isinstance(ob[0], tuple):
        coords = ob[0]
    else:
        coords = ob
    n = len(coords)
    dx = c_double(coords[0])
    dy = c_double(coords[1])
    dz = None
    if n == 3:
        dz = c_double(coords[2])

    if update_geom:
        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
        if n != update_ndim:
            raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: "
                "%d" % update_ndim)
    else:
        cs = lgeos.GEOSCoordSeq_create(1, n)

    # Because of a bug in the GEOS C API, always set X before Y
    lgeos.GEOSCoordSeq_setX(cs, 0, dx)
    lgeos.GEOSCoordSeq_setY(cs, 0, dy)
    if n == 3:
        lgeos.GEOSCoordSeq_setZ(cs, 0, dz)

    if update_geom:
        return None
    else:
        return lgeos.GEOSGeom_createPoint(cs), n
Пример #6
0
 def __call__(self, this):
     self._validate(this)
     env = this.envelope
     if env.geom_type == 'Point':
         return env.bounds
     cs = lgeos.GEOSGeom_getCoordSeq(env.exterior._geom)
     cs_len = c_uint(0)
     lgeos.GEOSCoordSeq_getSize(cs, byref(cs_len))
     minx = 1.e+20
     maxx = -1e+20
     miny = 1.e+20
     maxy = -1e+20
     temp = c_double()
     for i in range(cs_len.value):
         lgeos.GEOSCoordSeq_getX(cs, i, byref(temp))
         x = temp.value
         if x < minx: minx = x
         if x > maxx: maxx = x
         lgeos.GEOSCoordSeq_getY(cs, i, byref(temp))
         y = temp.value
         if y < miny: miny = y
         if y > maxy: maxy = y
     return (minx, miny, maxx, maxy)
Пример #7
0
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
    # If numpy is present, we use numpy.require to ensure that we have a
    # C-continguous array that owns its data. View data will be copied.
    ob = required(ob)
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 2
        m = array['shape'][0]
        n = array['shape'][1]
        if m < 3:
            raise ValueError(
                "A LinearRing must have at least 3 coordinate tuples")
        assert n == 2 or n == 3

        # Make pointer to the coordinate array
        if isinstance(array['data'], tuple):
            # numpy tuple (addr, read-only)
            cp = cast(array['data'][0], POINTER(c_double))
        else:
            cp = array['data']

        # Add closing coordinates to sequence?
        if cp[0] != cp[m * n - n] or cp[1] != cp[m * n - n + 1]:
            M = m + 1
        else:
            M = m

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(M, n)

        # add to coordinate sequence
        for i in xrange(m):
            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, cp[n * i])
            lgeos.GEOSCoordSeq_setY(cs, i, cp[n * i + 1])
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, cp[n * i + 2])

        # Add closing coordinates to sequence?
        if M > m:
            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, M - 1, cp[0])
            lgeos.GEOSCoordSeq_setY(cs, M - 1, cp[1])
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, M - 1, cp[2])

    except AttributeError:
        # Fall back on list
        m = len(ob)
        n = len(ob[0])
        if m < 3:
            raise ValueError(
                "A LinearRing must have at least 3 coordinate tuples")
        assert (n == 2 or n == 3)

        # Add closing coordinates if not provided
        if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
            M = m + 1
        else:
            M = m

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(M, n)

        # add to coordinate sequence
        for i in xrange(m):
            coords = ob[i]
            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
            lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
            if n == 3:
                try:
                    lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
                except IndexError:
                    raise ValueError("Inconsistent coordinate dimensionality")

        # Add closing coordinates to sequence?
        if M > m:
            coords = ob[0]
            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, M - 1, coords[0])
            lgeos.GEOSCoordSeq_setY(cs, M - 1, coords[1])
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, M - 1, coords[2])

    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLinearRing(cs), n
Пример #8
0
def geos_point_from_py(ob, update_geom=None, update_ndim=0):
    """Create a GEOS geom from an object that is a Point, a coordinate sequence
    or that provides the array interface.

    Returns the GEOS geometry and the number of its dimensions.
    """
    if isinstance(ob, Point):
        return geos_geom_from_py(ob)

    # If numpy is present, we use numpy.require to ensure that we have a
    # C-continguous array that owns its data. View data will be copied.
    ob = required(ob)
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 1
        n = array['shape'][0]
        assert n == 2 or n == 3

        dz = None
        da = array['data']
        if isinstance(da, tuple):
            cdata = da[0]
            # If we had numpy, we would do
            # from numpy.ctypeslib import as_ctypes
            # cp = as_ctypes(ob) - check that code?
            cp = cast(cdata, POINTER(c_double))
            dx = c_double(cp[0])
            dy = c_double(cp[1])
            if n == 3:
                dz = c_double(cp[2])
        else:
            dx, dy = da[0:2]
            if n == 3:
                dz = da[2]

    except AttributeError:
        # Fall back on the case of Python sequence data
        # Accept either (x, y) or [(x, y)]
        if not hasattr(ob, '__getitem__'):  # Iterators, e.g. Python 3 zip
            ob = list(ob)

        if isinstance(ob[0], tuple):
            coords = ob[0]
        else:
            coords = ob
        n = len(coords)
        dx = c_double(coords[0])
        dy = c_double(coords[1])
        dz = None
        if n == 3:
            dz = c_double(coords[2])

    if update_geom:
        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
        if n != update_ndim:
            raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: "
                "%d" % update_ndim)
    else:
        cs = lgeos.GEOSCoordSeq_create(1, n)

    # Because of a bug in the GEOS C API, always set X before Y
    lgeos.GEOSCoordSeq_setX(cs, 0, dx)
    lgeos.GEOSCoordSeq_setY(cs, 0, dy)
    if n == 3:
        lgeos.GEOSCoordSeq_setZ(cs, 0, dz)

    if update_geom:
        return None
    else:
        return lgeos.GEOSGeom_createPoint(cs), n
Пример #9
0
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
    # If numpy is present, we use numpy.require to ensure that we have a
    # C-continguous array that owns its data. View data will be copied.
    ob = required(ob)
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 2
        m = array['shape'][0]
        if m < 2:
            raise ValueError(
                "LineStrings must have at least 2 coordinate tuples")
        try:
            n = array['shape'][1]
        except IndexError:
            raise ValueError("Input %s is the wrong shape for a LineString" %
                             str(ob))
        assert n == 2 or n == 3

        # Make pointer to the coordinate array
        if isinstance(array['data'], tuple):
            # numpy tuple (addr, read-only)
            cp = cast(array['data'][0], POINTER(c_double))
        else:
            cp = array['data']

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                    "Wrong coordinate dimensions; this geometry has "
                    "dimensions: %d" % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(m, n)

        # add to coordinate sequence
        for i in range(m):
            dx = c_double(cp[n * i])
            dy = c_double(cp[n * i + 1])
            dz = None
            if n == 3:
                try:
                    dz = c_double(cp[n * i + 2])
                except IndexError:
                    raise ValueError("Inconsistent coordinate dimensionality")

            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, dx)
            lgeos.GEOSCoordSeq_setY(cs, i, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, dz)

    except AttributeError:
        # Fall back on list
        try:
            m = len(ob)
        except TypeError:  # Iterators, e.g. Python 3 zip
            ob = list(ob)
            m = len(ob)

        if m < 2:
            raise ValueError(
                "LineStrings must have at least 2 coordinate tuples")

        def _coords(o):
            if isinstance(o, Point):
                return o.coords[0]
            else:
                return o

        try:
            n = len(_coords(ob[0]))
        except TypeError:
            raise ValueError("Input %s is the wrong shape for a LineString" %
                             str(ob))
        assert n == 2 or n == 3

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                    "Wrong coordinate dimensions; this geometry has "
                    "dimensions: %d" % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(m, n)

        # add to coordinate sequence
        for i in range(m):
            coords = _coords(ob[i])
            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
            lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
            if n == 3:
                try:
                    lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
                except IndexError:
                    raise ValueError("Inconsistent coordinate dimensionality")

    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLineString(cs), n
Пример #10
0
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
    # If a LineString is passed in, clone it and return
    # If a LinearRing is passed in, clone the coord seq and return a
    # LineString.
    #
    # NB: access to coordinates using the array protocol has been moved
    # entirely to the speedups module.

    if isinstance(ob, LineString):
        if type(ob) == LineString:
            return geos_geom_from_py(ob)
        else:
            return geos_geom_from_py(ob, lgeos.GEOSGeom_createLineString)

    try:
        m = len(ob)
    except TypeError:  # Iterators, e.g. Python 3 zip
        ob = list(ob)
        m = len(ob)

    if m == 0:
        return None

    def _coords(o):
        if isinstance(o, Point):
            return o.coords[0]
        else:
            return o

    try:
        n = len(_coords(ob[0]))
    except TypeError:
        raise ValueError("Input %s is the wrong shape for a LineString" %
                         str(ob))
    assert n == 2 or n == 3

    # Create a coordinate sequence
    if update_geom is not None:
        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
        if n != update_ndim:
            raise ValueError("Wrong coordinate dimensions; this geometry has "
                             "dimensions: %d" % update_ndim)
    else:
        cs = lgeos.GEOSCoordSeq_create(m, n)

    # add to coordinate sequence
    for i in range(m):
        coords = _coords(ob[i])
        # Because of a bug in the GEOS C API,
        # always set X before Y
        lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
        lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
        if n == 3:
            try:
                lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
            except IndexError:
                raise ValueError("Inconsistent coordinate dimensionality")

    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLineString(cs), n
Пример #11
0
 def _update(self):
     self._ndim = self.__p__._ndim
     self._cseq = lgeos.GEOSGeom_getCoordSeq(self.__p__._geom)
Пример #12
0
def geos_point_from_py(ob, update_geom=None, update_ndim=0):
    """Create a GEOS geom from an object that is a coordinate sequence
    or that provides the array interface.

    Returns the GEOS geometry and the number of its dimensions.
    """
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 1
        n = array['shape'][0]
        assert n == 2 or n == 3

        dz = None
        da = array['data']
        if type(da) == type((0,)):
            cdata = da[0]
            cp = cast(cdata, POINTER(c_double))
            dx = c_double(cp[0])
            dy = c_double(cp[1])
            if n == 3:
                dz = c_double(cp[2])
                ndim = 3
        else:
            dx, dy = da[0:2]
            if n == 3:
                dz = da[2]
                ndim = 3

    except AttributeError:
        # Fall back on the case of Python sequence data
        # Accept either (x, y) or [(x, y)]
        if type(ob[0]) == type(tuple()):
            coords = ob[0]
        else:
            coords = ob
        n = len(coords)
        dx = c_double(coords[0])
        dy = c_double(coords[1])
        dz = None
        if n == 3:
            dz = c_double(coords[2])

    if update_geom:
        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
        if n != update_ndim:
            raise ValueError(
            "Wrong coordinate dimensions; this geometry has dimensions: %d" \
            % update_ndim)
    else:
        cs = lgeos.GEOSCoordSeq_create(1, n)
    
    # Because of a bug in the GEOS C API, always set X before Y
    lgeos.GEOSCoordSeq_setX(cs, 0, dx)
    lgeos.GEOSCoordSeq_setY(cs, 0, dy)
    if n == 3:
        lgeos.GEOSCoordSeq_setZ(cs, 0, dz)
   
    if update_geom:
        return None
    else:
        return lgeos.GEOSGeom_createPoint(cs), n
Пример #13
0
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
    # If a LinearRing is passed in, clone it and return
    # If a valid LineString is passed in, clone the coord seq and return a
    # LinearRing.
    #
    # NB: access to coordinates using the array protocol has been moved
    # entirely to the speedups module.

    if isinstance(ob, LineString):
        if type(ob) == LinearRing:
            return geos_geom_from_py(ob)
        elif not ob.is_valid:
            raise TopologicalError("An input LineString must be valid.")
        elif ob.is_closed and len(ob.coords) >= 4:
            return geos_geom_from_py(ob, lgeos.GEOSGeom_createLinearRing)
        else:
            ob = list(ob.coords)

    try:
        m = len(ob)
    except TypeError:  # generators
        ob = list(ob)
        m = len(ob)

    if m == 0:
        return None

    def _coords(o):
        if isinstance(o, Point):
            return o.coords[0]
        else:
            return o

    n = len(_coords(ob[0]))
    if m < 3:
        raise ValueError("A LinearRing must have at least 3 coordinate tuples")
    assert (n == 2 or n == 3)

    # Add closing coordinates if not provided
    if (m == 3 or _coords(ob[0])[0] != _coords(ob[-1])[0]
            or _coords(ob[0])[1] != _coords(ob[-1])[1]):
        M = m + 1
    else:
        M = m

    # Create a coordinate sequence
    if update_geom is not None:
        if n != update_ndim:
            raise ValueError(
                "Coordinate dimensions mismatch: target geom has {} dims, "
                "update geom has {} dims".format(n, update_ndim))
        cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
    else:
        cs = lgeos.GEOSCoordSeq_create(M, n)

    # add to coordinate sequence
    for i in range(m):
        coords = _coords(ob[i])
        # Because of a bug in the GEOS C API,
        # always set X before Y
        lgeos.GEOSCoordSeq_setX(cs, i, coords[0])
        lgeos.GEOSCoordSeq_setY(cs, i, coords[1])
        if n == 3:
            try:
                lgeos.GEOSCoordSeq_setZ(cs, i, coords[2])
            except IndexError:
                raise ValueError("Inconsistent coordinate dimensionality")

    # Add closing coordinates to sequence?
    if M > m:
        coords = _coords(ob[0])
        # Because of a bug in the GEOS C API,
        # always set X before Y
        lgeos.GEOSCoordSeq_setX(cs, M - 1, coords[0])
        lgeos.GEOSCoordSeq_setY(cs, M - 1, coords[1])
        if n == 3:
            lgeos.GEOSCoordSeq_setZ(cs, M - 1, coords[2])

    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLinearRing(cs), n
Пример #14
0
def geos_linearring_from_py(ob, update_geom=None, update_ndim=0):
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 2
        m = array['shape'][0]
        n = array['shape'][1]
        if m < 3:
            raise ValueError(
                "A LinearRing must have at least 3 coordinate tuples")
        assert n == 2 or n == 3

        # Make pointer to the coordinate array
        try:
            cp = cast(array['data'][0], POINTER(c_double))
        except ArgumentError:
            cp = array['data']

        # Add closing coordinates to sequence?
        if cp[0] != cp[m * n - n] or cp[1] != cp[m * n - n + 1]:
            M = m + 1
        else:
            M = m

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(M, n)

        # add to coordinate sequence
        for i in xrange(m):
            dx = c_double(cp[n * i])
            dy = c_double(cp[n * i + 1])
            dz = None
            if n == 3:
                dz = c_double(cp[n * i + 2])

            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, dx)
            lgeos.GEOSCoordSeq_setY(cs, i, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, dz)

        # Add closing coordinates to sequence?
        if M > m:
            dx = c_double(cp[0])
            dy = c_double(cp[1])
            dz = None
            if n == 3:
                dz = c_double(cp[2])

            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, M - 1, dx)
            lgeos.GEOSCoordSeq_setY(cs, M - 1, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, M - 1, dz)

    except AttributeError:
        # Fall back on list
        m = len(ob)
        n = len(ob[0])
        if m < 3:
            raise ValueError(
                "A LinearRing must have at least 3 coordinate tuples")
        assert (n == 2 or n == 3)

        # Add closing coordinates if not provided
        if m == 3 or ob[0][0] != ob[-1][0] or ob[0][1] != ob[-1][1]:
            M = m + 1
        else:
            M = m

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(M, n)

        # add to coordinate sequence
        for i in xrange(m):
            coords = ob[i]
            dx = c_double(coords[0])
            dy = c_double(coords[1])
            dz = None
            if n == 3:
                dz = c_double(coords[2])

            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, dx)
            lgeos.GEOSCoordSeq_setY(cs, i, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, dz)

        # Add closing coordinates to sequence?
        if M > m:
            coords = ob[0]
            dx = c_double(coords[0])
            dy = c_double(coords[1])
            dz = None
            if n == 3:
                dz = c_double(coords[2])

            # Because of a bug in the GEOS C API,
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, M - 1, dx)
            lgeos.GEOSCoordSeq_setY(cs, M - 1, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, M - 1, dz)

    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLinearRing(cs), n
Пример #15
0
def geos_linestring_from_py(ob, update_geom=None, update_ndim=0):
    try:
        # From array protocol
        array = ob.__array_interface__
        assert len(array['shape']) == 2
        m = array['shape'][0]
        if m < 2:
            raise ValueError(
                "LineStrings must have at least 2 coordinate tuples")
        try:
            n = array['shape'][1]
        except IndexError:
            raise ValueError(
                "Input %s is the wrong shape for a LineString" % str(ob))
        assert n == 2 or n == 3

        # Make pointer to the coordinate array
        try:
            cp = cast(array['data'][0], POINTER(c_double))
        except ArgumentError:
            cp = array['data']

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(m, n)

        # add to coordinate sequence
        for i in xrange(m):
            dx = c_double(cp[n*i])
            dy = c_double(cp[n*i+1])
            dz = None
            if n == 3:
                try:
                    dz = c_double(cp[n*i+2])
                except IndexError:
                    raise ValueError("Inconsistent coordinate dimensionality")

            # Because of a bug in the GEOS C API, 
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, dx)
            lgeos.GEOSCoordSeq_setY(cs, i, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, dz)

    except AttributeError:
        # Fall back on list
        m = len(ob)
        if m < 2:
            raise ValueError(
                "LineStrings must have at least 2 coordinate tuples")
        try:
            n = len(ob[0])
        except TypeError:
            raise ValueError(
                "Input %s is the wrong shape for a LineString" % str(ob))
        assert n == 2 or n == 3

        # Create a coordinate sequence
        if update_geom is not None:
            cs = lgeos.GEOSGeom_getCoordSeq(update_geom)
            if n != update_ndim:
                raise ValueError(
                "Wrong coordinate dimensions; this geometry has dimensions: %d" \
                % update_ndim)
        else:
            cs = lgeos.GEOSCoordSeq_create(m, n)
        
        # add to coordinate sequence
        for i in xrange(m):
            coords = ob[i]
            dx = c_double(coords[0])
            dy = c_double(coords[1])
            dz = None
            if n == 3:
                try:
                    dz = c_double(coords[2])
                except IndexError:
                    raise ValueError("Inconsistent coordinate dimensionality")
        
            # Because of a bug in the GEOS C API, 
            # always set X before Y
            lgeos.GEOSCoordSeq_setX(cs, i, dx)
            lgeos.GEOSCoordSeq_setY(cs, i, dy)
            if n == 3:
                lgeos.GEOSCoordSeq_setZ(cs, i, dz)
    
    if update_geom is not None:
        return None
    else:
        return lgeos.GEOSGeom_createLineString(cs), n