RFC 49:曲线几何

作者:连鲁奥

联系人:spatialys.com上的偶数点rouault

状态:采用,在GDAL 2.0中实现

总结

GDAL 1.X中的当前几何模型使用点、线、多边形及其集合(多点、多线、多多边形和几何集合)。它是根据“OpenGIS简单功能访问第1部分:公共架构”(在其1.1.0版本中)的几何类层次结构建模的。

本RFC涵盖了ISO/IEC 13249第3部分空间(缩写为ISO SQL/MM第3部分)中添加的新几何类型的添加:

  • 字符串:一个圆弧或一系列相连的圆弧,每一个圆弧由三个点描述:圆弧的第一点、中间点和终点

  • 复合曲线:一系列相连的曲线,线串或圆串

  • 曲线多边形:由一个外圈和零个或多个内圈组成的多边形。每个环可以是一个曲线实现:线字符串、循环字符串、复合曲线。

  • 多曲线:曲线的集合(线串、圆串、复合曲线)

  • 多曲面:曲面(多边形、曲线多边形)的集合

本RFC的范围包括:

  • 将新的几何类添加到现有的几何类层次结构中,并使用WKT(已知文本)和WKB(已知二进制)编码的相应导入器和导出器

  • 添加方法以将这些曲线几何体转换为其近似线性版本,并执行反向操作

  • 升级一些可以支持这种几何结构的驱动程序:GML(间接地是NAS、WFS)、PostGIS/PGDump、GeoPackage、SQLite、CSV、VRT。

参考文件

以下文件已用于实施:

核心变化

新的cass层次结构

新的类层次结构如下所示,主要与SQL/MM第3部分保持一致

../../_images/classOGRGeometry.png

唯一的例外是:

  • OGRLinearRing:GDAL 1.X中的这个类是为了向后兼容而保留的,也是因为它仍然存在于sfa1.2.1中,即使SQL/MM第3部分中没有这个类

  • OGRSimpleCurve:这个抽象类是OGR中的一个实现细节,它通过只与OGRLineString中的代码共享,简化了ogrcircurlarstring的实现。

几何图形类型

OGRwkbGeometryType枚举已扩展为以下值:

wkbCircularString = 8,  /**< one or more circular arc segments connected end to end,
                         *   ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbCompoundCurve = 9,   /**< sequence of contiguous curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbCurvePolygon = 10,   /**< planar surface, defined by 1 exterior boundary
                         *   and zero or more interior boundaries, that are curves.
                         *    ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbMultiCurve = 11,     /**< GeometryCollection of Curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbMultiSurface = 12,   /**< GeometryCollection of Surfaces, ISO SQL/MM Part 3. GDAL >= 2.0 */

wkbCircularStringZ = 1008,  /**< wkbCircularString with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbCompoundCurveZ = 1009,   /**< wkbCompoundCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbCurvePolygonZ = 1010,    /**< wkbCurvePolygon with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbMultiCurveZ = 1011,      /**< wkbMultiCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
wkbMultiSurfaceZ = 1012,    /**< wkbMultiSurface with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */

这些代码取自SFA 1.2.1,与PostGIS 2实现一致。注意,ISO SQL/MM第3部分允许wkbCircularString(8或1000001)的替代值:见上述草案中的表15。10000XX范围内的值可能可以追溯到早期的草稿版本。OGR将导入它们,但在导出WKB时将使用sfa1.2.1中的值。

已经考虑过是否值得修改现有2.5D几何图形(wkbPoint25D等)的枚举值,以符合ISO SQL/MM第3部分/SFA 1.2.1的WKB代码,但这样做并没有明显的优势,对OGR API现有用户的影响。

注:Z尺寸的不同表达方式(wkb25DBit位表示“旧”几何类型,而+1000位表示“新”几何类型)的混合不会直接影响几何图形作为WKB的导出。OGRwkbGeometryType的值与WKB geometrytype的值之间没有直接耦合。ogrgometry的exportToWkb()方法使用WKB变量参数来选择所需的WKB变量。

