znlgis 博客

GIS开发与技术分享

第5章:枚举类型与常量定义

5.1 概述

Clipper2 定义了多种枚举类型来控制裁剪、偏移等操作的行为。这些枚举类型直接影响算法的执行逻辑和最终结果。本章将详细解析每种枚举类型的含义和应用场景。

5.2 ClipType 裁剪类型

5.2.1 枚举定义

public enum ClipType
{
    NoClip,
    Intersection,
    Union,
    Difference,
    Xor
}

5.2.2 各类型详解

NoClip(无裁剪)

ClipType.NoClip

不执行任何裁剪操作。通常用于测试或占位符。

Intersection(交集)

ClipType.Intersection

返回主体和裁剪多边形的公共区域。

Subject:          Clip:             Result:
┌────────┐       ┌────────┐        ┌────┐
│        │       │        │        │    │
│   ┌────┼───┐   │   ┌────┼───┐    │    │
│   │    │   │   │   │    │   │    └────┘
│   │    │   │ ∩ │   │    │   │ =  
│   └────┼───┘   │   └────┼───┘    
│        │       │        │        
└────────┘       └────────┘        

Union(并集)

ClipType.Union

返回主体和裁剪多边形的合并区域。

Subject:          Clip:             Result:
┌────────┐       ┌────────┐        ┌────────────────┐
│        │       │        │        │                │
│   ┌────┼───┐   │   ┌────┼───┐    │                │
│   │    │   │   │   │    │   │    │                │
│   │    │   │ ∪ │   │    │   │ =  │                │
│   └────┼───┘   │   └────┼───┘    │                │
│        │       │        │        │                │
└────────┘       └────────┘        └────────────────┘

Difference(差集)

ClipType.Difference

返回主体多边形减去裁剪多边形的区域。

注意:差集运算是非交换的,Subject - Clip ≠ Clip - Subject

Subject:          Clip:             Result:
┌────────┐       ┌────────┐        ┌────┐
│        │       │        │        │    │
│   ┌────┼───┐   │   ┌────┼───┐    │    │
│   │    │   │   │   │    │   │    │    └────┐
│   │    │   │ - │   │    │   │ =  │         │
│   └────┼───┘   │   └────┼───┘    │    ┌────┘
│        │       │        │        │    │
└────────┘       └────────┘        └────┘

Xor(异或)

ClipType.Xor

返回主体和裁剪多边形的非公共区域(属于其中一个但不同时属于两个)。

Subject:          Clip:             Result:
┌────────┐       ┌────────┐        ┌────┐    ┌────┐
│        │       │        │        │    │    │    │
│   ┌────┼───┐   │   ┌────┼───┐    │    └────┘    │
│   │    │   │   │   │    │   │    │              │
│   │    │   │ ⊕ │   │    │   │ =  │              │
│   └────┼───┘   │   └────┼───┘    │    ┌────┐    │
│        │       │        │        │    │    │    │
└────────┘       └────────┘        └────┘    └────┘

5.2.3 交换性

操作 交换性
Intersection 是(A ∩ B = B ∩ A)
Union 是(A ∪ B = B ∪ A)
Difference 否(A - B ≠ B - A)
Xor 是(A ⊕ B = B ⊕ A)

5.3 PathType 路径类型

5.3.1 枚举定义

public enum PathType
{
    Subject,
    Clip
}

5.3.2 用途

用于区分添加到裁剪器的路径是主体还是裁剪多边形:

Clipper64 clipper = new Clipper64();
clipper.AddPath(subjectPath, PathType.Subject, true);
clipper.AddPath(clipPath, PathType.Clip, true);

或使用便捷方法:

clipper.AddSubject(subjectPath);  // 等同于 AddPath(..., PathType.Subject, false)
clipper.AddClip(clipPath);        // 等同于 AddPath(..., PathType.Clip, false)

5.4 FillRule 填充规则

5.4.1 枚举定义

public enum FillRule
{
    EvenOdd,
    NonZero,
    Positive,
    Negative
}

