多边形

Polygon 是存储为一系列点的二维表面,这些点定义一个外部边界环和零个或多个内部环。

Polygon 实例

可以从至少具有三个不同点的环中构建一个 Polygon 实例。Polygon 实例也可以为空。

Polygon 的外部环和任意内部环定义了其边界。环内部的空间定义了 Polygon 的内部。

下图显示了 Polygon 实例的示例。

几何 Polygon 实例的示例

如图中所示:

  1. 图 1 是由外部环定义其边界的 Polygon 实例。

  2. 图 2 是由外部环和两个内部环定义其边界的 Polygon 实例。内部环内的面积是 Polygon 实例的外部环的一部分。

  3. 图 3 是一个有效的 Polygon 实例,因为其内部环在单个切点处相交。

接受的实例

接受的 Polygon 实例是可存储于 geometry 或 geography 变量中且不引发异常的实例。下面是 geometry 类型的接受的 Polygon 实例:

  • 空的 Polygon 实例

  • 具有一个可接受的外环以及零个或更多可接受的内环的 Polygon 实例

一个环若要可接受,需要满足以下条件。

  • LineString 实例必须是接受的实例。

  • LineString 实例必须具有至少四个点,包括三个不同点。

  • LineString 实例的起始点和结束点必须具有相同的 X 和 Y 值。

    注意注意

    Z 和 M 值被忽略。

只有在该实例有效时,才会接受 geography 类型的 Polygon 实例。有关 geography 类型的有效 Polygon 实例的详细信息,请参阅 BkmkValidGeographyPolygons

下面的示例显示接受的 Polygon 实例。

DECLARE @g1 geometry = 'POLYGON EMPTY';
DECLARE @g2 geometry = 'POLYGON((1 1, 3 3, 3 1, 1 1))';
DECLARE @g3 geometry = 'POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5),(0 0, 3 0, 3 3, 0 3, 0 0))';
DECLARE @g4 geometry = 'POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5),(3 0, 6 0, 6 3, 3 3, 3 0))';

@g4 表明接受的 Polygon 实例可能不是有效的 Polygon 实例。下面的示例引发 System.FormatException,因为 Polygon 实例未被接受。

DECLARE @g1 geometry = 'POLYGON((1 1, 3 3, 1 1))';
DECLARE @g2 geometry = 'POLYGON((1 1, 3 3, 3 1, 1 5))';

@g1 未被接受,因为外环的 LineString 实例未包含足够的点。@g2 未被接受,因为外环 LineString 实例的起始点与结束点不同。下面的示例具有一个可接受的外环,但内环不可接受。这也引发 System.FormatException。

DECLARE @g geometry = 'POLYGON((-5 -5, -5 5, 5 5, 5 -5, -5 -5),(0 0, 3 0, 0 0))';

有效实例

Polygon 的内部环在单个切点处既可与自身接触也可彼此接触,但如果 Polygon 的内部环交叉,则该实例无效。

下面的示例显示有效的 Polygon 实例。

DECLARE @g1 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20))';
DECLARE @g2 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0))';
DECLARE @g3 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 0 10, -5 -10, -10 0))';
SELECT @g1.STIsValid(), @g2.STIsValid(), @g3.STIsValid();

@g3 是有效的,因为两个内环在一个点上接触并且不彼此交叉。下面的示例显示无效的 Polygon 实例。

DECLARE @g1 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (20 0, 0 10, 0 -20, 20 0))';
DECLARE @g2 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (5 0, 1 5, 1 -5, 5 0))';
DECLARE @g3 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 0 10, 0 -10, -10 0))';
DECLARE @g4 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 1 5, 0 -10, -10 0))';
SELECT @g1.STIsValid(), @g2.STIsValid(), @g3.STIsValid(), @g4.STIsValid();

@g1 无效,因为内环与外环在两处接触。@g2 无效,因为第二个内环位于第一个内环的内部。@g3 无效,因为两个内环在多个连续点接触。@g4 无效,因为两个内环的内部重叠。