现在明显不赞成使用wkb25DBit值(0x8000000),该值有时用于测试几何类型是否为3D,因为它不适用于新的几何类型。wkbHasZ()和wkbSetZ()已分别添加到测试几何体类型是否为3D,或将几何体类型修改为3D。wkb25DBit常量现在对GDAL中的所有代码都禁用(但用户代码仍然可以访问),并且所有驱动程序都已转换为使用新宏。

新的函数族已用于操作几何类型:

OGRwkbGeometryType CPL_DLL OGR_GT_Flatten( OGRwkbGeometryType eType );
    --> Returns the 2D geometry type corresponding to the passed geometry type.

OGRwkbGeometryType CPL_DLL OGR_GT_SetZ( OGRwkbGeometryType eType );
    --> Returns the 3D geometry type corresponding to the passed geometry type.

OGRwkbGeometryType CPL_DLL OGR_GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM );
    --> Returns a 2D or 3D geometry type depending on parameter.

int                CPL_DLL OGR_GT_HasZ( OGRwkbGeometryType eType );
    --> Return if the geometry type is a 3D geometry type.

int                CPL_DLL OGR_GT_IsSubClassOf( OGRwkbGeometryType eType,
                                                OGRwkbGeometryType eSuperType );
    --> Returns if a type is a subclass of another one

int                CPL_DLL OGR_GT_IsCurve( OGRwkbGeometryType );
    -->  Return if a geometry type is an instance of Curve
        (i.e. wkbLineString, wkbCircularString or wkbCompoundCurve)

int                CPL_DLL OGR_GT_IsSurface( OGRwkbGeometryType );
    -->  Return if a geometry type is an instance of Surface
        (i.e. wkbPolygon or wkbCurvePolygon)

int                CPL_DLL OGR_GT_IsNonLinear( OGRwkbGeometryType );
    --> Return if a geometry type is a non-linear geometry type.
        Such geometry type are wkbCircularString, wkbCompoundCurve, wkbCurvePolygon,
        wkbMultiCurve, wkbMultiSurface and their 3D variant.

OGRwkbGeometryType CPL_DLL OGR_GT_GetCollection( OGRwkbGeometryType eType );
    -->  Returns the collection type that can contain the passed geometry type

OGRwkbGeometryType CPL_DLL OGR_GT_GetCurve( OGRwkbGeometryType eType );
    --> Returns the curve geometry type that can contain the passed geometry type.
        Handled conversions are : wkbPolygon -> wkbCurvePolygon,
        wkbLineString->wkbCompoundCurve, wkbMultiPolygon->wkbMultiSurface
        and wkbMultiLineString->wkbMultiCurve.

OGRwkbGeometryType CPL_DLL OGR_GT_GetLinear( OGRwkbGeometryType eType );
    --> Returns the non-curve geometry type that can contain the passed geometry type
        Handled conversions are : wkbCurvePolygon -> wkbPolygon,
        wkbCircularString->wkbLineString, wkbCompoundCurve->wkbLineString,
        wkbMultiSurface->wkbMultiPolygon and wkbMultiCurve->wkbMultiLineString.

现有的wkbFlatten()是OGR_GT_Flatten()的别名,新的wkbHasZ()是OGR_GT_HasZ()的别名,wkbSetZ()是OGR_GT_SetZ()的别名。

新方法

  • 在几何测量课上:

    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;

/**
 * \brief Returns if this geometry is or has curve geometry.
 *
 * Returns if a geometry is, contains or may contain a CIRCULARSTRING, COMPOUNDCURVE,
 * CURVEPOLYGON, MULTICURVE or MULTISURFACE.
 *
 * If bLookForNonLinear is set to TRUE, it will be actually looked if the
 * geometry or its subgeometries are or contain a non-linear geometry in them. In which
 * case, if the method returns TRUE, it means that getLinearGeometry() would
 * return an approximate version of the geometry. Otherwise, getLinearGeometry()
 * would do a conversion, but with just converting container type, like
 * COMPOUNDCURVE -> LINESTRING, MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON,
 * resulting in a "loss-less" conversion.
 */

    virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;

