第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 的枚举类型和常量:
- ClipType:四种布尔运算类型
- PathType:区分主体和裁剪路径
- FillRule:四种填充规则
- JoinType:四种拐角连接方式
- EndType:五种端点处理方式
- PointInPolygonResult:点位置判断结果
- VertexFlags:内部顶点标志
- 内部常量:坐标范围和容差定义
理解这些枚举类型是正确使用 Clipper2 的基础。
| 上一章:矩形边界 | 返回目录 | 下一章:InternalClipper内部工具类 |