填充规则决定了多边形内部的判定方式,特别是对于自相交或嵌套的多边形。

5.4.2 EvenOdd(奇偶规则)

FillRule.EvenOdd

从任一点向外画一条射线,如果与多边形边界相交的次数为奇数,则该点在多边形内部。

特点

  • 最直观的规则
  • 自相交多边形会产生”孔洞”效果
  • 路径方向无关
        ↗ 穿过 1 次 → 内部
┌─────────────────┐
│                 │
│    ┌───────┐    │   ↗ 穿过 2 次 → 外部
│    │       │    │
│    │   ●   │    │   ↗ 穿过 3 次 → 内部
│    │       │    │
│    └───────┘    │
│                 │
└─────────────────┘

5.4.3 NonZero(非零规则)

FillRule.NonZero

从任一点向外画一条射线,计算与边界相交时的”缠绕数”:

  • 从右向左穿过边界:+1
  • 从左向右穿过边界:-1

如果缠绕数不为零,则该点在多边形内部。

特点

  • 考虑路径方向
  • 同向嵌套多边形会合并
  • 反向嵌套多边形会产生孔洞

5.4.4 Positive(正向规则)

FillRule.Positive

只有当缠绕数为正数时,点才在多边形内部。

用途:只保留逆时针方向(正面积)的多边形区域。

5.4.5 Negative(负向规则)

FillRule.Negative

只有当缠绕数为负数时,点才在多边形内部。

用途:只保留顺时针方向(负面积)的多边形区域。

5.4.6 填充规则比较

同向嵌套正方形:
┌───────────────┐
│  ┌─────────┐  │
│  │  ┌───┐  │  │
│  │  │   │  │  │
│  │  └───┘  │  │
│  └─────────┘  │
└───────────────┘

EvenOdd:  内外内(三层交替)
NonZero:  全内(合并)
Positive: 全内(同向)
Negative: 全外(反向为空)

5.5 JoinType 连接类型

5.5.1 枚举定义

public enum JoinType
{
    Miter,    // 斜接
    Square,   // 方形
    Bevel,    // 斜角
    Round     // 圆角
}

这些类型用于 ClipperOffset 的路径偏移操作,决定拐角处的处理方式。

5.5.2 Miter(斜接)

JoinType.Miter

拐角处的两条偏移边延伸到相交点。

原始:           Miter 偏移:
  ╱              ╱│
 ╱              ╱ │
╱───────  →   ╱──────
              │
              │

注意:当角度很小时,斜接点会非常远,因此有 MiterLimit 参数限制。

5.5.3 Square(方形)

JoinType.Square

在拐角处添加一个方形端点。

原始:           Square 偏移:
  ╱              ┌─┐
 ╱              ╱  │
╱───────  →   ╱───────
              │
              └──

5.5.4 Bevel(斜角)

JoinType.Bevel

直接连接两条偏移边的端点,形成斜切面。

原始:           Bevel 偏移:
  ╱               ╱
 ╱              ╱╲
╱───────  →   ╱──────
              │
              │

5.5.5 Round(圆角)

JoinType.Round

在拐角处使用圆弧连接。

原始:           Round 偏移:
  ╱              ╭─╮
 ╱              ╱   ╲
╱───────  →   ╱───────
              │
              ╰─

5.6 EndType 端点类型

5.6.1 枚举定义

public enum EndType
{
    Polygon,   // 闭合多边形
    Joined,    // 连接的开放路径
    Butt,      // 平头
    Square,    // 方形端
    Round      // 圆形端
}

这些类型决定开放路径端点的处理方式。

5.6.2 Polygon(闭合多边形)

EndType.Polygon

将路径视为闭合多边形处理。偏移后仍然是闭合多边形。

5.6.3 Joined(连接)

EndType.Joined

开放路径,但首尾相连。偏移后会产生两条平行路径。

原始:    Joined 偏移:
○────○    ○────○
          │    │
          ○────○

5.6.4 Butt(平头)

EndType.Butt