/**
 * \brief Return curve version of this geometry.
 *
 * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
 * MULTICURVE or MULTISURFACE in it, by de-approximating curve geometries.
 *
 * If the geometry has no curve portion, the returned geometry will be a clone
 * of it.
 *
 * The ownership of the returned geometry belongs to the caller.
 *
 * The reverse method is OGRGeometry::getLinearGeometry().
 *
 * This function is the same as C function OGR_G_GetCurveGeometry().
 *
 * @param papszOptions options as a null-terminated list of strings.
 *                     Unused for now. Must be set to NULL.
 */

    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
                                             const char* const* papszOptions = NULL) const;


/**
 * \brief Return, possibly approximate, non-curve version of this geometry.
 *
 * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
 * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
 *
 * The ownership of the returned geometry belongs to the caller.
 *
 * The reverse method is OGRGeometry::getCurveGeometry().
 *
 * This method is the same as the C function OGR_G_GetLinearGeometry().
 *
 * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
 * arc, zero to use the default setting.
 * @param papszOptions options as a null-terminated list of strings.
 *                     See OGRGeometryFactory::curveToLineString() for valid options.
 */
  • 在ogergometryFactory类中:

static OGRLineString* curveToLineString(
                                            double x0, double y0, double z0,
                                            double x1, double y1, double z1,
                                            double x2, double y2, double z2,
                                            int bHasZ,
                                            double dfMaxAngleStepSizeDegrees,
                                            const char*const* papszOptions )
/**
 * \brief Converts an arc circle into an approximate line string
 *
 * The arc circle is defined by a first point, an intermediate point and a
 * final point.
 *
 * The provided dfMaxAngleStepSizeDegrees is a hint. The discretization
 * algorithm may pick a slightly different value.
 *
 * So as to avoid gaps when rendering curve polygons that share common arcs,
 * this method is guaranteed to return a line with reversed vertex if called
 * with inverted first and final point, and identical intermediate point.
 *
 * @param x0 x of first point
 * @param y0 y of first point
 * @param z0 z of first point
 * @param x1 x of intermediate point
 * @param y1 y of intermediate point
 * @param z1 z of intermediate point
 * @param x2 x of final point
 * @param y2 y of final point
 * @param z2 z of final point
 * @param bHasZ TRUE if z must be taken into account
 * @param dfMaxAngleStepSizeDegrees  the largest step in degrees along the
 * arc, zero to use the default setting.
 * @param papszOptions options as a null-terminated list of strings or NULL.
 * Recognized options:
 * <ul>
 * <li>ADD_INTERMEDIATE_POINT=STEALTH/YES/NO (Default to STEALTH).
 *         Determine if and how the intermediate point must be output in the linestring.
 *         If set to STEALTH, no explicit intermediate point is added but its
 *         properties are encoded in low significant bits of intermediate points
 *         and OGRGeometryFactory::curveFromLineString() can decode them.
 *         This is the best compromise for round-tripping in OGR and better results
 *         with PostGIS <a href="http://postgis.org/docs/ST_LineToCurve.html">ST_LineToCurve()</a>
 *         If set to YES, the intermediate point is explicitly added to the linestring.
 *         If set to NO, the intermediate point is not explicitly added.
 * </li>
 * </ul>
 */

--> This method is used by OGRCircularString::getLinearGeometry()

OGRCurve* OGRGeometryFactory::curveFromLineString(const OGRLineString* poLS,
                                                  CPL_UNUSED const char*const* papszOptions)

