




















Clipper2 定义了多种枚举类型来控制裁剪、偏移等操作的行为。这些枚举类型直接影响算法的执行逻辑和最终结果。本章将详细解析每种枚举类型的含义和应用场景。
public enum ClipType
{
NoClip,
Intersection,
Union,
Difference,
Xor
}
ClipType.NoClip
不执行任何裁剪操作。通常用于测试或占位符。
ClipType.Intersection
返回主体和裁剪多边形的公共区域。
Subject: Clip: Result:
┌────────┐ ┌────────┐ ┌────┐
│ │ │ │ │ │
│ ┌────┼───┐ │ ┌────┼───┐ │ │
│ │ │ │ │ │ │ │ └────┘
│ │ │ │ ∩ │ │ │ │ =
│ └────┼───┘ │ └────┼───┘
│ │ │ │
└────────┘ └────────┘
ClipType.Union
返回主体和裁剪多边形的合并区域。
Subject: Clip: Result:
┌────────┐ ┌────────┐ ┌────────────────┐
│ │ │ │ │ │
│ ┌────┼───┐ │ ┌────┼───┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ∪ │ │ │ │ = │ │
│ └────┼───┘ │ └────┼───┘ │ │
│ │ │ │ │ │
└────────┘ └────────┘ └────────────────┘
ClipType.Difference
返回主体多边形减去裁剪多边形的区域。
注意:差集运算是非交换的,Subject - Clip ≠ Clip - Subject。
Subject: Clip: Result:
┌────────┐ ┌────────┐ ┌────┐
│ │ │ │ │ │
│ ┌────┼───┐ │ ┌────┼───┐ │ │
│ │ │ │ │ │ │ │ │ └────┐
│ │ │ │ - │ │ │ │ = │ │
│ └────┼───┘ │ └────┼───┘ │ ┌────┘
│ │ │ │ │ │
└────────┘ └────────┘ └────┘
ClipType.Xor
返回主体和裁剪多边形的非公共区域(属于其中一个但不同时属于两个)。
Subject: Clip: Result:
┌────────┐ ┌────────┐ ┌────┐ ┌────┐
│ │ │ │ │ │ │ │
│ ┌────┼───┐ │ ┌────┼───┐ │ └────┘ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ⊕ │ │ │ │ = │ │
│ └────┼───┘ │ └────┼───┘ │ ┌────┐ │
│ │ │ │ │ │ │ │
└────────┘ └────────┘ └────┘ └────┘
| 操作 | 交换性 |
|---|---|
| Intersection | 是(A ∩ B = B ∩ A) |
| Union | 是(A ∪ B = B ∪ A) |
| Difference | 否(A - B ≠ B - A) |
| Xor | 是(A ⊕ B = B ⊕ A) |
public enum PathType
{
Subject,
Clip
}
用于区分添加到裁剪器的路径是主体还是裁剪多边形:
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)
public enum FillRule
{
EvenOdd,
NonZero,
Positive,
Negative
}
填充规则决定了多边形内部的判定方式,特别是对于自相交或嵌套的多边形。
FillRule.EvenOdd
从任一点向外画一条射线,如果与多边形边界相交的次数为奇数,则该点在多边形内部。
特点:
↗ 穿过 1 次 → 内部
┌─────────────────┐
│ │
│ ┌───────┐ │ ↗ 穿过 2 次 → 外部
│ │ │ │
│ │ ● │ │ ↗ 穿过 3 次 → 内部
│ │ │ │
│ └───────┘ │
│ │
└─────────────────┘
FillRule.NonZero
从任一点向外画一条射线,计算与边界相交时的"缠绕数":
如果缠绕数不为零,则该点在多边形内部。
特点:
FillRule.Positive
只有当缠绕数为正数时,点才在多边形内部。
用途:只保留逆时针方向(正面积)的多边形区域。
FillRule.Negative
只有当缠绕数为负数时,点才在多边形内部。
用途:只保留顺时针方向(负面积)的多边形区域。
同向嵌套正方形:
┌───────────────┐
│ ┌─────────┐ │
│ │ ┌───┐ │ │
│ │ │ │ │ │
│ │ └───┘ │ │
│ └─────────┘ │
└───────────────┘
EvenOdd: 内外内(三层交替)
NonZero: 全内(合并)
Positive: 全内(同向)
Negative: 全外(反向为空)
public enum JoinType
{
Miter, // 斜接
Square, // 方形
Bevel, // 斜角
Round // 圆角
}
这些类型用于 ClipperOffset 的路径偏移操作,决定拐角处的处理方式。
JoinType.Miter
拐角处的两条偏移边延伸到相交点。
原始: Miter 偏移:
╱ ╱│
╱ ╱ │
╱─────── → ╱──────
│
│
注意:当角度很小时,斜接点会非常远,因此有 MiterLimit 参数限制。
JoinType.Square
在拐角处添加一个方形端点。
原始: Square 偏移:
╱ ┌─┐
╱ ╱ │
╱─────── → ╱───────
│
└──
JoinType.Bevel
直接连接两条偏移边的端点,形成斜切面。
原始: Bevel 偏移:
╱ ╱
╱ ╱╲
╱─────── → ╱──────
│
│
JoinType.Round
在拐角处使用圆弧连接。
原始: Round 偏移:
╱ ╭─╮
╱ ╱ ╲
╱─────── → ╱───────
│
╰─
public enum EndType
{
Polygon, // 闭合多边形
Joined, // 连接的开放路径
Butt, // 平头
Square, // 方形端
Round // 圆形端
}
这些类型决定开放路径端点的处理方式。
EndType.Polygon
将路径视为闭合多边形处理。偏移后仍然是闭合多边形。
EndType.Joined
开放路径,但首尾相连。偏移后会产生两条平行路径。
原始: Joined 偏移:
○────○ ○────○
│ │
○────○
EndType.Butt
端点处垂直截断。
原始: Butt 偏移:
○────○ │────│
│ │
│────│
EndType.Square
端点处添加方形延伸。
原始: Square 偏移:
○────○ ┌─────┐
│ │
└─────┘
EndType.Round
端点处添加半圆形。
原始: Round 偏移:
○────○ ╭─────╮
│ │
╰─────╯
[Flags]
public enum PointInPolygonResult
{
IsOn = 0, // 在边界上
IsInside = 1, // 在内部
IsOutside = 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;
}
[Flags]
internal enum VertexFlags
{
None = 0,
OpenStart = 1, // 开放路径起点
OpenEnd = 2, // 开放路径终点
LocalMax = 4, // 局部最大值
LocalMin = 8 // 局部最小值
}
这是内部使用的标志枚举,用于标记顶点的特殊属性。
由于使用了 [Flags] 特性,可以组合多个标志:
// 开放路径起点同时是局部极小值
VertexFlags flags = VertexFlags.OpenStart | VertexFlags.LocalMin;
// 检查是否包含某标志
if ((flags & VertexFlags.OpenStart) != VertexFlags.None)
{
// 是开放路径起点
}
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;
}
| 常量 | 值 | 说明 |
|---|---|---|
MaxInt64 |
2⁶³-1 | 64位有符号整数最大值 |
MaxCoord |
MaxInt64/4 | 最大坐标值,预留溢出空间 |
Invalid64 |
MaxInt64 | 用于标记无效值 |
floatingPointTolerance |
10⁻¹² | 浮点数近似相等容差 |
defaultMinimumEdgeLength |
0.1 | 默认最小边长 |
在几何计算中,经常需要计算两点坐标差的乘积:
// 叉积计算
double cross = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
如果坐标接近 MaxInt64,差值可能接近 2 * MaxInt64,乘积可能接近 4 * MaxInt64²,超出 long 范围。
将 MaxCoord 限制为 MaxInt64 / 4,确保中间计算不会溢出。
本章详细介绍了 Clipper2 的枚举类型和常量:
理解这些枚举类型是正确使用 Clipper2 的基础。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。