端点处垂直截断。

原始:    Butt 偏移:
○────○    │────│
          │    │
          │────│

5.6.5 Square(方形端)

EndType.Square

端点处添加方形延伸。

原始:    Square 偏移:
○────○    ┌─────┐
          │     │
          └─────┘

5.6.6 Round(圆形端)

EndType.Round

端点处添加半圆形。

原始:    Round 偏移:
○────○    ╭─────╮
          │     │
          ╰─────╯

5.7 PointInPolygonResult 点在多边形中的结果

5.7.1 枚举定义

[Flags]
public enum PointInPolygonResult
{
    IsOn = 0,      // 在边界上
    IsInside = 1,  // 在内部
    IsOutside = 2  // 在外部
}

5.7.2 使用示例

Point64 testPoint = new Point64(50, 50);
Path64 polygon = Clipper.MakePath(new long[] {
    0, 0, 100, 0, 100, 100, 0, 100
});

PointInPolygonResult result = Clipper.PointInPolygon(testPoint, polygon);

switch (result)
{
    case PointInPolygonResult.IsInside:
        Console.WriteLine("点在多边形内部");
        break;
    case PointInPolygonResult.IsOutside:
        Console.WriteLine("点在多边形外部");
        break;
    case PointInPolygonResult.IsOn:
        Console.WriteLine("点在多边形边界上");
        break;
}

5.8 VertexFlags 顶点标志

5.8.1 枚举定义

[Flags]
internal enum VertexFlags
{
    None = 0,
    OpenStart = 1,   // 开放路径起点
    OpenEnd = 2,     // 开放路径终点
    LocalMax = 4,    // 局部最大值
    LocalMin = 8     // 局部最小值
}

这是内部使用的标志枚举,用于标记顶点的特殊属性。

5.8.2 位标志操作

由于使用了 [Flags] 特性,可以组合多个标志:

// 开放路径起点同时是局部极小值
VertexFlags flags = VertexFlags.OpenStart | VertexFlags.LocalMin;

// 检查是否包含某标志
if ((flags & VertexFlags.OpenStart) != VertexFlags.None)
{
    // 是开放路径起点
}

5.9 内部常量

5.9.1 InternalClipper 常量

internal static class InternalClipper
{
    internal const long MaxInt64 = 9223372036854775807;
    internal const long MaxCoord = MaxInt64 / 4;
    internal const double max_coord = MaxCoord;
    internal const double min_coord = -MaxCoord;
    internal const long Invalid64 = MaxInt64;

    internal const double floatingPointTolerance = 1E-12;
    internal const double defaultMinimumEdgeLength = 0.1;
}

5.9.2 常量说明

常量 说明
MaxInt64 2⁶³-1 64位有符号整数最大值
MaxCoord MaxInt64/4 最大坐标值,预留溢出空间
Invalid64 MaxInt64 用于标记无效值
floatingPointTolerance 10⁻¹² 浮点数近似相等容差
defaultMinimumEdgeLength 0.1 默认最小边长

5.9.3 为什么 MaxCoord = MaxInt64 / 4?

在几何计算中,经常需要计算两点坐标差的乘积:

// 叉积计算
double cross = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);

如果坐标接近 MaxInt64,差值可能接近 2 * MaxInt64,乘积可能接近 4 * MaxInt64²,超出 long 范围。

MaxCoord 限制为 MaxInt64 / 4,确保中间计算不会溢出。

5.10 本章小结

本章详细介绍了 Clipper2 的枚举类型和常量:

  1. ClipType:四种布尔运算类型
  2. PathType:区分主体和裁剪路径
  3. FillRule:四种填充规则
  4. JoinType:四种拐角连接方式
  5. EndType:五种端点处理方式
  6. PointInPolygonResult:点位置判断结果
  7. VertexFlags:内部顶点标志
  8. 内部常量:坐标范围和容差定义

理解这些枚举类型是正确使用 Clipper2 的基础。


上一章:矩形边界 返回目录 下一章:InternalClipper内部工具类