/**
 * \brief Try to convert a linestring approximating curves into a curve.
 *
 * This method can return a COMPOUNDCURVE, a CIRCULARSTRING or a LINESTRING.
 *
 * This method is the reverse of curveFromLineString().
 *
 * @param poLS handle to the geometry to convert.
 * @param papszOptions options as a null-terminated list of strings.
 *                     Unused for now. Must be set to NULL.
 */

--> This method is used by OGRLineString::getCurveGeometry()


OGRGeometry* OGRGeometryFactory::forceTo( OGRGeometry* poGeom,
                                          OGRwkbGeometryType eTargetType,
                                          const char*const* papszOptions )
 *
 * Tries to force the provided geometry to the specified geometry type.
 *
 * It can promote 'single' geometry type to their corresponding collection type
 * (see OGR_GT_GetCollection()) or the reverse. non-linear geometry type to
 * their corresponding linear geometry type (see OGR_GT_GetLinear()), by
 * possibly approximating circular arcs they may contain.
 * Regarding conversion from linear geometry types to curve geometry types, only
 * "wrapping" will be done. No attempt to retrieve potential circular arcs by
 * de-approximating stroking will be done. For that, OGRGeometry::getCurveGeometry()
 * can be used.
 *
 * The passed in geometry is consumed and a new one returned (or potentially the same one).
 *
 * @param poGeom the input geometry - ownership is passed to the method.
 * @param eTargetType target output geometry type.
 * @param papszOptions options as a null-terminated list of strings or NULL.
 * @return new geometry.
 */

--> This method generalizes the existing forceToPolygon(), forceToLineString(),
forceToMultiPolygon(), forceToMultiLineString(), that have been extended to
deal with the new geometry types. forceTo() and actually calls them if they
can be used for the requested conversion, and also deal with conversion between
linear and non-linear geometry types.

现有测量方法的实施

由于GEOS目前不支持曲线几何,因此所有与GEOS相关的操作,返回布尔值(如Intersects())的操作,或返回新几何体(如Intersection())的操作,当GEOS返回一个几何图形,并且其中一个输入参数是非线性几何图形时,首先将非线性几何图形转换为它们的线性近似值(如果GEOS在未来支持曲线几何图形,则可能会重新讨论此问题),执行反向操作以尝试检索尽可能多的曲线几何图形。当然,结果一般不会十全十美,但总比什么都没有要好。

两个相邻半圆的并集的简单示例:

g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0,1 1,2 0),(2 0,0 0)))')
g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0,1 -1,2 0),(2 0,0 0)))')
g3 = g1.Union(g2)
assert g3.ExportToWkt() == 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,1 -1,0 0))'

或者对缓冲区操作的结果显式使用getCurvegeMetry():

g1 = ogr.CreateGeometryFromWkt('POINT(1 2)')
g2 = g1.Buffer(0.5)
g3 = g2.GetCurveGeometry()
assert g3.ExportToWkt() != 'CURVEPOLYGON (CIRCULARSTRING (1.5 2.0,0.5 2.0,1.5 2.0))'

对ogrcrcularstring(因此ogrccompoundcurve)的Length()操作使用圆几何来计算精确的长度,而不返回线性近似。OGRCurvePolygon上的Area()操作通常需要转到线性近似。在整圆或凸曲线多边形上操作时,会进行优化以避免出现这种情况(通过计算包含在描述的圆形部分中的所有顶点形成的多边形的面积,并添加 circular segments

C API更改

折旧:

  • wkb25DBit仍然存在,但由于与新的几何类型不兼容,因此已弃用。改用wkbFlatten()、wkbHasZ()、wkbSetZ()宏

添加物:

  • OGR_GT_xxxx(用于几何类型):如上所述

  • OGRErr OGR_G_ExportToIsoWkb(OGRGeometryH,OGRwkbByteOrder,unsigned char*):将几何图形导出为符合ISO SQL/MM第3部分的WKB。

  • OGRErr OGR_G_出口到sowkt(ogergometryh,char * * ):将几何图形导出为符合ISO SQL/MM第3部分的WKT,即2.5D几何图形名称的后缀为“Z”,例如“点Z(1 2 3)”。

  • ogrgometryh OGR_G_Value(ogrgometryh,double dfDistance):现有ogrgometry的映射::Value()

  • int OGR_G_HasCurveGeometry(ogrgometryh,int bLookForNonLinear):ogrgometry的映射::HasCurveGeometry()

  • 几何计量学 ** papszOptions):几何映射::hasCurveGeometry()

  • 曲线测量法 ** papszOptions):几何映射::hasCurveGeometry()

  • void ogrsetnlineargetiesenabledflag(int bFlag):在向后兼容性部分讨论

  • int OGRGetNonLinearGeometriesEnabledFlag():在向后兼容性部分讨论