geometry 数据类型

为使 geometry 类型的 Polygon 实例有效,该实例需要满足以下条件:

  1. 第一个环是外环。

  2. 所有内环都处于外环内。

  3. 没有内环处于其他内环内。

  4. 没有环与自身或其他环交叉。

  5. 不能有两个环共用同一边。

  6. 一个内环的内部不能与另一个内环的内部重叠。

  7. 所有环只能与自身接触,或者在零个或有限数目的正切点上与其他环接触。

  8. Polygon 实例的内部是连接的。在实例的任何两个内部点之间必须存在完全位于该实例内的至少一个路径。

下面的示例显示有效的 Polygon 实例。

DECLARE @g1 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20))';
DECLARE @g2 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0))';
DECLARE @g3 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 0 10, -5 -10, -10 0))';
SELECT @g1.STIsValid(), @g2.STIsValid(), @g3.STIsValid();

@g3 是有效的,因为两个内环在一个点上接触并且不彼此交叉。下面的示例显示无效的 Polygon 实例。

DECLARE @g1 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (20 0, 0 10, 0 -20, 20 0))';
DECLARE @g2 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (5 0, 1 5, 1 -5, 5 0))';
DECLARE @g3 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 0 10, 0 -10, -10 0))';
DECLARE @g4 geometry = 'POLYGON((-20 -20, -20 20, 20 20, 20 -20, -20 -20), (10 0, 0 10, 0 -10, 10 0), (-10 0, 1 5, 0 -10, -10 0))';
DECLARE @g5 geometry = 'POLYGON((10 0, 0 10, 0 -10, 10 0), (-20 -20, -20 20, 20 20, 20 -20, -20 -20) )';
SELECT @g1.STIsValid(), @g2.STIsValid(), @g3.STIsValid(), @g4.STIsValid(), @g5.STIsValid();

@g1 无效,因为内环在两个位置中与外环接触。@g2 无效,因为第二个内环在第一个内环的内部。@g3 无效,因为两个内环在多个连续点接触。@g4 无效,因为两个内环的内部重叠。@g5 无效,因为第一个环是内环,第二个环是外环。

geography 数据类型

为使 geography 类型的 Polygon 实例有效,该实例必须满足以下条件:

  1. 该实例必须满足成为 geometry 类型的接受的 Polygon 实例所要求的所有规则。

  2. 实例的内部使用左手定律进行连接。

  3. 实例可以容纳在半球中。

  4. 没有环与自身或任何其他环交叉。

  5. 所有环只能与自身接触,或者在零个或有限数目的正切点上与任何其他环接触。

下面的示例引发 Microsoft.SqlServer.Types.GLArgumentException,因为 Polygon 实例超出了半球。

DECLARE @g geography = 'POLYGON((-122.358 47.653, 122.348 47.649, 122.348 47.658, 122.358 47.658, -122.358 47.653))';

下面的示例显示 geography 类型的有效 Polygon 实例。

DECLARE @g geography = 'POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))';

示例

下例创建了一个带有孔和 SRID 为 10 的简单 geometryPolygon 实例。

DECLARE @g geometry;
SET @g = geometry::STPolyFromText('POLYGON((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1))', 10);

可能输入无效的实例并转换为有效的geometry 实例。在下列 Polygon 示例中,内部环和外部环重叠且该实例无效。

DECLARE @g geometry;
SET @g = geometry::Parse('POLYGON((1 0, 0 1, 1 2, 2 1, 1 0), (2 0, 1 1, 2 2, 3 1, 2 0))');

在下例中,无效实例通过 MakeValid() 成为有效实例。

SET @g = @g.MakeValid();
SELECT @g.ToString();

以上示例中返回的 geometry 实例为 MultiPolygon。

MULTIPOLYGON (((2 0, 3 1, 2 2, 1.5 1.5, 2 1, 1.5 0.5, 2 0)), ((1 0, 1.5 0.5, 1 1, 1.5 1.5, 1 2, 0 1, 1 0)))