第4章:枚举类型与常量定义
4.1 概述
Clipper1 定义了多个枚举类型和常量,用于控制裁剪行为、指定填充规则、设置偏移选项等。理解这些定义对于正确使用 Clipper 至关重要。
4.2 ClipType 枚举
ClipType 定义了四种布尔运算类型:
public enum ClipType {
ctIntersection, // 交集
ctUnion, // 并集
ctDifference, // 差集
ctXor // 异或
}
4.2.1 Intersection(交集)
Subject Clip Result
┌───┐ ┌───┐
│ S │ │ C │ ┌─┐
│ ┌─┼───┐ │ │ = │█│
└─┼─┘ │ └───┘ └─┘
└─────┘
特点:返回两个多边形重叠的区域。
应用场景:
- 计算两个区域的公共部分
- 遮罩/裁剪效果
- 碰撞检测中的重叠区域
4.2.2 Union(并集)
Subject Clip Result
┌───┐ ┌───┐ ┌───────┐
│ S │ │ C │ │███████│
│ ┌─┼───┐ │ │ = │███████│
└─┼─┘ │ └───┘ └───────┘
└─────┘
特点:返回两个多边形覆盖的所有区域。
应用场景:
- 合并相邻区域
- 消除内部边界
- 构建复合形状
4.2.3 Difference(差集)
Subject Clip Result
┌───┐ ┌───┐ ┌──┐
│ S │ │ C │ │██│
│ ┌─┼───┐ │ │ = │██│
└─┼─┘ │ └───┘ └──┘
└─────┘
特点:返回 Subject 中不与 Clip 重叠的部分。
应用场景:
- 从形状中挖孔
- 计算边界区域
- 布尔减法运算
4.2.4 Xor(异或)
Subject Clip Result
┌───┐ ┌───┐ ┌──┬──┐
│ S │ │ C │ │██│ │
│ ┌─┼───┐ │ │ = │ └──┤
└─┼─┘ │ └───┘ └────█│
└─────┘ │
└┘
特点:返回两个多边形不重叠的部分(对称差)。
应用场景:
- 检测变化区域
- 高亮差异
- 边界效果
4.3 PolyType 枚举
PolyType 指定多边形在布尔运算中的角色:
public enum PolyType {
ptSubject, // 主体多边形
ptClip // 裁剪多边形
}
4.3.1 使用方式
Clipper clipper = new Clipper();
// 添加主体多边形
clipper.AddPath(subjectPath, PolyType.ptSubject, true);
clipper.AddPaths(subjectPaths, PolyType.ptSubject, true);
// 添加裁剪多边形
clipper.AddPath(clipPath, PolyType.ptClip, true);
clipper.AddPaths(clipPaths, PolyType.ptClip, true);
4.3.2 对布尔运算的影响
| 运算类型 | Subject | Clip | 结果 |
|---|---|---|---|
| Intersection | ✓ | ✓ | Subject ∩ Clip |
| Union | ✓ | ✓ | Subject ∪ Clip |
| Difference | ✓ | ✓ | Subject - Clip |
| Xor | ✓ | ✓ | Subject ⊕ Clip |
注意:Difference 运算是不对称的,Subject - Clip ≠ Clip - Subject。
4.4 PolyFillType 枚举
PolyFillType 定义多边形填充规则,决定哪些区域被视为”内部”:
public enum PolyFillType {
pftEvenOdd, // 奇偶规则
pftNonZero, // 非零规则
pftPositive, // 正向规则
pftNegative // 负向规则
}
4.4.1 EvenOdd(奇偶规则)
从点发射射线,计数穿过的边数:
- 奇数:内部
- 偶数:外部
┌─────────────┐
│ 1(内) │
┌───┼───┐ │
│ 2 │ 1 │ │
│(外)│(内) │
└───┴───┴─────────┘
特点:
- 最常用的规则
- 自动处理自相交多边形
- 交替填充重叠区域
4.4.2 NonZero(非零规则)
从点发射射线:
- 向上穿过:winding_number++
- 向下穿过:winding_number--
- winding_number ≠ 0:内部
- winding_number = 0:外部
→→→→→→→→→→→→→→
┌─────────────┐
│ winding=1 │
│ (内) │
↓ ┌───┐ ↑
│ │w=2│ │
│ │(内) │
└───┴───┴─────┘
特点:
- 考虑边的方向
- 同向重叠区域保持填充
- 适合路径描边
4.4.3 Positive(正向规则)
// 只有 winding_number > 0 的区域被填充
特点:
- 只填充正向缠绕的区域
- 忽略负向边的贡献
4.4.4 Negative(负向规则)
// 只有 winding_number < 0 的区域被填充
特点:
- 只填充负向缠绕的区域
- 忽略正向边的贡献
4.4.5 填充规则对比
// 自相交多边形(8字形)
Path figure8 = new Path();
figure8.Add(new IntPoint(0, 0));
figure8.Add(new IntPoint(100, 100));
figure8.Add(new IntPoint(100, 0));
figure8.Add(new IntPoint(0, 100));
// 使用不同填充规则
Paths resultEvenOdd = new Paths();
Paths resultNonZero = new Paths();
clipper.AddPath(figure8, PolyType.ptSubject, true);
clipper.Execute(ClipType.ctUnion, resultEvenOdd,
PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);
clipper.Clear();
clipper.AddPath(figure8, PolyType.ptSubject, true);
clipper.Execute(ClipType.ctUnion, resultNonZero,
PolyFillType.pftNonZero, PolyFillType.pftNonZero);
4.5 JoinType 枚举
JoinType 用于 ClipperOffset,指定偏移时拐角的连接方式:
public enum JoinType {
jtSquare, // 方形连接
jtRound, // 圆形连接
jtMiter // 斜接连接
}
4.5.1 Square(方形连接)
原始角: 偏移后:
╱ ┌───┐
╱ │ │
╱ │ │
特点:
- 在拐角处创建 45° 斜切
- 产生明确的边界
- 适合工程应用
4.5.2 Round(圆形连接)
原始角: 偏移后:
╱ ╭───╮
╱ │ │
╱ │ │
特点:
- 在拐角处创建圆弧
- 视觉效果平滑
- 适合图形设计
4.5.3 Miter(斜接连接)
原始角: 偏移后:
╱ ╱
╱ ╱
╱ ╱
╱
特点:
- 延伸边线直到相交
- 锐角可能产生很长的尖角
- 使用 MiterLimit 控制最大延伸
4.6 EndType 枚举
EndType 用于 ClipperOffset,指定开放路径端点的处理方式:
public enum EndType {
etClosedPolygon, // 闭合多边形
etClosedLine, // 闭合线
etOpenButt, // 开放-平头
etOpenSquare, // 开放-方头
etOpenRound // 开放-圆头
}
4.6.1 ClosedPolygon
// 用于闭合多边形,首尾自动连接
// 偏移会产生内外两个轮廓(或只有外轮廓)
4.6.2 ClosedLine
// 用于闭合线(首尾连接但可能自相交)
// 偏移两侧但不在端点处闭合
4.6.3 OpenButt(平头)
原始线: 偏移后:
─────── ┌───────┐
└───────┘
4.6.4 OpenSquare(方头)
原始线: 偏移后:
─────── ┌─────────┐
└─────────┘
(延伸 delta 距离)
4.6.5 OpenRound(圆头)
原始线: 偏移后:
─────── ╭─────────╮
╰─────────╯
(圆弧端点)
4.7 内部枚举类型
4.7.1 EdgeSide
internal enum EdgeSide { esLeft, esRight }
指定边相对于输出多边形的位置(左侧或右侧)。
4.7.2 Direction
internal enum Direction { dRightToLeft, dLeftToRight }
指定边的扫描方向,用于水平边处理。
4.8 常量定义
4.8.1 ClipperBase 常量
public class ClipperBase
{
internal const double horizontal = -3.4E+38;
internal const int Skip = -2;
internal const int Unassigned = -1;
internal const double tolerance = 1.0E-20;
internal static bool near_zero(double val)
{
return (val > -tolerance) && (val < tolerance);
}
#if use_int32
public const cInt loRange = 0x7FFF;
public const cInt hiRange = 0x7FFF;
#else
public const cInt loRange = 0x3FFFFFFF;
public const cInt hiRange = 0x3FFFFFFFFFFFFFFFL;
#endif
}
| 常量 | 值 | 说明 |
|---|---|---|
horizontal |
-3.4E+38 | 标识水平边的特殊斜率值 |
Skip |
-2 | 标记需要跳过的边 |
Unassigned |
-1 | 表示未分配的输出索引 |
tolerance |
1.0E-20 | 浮点数零判断的容差 |
loRange |
0x3FFFFFFF | 低精度模式的坐标范围 |
hiRange |
0x3FFFFFFFFFFFFFFFL | 高精度模式的坐标范围 |
4.8.2 Clipper 常量
public class Clipper : ClipperBase
{
// InitOptions 可以传递给构造函数
public const int ioReverseSolution = 1;
public const int ioStrictlySimple = 2;
public const int ioPreserveCollinear = 4;
}
| 常量 | 值 | 说明 |
|---|---|---|
ioReverseSolution |
1 | 反转结果多边形的方向 |
ioStrictlySimple |
2 | 确保结果是严格简单的多边形 |
ioPreserveCollinear |
4 | 保留共线顶点 |
4.8.3 使用 InitOptions
// 默认选项
Clipper clipper1 = new Clipper();
// 反转结果方向
Clipper clipper2 = new Clipper(Clipper.ioReverseSolution);
// 严格简单多边形
Clipper clipper3 = new Clipper(Clipper.ioStrictlySimple);
// 组合选项(使用位或)
Clipper clipper4 = new Clipper(
Clipper.ioReverseSolution | Clipper.ioStrictlySimple
);
// 也可以通过属性设置
clipper1.ReverseSolution = true;
clipper1.StrictlySimple = true;
clipper1.PreserveCollinear = true;
4.8.4 ClipperOffset 常量
public class ClipperOffset
{
private const double two_pi = Math.PI * 2;
private const double def_arc_tolerance = 0.25;
public double ArcTolerance { get; set; }
public double MiterLimit { get; set; }
}
| 常量/属性 | 默认值 | 说明 |
|---|---|---|
two_pi |
2π | 完整圆的弧度 |
def_arc_tolerance |
0.25 | 默认弧度容差 |
ArcTolerance |
0.25 | 圆弧近似的容差 |
MiterLimit |
2.0 | 斜接限制 |
4.9 横向边斜率常量
internal const double horizontal = -3.4E+38;
这个特殊值用于标识水平边。在 Clipper 的坐标系中(Y 轴向上),水平边的斜率定义为无穷大或极大值。使用 -3.4E+38 而非正无穷,是为了便于比较和特殊处理。
使用示例:
internal static bool IsHorizontal(TEdge e)
{
return e.Delta.Y == 0;
}
private void SetDx(TEdge e)
{
e.Delta.X = (e.Top.X - e.Bot.X);
e.Delta.Y = (e.Top.Y - e.Bot.Y);
if (e.Delta.Y == 0)
e.Dx = horizontal;
else
e.Dx = (double)(e.Delta.X) / (e.Delta.Y);
}
4.10 坐标范围常量详解
4.10.1 32位模式
#if use_int32
public const cInt loRange = 0x7FFF; // 32,767
public const cInt hiRange = 0x7FFF; // 32,767
#endif
在 32 位模式下,坐标范围被严格限制,因为中间计算可能产生溢出。
4.10.2 64位模式
#else
public const cInt loRange = 0x3FFFFFFF; // 约 10⁹
public const cInt hiRange = 0x3FFFFFFFFFFFFFFFL; // 约 4.6×10¹⁸
#endif
两个范围的意义:
- loRange:低精度范围,中间计算使用普通 64 位整数
- hiRange:高精度范围,中间计算使用 128 位整数(Int128)
当坐标超过 loRange 时,Clipper 自动切换到 128 位计算模式,以避免溢出。
4.11 本章小结
本章详细介绍了 Clipper1 中的枚举类型和常量:
- 布尔运算类型(ClipType):
- 交集、并集、差集、异或
- 多边形类型(PolyType):
- 主体和裁剪多边形的区分
- 填充规则(PolyFillType):
- 奇偶、非零、正向、负向规则
- 偏移选项:
- JoinType:方形、圆形、斜接连接
- EndType:各种端点处理方式
- 重要常量:
- 坐标范围限制
- 初始化选项
- 特殊标记值
理解这些枚举和常量是正确配置 Clipper 的基础,不同的选项组合可以实现各种复杂的几何运算需求。
| 上一章:路径与多边形表示 | 返回目录 | 下一章:Int128高精度运算 |