驱动因素的变化

  • GML几何导入程序:Arc、Arc string、arcbybybublge、ArcByCenterPoint、Circle和CircleByCenterPoints GML元素将作为环形字符串OGR几何返回。如果它们包含在其他GML元素中,例如CurveComposite、MultiCurve、Surface,则还将返回相应的非线性OGR几何图形。当读取由曲面、多曲面、曲线、多曲线组成的几何图形时,应尽量返回线性类型的OGR几何类,即OGRCurvePolygon、ogrcompundcurve等。。。仅当几何图形中有循环字符串时才返回。

  • GML几何导出器:当传递包含圆字符串的几何体时,可以生成ArcString和Circle GML元素。

  • GML驱动程序:可以读取/写入所有新的几何类型。读取GML3应用程序架构时,几何字段的声明(如CurvePropertyType、SurfacePropertyType、MultiCurvePropertyType或MultiSurfacePropertyType)也将被解释为潜在的非线性几何,相应的OGR几何类型将用于层几何类型和特征的几何也将遵循该图层几何图形类型。这会影响WFS驱动程序。

  • NAS驱动程序:可以返回新的几何体类型。只有当NAS文件包含圆弧时,NAS图层才会使用新的几何图形类型。

  • PG/PostGIS:可以读取/写入PostGIS 2.X和PostGIS 1.X的所有新几何类型。对于PostGIS 1.X兼容性,必须在importFromWkb()/exportToWkb()中进行特殊处理,以处理PostGIS 1.X用于曲线多边形、多曲线和多曲面的非标准代码。这是通过将wkbVariantPostGIS1值添加到这些方法使用的OGRwkbVariant枚举来完成的。

  • PGDump:可以写入所有新的几何体类型。以上有关版本之间差异的说明使得正确指定POSTGIS_版本数据集创建选项非常重要。

  • GeoPackage:可以读取/写入所有新的几何体类型。注意:这不在GeoPackage规范的核心中,但它仍然是一个注册的扩展。

  • SQLite:可以读取/写入非Spatialite数据库的所有新几何类型,因为Spatialite不支持曲线几何类型。但是,尝试(很好的黑客)这样,SQLite SQL方言仍然可以使用。基本上,当将OGR几何体转换为空间几何体时,如果它是曲线几何体类型之一,则生成的blob将首先包含线性几何体的空间兼容blob,然后包含曲线几何体的WKB。如果使用 ST_ 例如,函数将忽略后面的函数。从sqlite读取blob时,如果添加的曲线几何图形WKB仍然存在,则将使用它。否则将使用空间几何体blob。因此,SELECT语句只选择几何列而不对其执行任何操作应该会保留曲线几何。

  • MEM:可以读/写所有新的几何类型。

  • CSV:可以读取/写入所有新的几何类型。

  • VRT:声明为与所有新的几何体类型兼容。实际性能将取决于VRT所包装的底层。

公用设施的变化

  • ogr2ogr:-nlt选项支持新的几何体名称(循环字符串等)。”-nlt CONVERT_TO_LINEAR“还可用于要求将曲线几何图形转换为其线性近似值(用于此操作的是forceTo(xxx,OGR_GT_GetLinear()))。注意:这并不是绝对必要的,因为所有的驱动程序都应该能够使用后向兼容性中描述的兼容性机制处理非线性几何体类型。但这可能有助于生成具有线性几何类型的PostGIS表或GeoPackage数据库,即使源包含非线性几何。”-“nlt CONVERT_TO_LINEAR”可以与“-nlt PROMOTE_TO_MULTI”结合使用。

SWIG绑定的更改

增加:

  • 新的几何类型为ogr.wkbXXXXX

  • ogr.ForceTo()

  • Geometry.ExportToIsoWkt()

  • Geometry.ExportToIsoWkb()

  • Geometry.HasCurveGeometry(int bLookForCircular=FALSE)

  • Geometry.GetLinearGeometry(双dfMaxAngleStepSizeGrees=0.0,字符 ** 选项=空)

  • 几何学.GetCurveGeometry(char ** 选项=空)

  • ogr.SetNonLinearGeometriesEnabledFlag(int bFlag)

  • ogr.GetNonLinearGeometriesEnabledFlag()

  • ogr.GT_xxxxx函数

使用ogr.wkb25DBit将发出弃用警告

向后兼容性

关于使用GDAL的代码

许多应用程序将无法正确处理某些驱动程序现在可能返回的新几何体类型。如果不想测试几何类型并显式调用转换函数,可以调用ogrsetOnlineArgeMetriesEnabledFlag(FALSE)(默认值为TRUE,即可以返回非线性几何)。在这种情况下,通过使用OGRu Gu ForceTo()进行线性近似,它们将被转换为最接近的线性几何体。

此标志仅对SWIG绑定中的OGR_F_GetGeometryRef()、OGR_getgeomefieldref()、OGR_L_GetGeomType()、OGR_GFld_GetType()和OGR_FD_GetGeomType()C API以及相应方法有影响。

类库通常应该 not 使用该方法,因为这可能会干扰其他库或应用程序。

注意,它确实 not 影响C++ API的行为。在C++级别尝试这样做是危险的/复杂的,因为它可能会混淆驱动程序,因为它们可能调用GeGeMoType()。

关于OGR驱动程序

可以处理新几何类型的驱动程序应该声明新的数据集级ODsCCurveGeometries和层级OLCCurveGeometries功能。驱动程序实现的虚拟方法CreateFeature()和SetFeature()已重命名为ICreateFeature()和ISetFeature()。OGRLayer现在有一个非虚拟CreateFeature()和SetFeature()来检查层是否具有曲线几何功能。如果没有,并且传递的特征具有非线性几何体,则在调用驱动程序ICreateFeature()/ISetFeature()方法之前,这些几何体将透明地转换为其线性近似值。类似地,如果需要,数据源级别的CreateLayer()方法将把传递的几何体类型转换为非线性的对应类型。

所有树内驱动程序都已转换为从CreateFeature()切换到ICreateFeature()和SetFeature()切换到ISetFeature()。树外驱动程序必须进行类似的调整,否则这些方法将失败(OGRLayer类中现在的非虚拟方法将尝试创建同一类的默认实现,这将失败)。

文档

所有新方法和OGR几何类都被记录在案。必要时更新驱动程序文档。MIGRATION_GUIDE.TXT将使用此RFC的文本摘要进行更新。

测试

已经做了很少的更改,所以现有的自动测试套件仍然可以通过。对新几何类和转换方法的非常全面的测试已经添加到ogr_geom.py和ogr_gml_geom.py中。更新的驱动程序也收到了新的测试。

实施

甚至鲁奥也会实施。与源极协调(见 QGIS Enhancement 8: Geometry redesign ),由瑞士QGIS用户组赞助。

建议的实现位于 https://github.com/rouault/gdal2/tree/curve_geometries 储存库。

更改列表: https://github.com/rouault/gdal2/compare/curve_geometries

投票历史

+从塔马斯,朱卡尔和埃文