Javascript Clipper library, v6(介绍目录)
1.老祖宗C#版的Clipper2
Clipper2库可以对简单和复杂的多边形执行交集、并并、差分和异或布尔运算。它还执行多边形偏移
github地址:GitHub - AngusJohnson/Clipper2: Polygon Clipping and Offsetting - C++, C# and Delphi
2.目前的移植版本
基于C#版的移植版本和语言如下
语言 | 版本 | 文档地址 |
JavaScript | Javascript_Clipper_6.4.2.2_fpoint.zip(更新2017-09-08) | https://sourceforge.net/p/jsclipper/wiki/Home%206/ |
---|---|---|
WASM | Clipper2-WASM | GitHub - ErikSom/Clipper2-WASM: WASM port of Clipper 2 for Polygon Clipping and Offsetting |
Java | Clipper2-java | GitHub - micycle1/Clipper2-java: Java port of Clipper2, a Polygon Clipping and Offsetting Library |
Kotlin | clipper2-kotlin | GitHub - urbanistic/clipper2-kotlin |
golang | goclipper2 | GitHub - epit3d/goclipper2 |
3.JavaScript Clipper文档
3.1 使用前须知
操作对象: 多边形 polygons和线条 lines
操作方式:裁剪clipping和偏移offsetting
区别其他库(看点):
(1)处理所有类型多边形,包括自相交多边形
(2)支持多个多边形填充规则(偶奇,非零,正,负)
(3)执行速度快
(4)直线line和多边形polygon的偏移offsetting操作
术语:
(1)Clipping裁剪:一般认为裁剪就是给定的一个多边形(当然可以多个多边形),超出多边形之外的剪切掉,换算的是交集。但在本文档中,它指的是四种布尔操作(交集、并并、差异和异或)中的任何一种。
(2)subject/clip:被裁剪对象叫做subject, clip window等称为clip
(3)segment线段:由相连的两点(point/vertice)表示
(4)Path路径:直线或者多边形有序顶点序列,由一系列segment构成的路径
Open paths是指起点和终点不相连的Paths, 也叫做polylines
Close paths是指起点和终点相连的Paths,通常叫做polygon
subject可能是Open paths, 也可能是closed paths
clip只能是closed paths.
(5)Contour轮廓:同path术语
(6)Line直线:或者polyline折线是包含2个或更多顶点的开放路径。
(7)Polygon多边形:在本文档中,多边形指的是已知闭合的路径。
(8)simple polygons简单多边形: 由一条不自交(self-intersect)的Close Paths构成的图形称为简单多边形(simple polygons)
(9)complex polygons复杂多边形:如果Closed paths自相交,或者由多条Paths组成的polygons, 称为复杂多边形(complex polygons)
(7)Polygon Hole洞:是一个多边形内的封闭区域,它不是多边形的一部分。形成孔外边界的多边形称为孔多边形。 holes通常是由位于outer polygon contour内部的inner polygon contour 组成。
(8)Polygon Filling region 简单多变形(simple polygons)的填充区域是固定的,复杂多变形(complex polygons)的填充区域(Filling region)依赖填充规则(Filling rule),填充规则决定什么是hole, 什么不是hole, hole不填充,不属于填充区域,除掉hole的部分都属于填充区域。
(9)Polygon Filling Rule多边形填充规则:
通过填充,可以表明哪些区域是位于Closed path的内部,哪些区域是位于Closed path的外部。Clipper2支持4种填充规则(Filling rule),分别是:EvenOdd, NonZero, Positive, Negative,其中EvenOdd规则是基于射线法确定,NonZero, Positive, Negative是基于图形的winding number确定。
- EvenOdd: 也称交替填充( alternate filling),从图形的外部一点引一条射线,第一次相交Paths, 相应的区域填充,第二次相交的Paths,相应区域不填充,第三次相交Paths,相应区域填充,依次类推
- NonZero: Winding number不为0的部分填充
- Positive: Winding number 大于0的部分填充
- Negative: Winding number 小于0的部分填充
EvenOdd规则和Paths中edge direction和Winding number无关,其它三个与Paths中edge direction和Winding number相关。
(10)Winding number绕圈数
Winding number可以理解为绕圈数 ,详细解释见后续章节
(11)Touching
在Closed Paths中,segments通常被叫做edge.
- Edge touching是指edge共线(collinear)或重合(overlap)
- Polygon touching是指当两个polygon有Edge touching
(12)Polygon offseting
Polygon offseting就是将polygon变大或者变小。
Clipper2的offseting支持(inflating/deflating),不支持单方向的offseting,比如horizontal or vertical offseting。对于Open paths or Closed paths,Clipper都支持offseting
1. Join type
做Polygon offseting时,edge的连接类型(Join type)可能是Square、Round、Miter,这主要是对连接处非90度的情况进行处理的。它们分别的功能是:
- Square:当edge的join处,角度小于90度时,当inflate/deflate polygon时,会将尖角切掉,并且添加一条线段,添加的线段到join vertex的距离是inflate/deflate的offset。
- Round: 当edge的join处,角度小于90度时,当inflate/deflate polygon时,会将尖角切掉,并且添加一条凸型曲线,添加的曲线到join vertex的距离是inflate/deflate的offset。
- Miter: 当edge的join处,角度小于90度时,当inflate/deflate polygon时,会将尖角切掉,并且添加一条线段,添加的线段到join vertex的距离是inflate/deflate的offset * miter, miter的默认值是2,当miter为无穷大时,这种情况下inflate/deflate将保留原来图形的尖角(spike)。
2. End type
当进行做Polygon offseting时,由于input可能是Open paths or Closed paths,End type将指明如何对待input的ending vertices.
- Polygon: output result path将会被当做polygon(首尾相连,填充内部)
- Join: output result path 将会被当作polyline(首尾相连,内部不填充)–not clear
- Square: ends 延长offset长度,采用Square的方法截短
- Round:ends 延长offset长度,采用Square的方法截短
- Butt: ends不延长,采用Square方法截断
当对Polygons进行inflate/deflate时,EndType必须选择 EndType.Polygon,如果选择别的类型,将会支队polygon的outline进行inflate/deflate
3.2 Clipper2 中注意事项
3.2.1. polygon touching problem
由于subject可能是Open paths,也可能是closed paths,clip只能是closed paths.那么我们有时可能是clip closed paths,有时是clip open paths.
用的最多的是clip closed paths,这种情况下得到的外层contour一般是逆时针的(anti-clockwise/counter-clockwise),内层holes是顺时针的(clockwise),这意味着用EvenOdd填充方法或NonZero填充方法得到的contour是一样的。
clip closed paths最大的一个问题是得到的结果可能还有polygon touching的情况,如果遇到这样的情况,作者的建议是再调用一次union,那么得到的应该是最简(simplest/clean)形式的polygon。
3.2.2 Self-intersection polygon
boolean操作支持self-intersection polygon
offseting操作不支持self-intersection polygon
3.2.3 Rounding
在计算几何中,由于坐标是由离散的实数表示的(不管时整型还是浮点数),那么,从理论上来说,如果我们需要得到确切的坐标(比如两条线的交点),几何计算就不可能是numerically robust的。
Clipper2预期到了坐标的不精确,管理这种不精确性,做到了numerically robust,主要是通过以下几点:
- 用整型表示所有的内部坐标(by using integer variables rather than floats, maximum imprecision is constant. This simplifies differentiating significant from insignificant imprecision)。
- 使用算法来解决由于不精确性带来的坐标不是严格不等的问题
- 内部计算对所有的结果进行round
3.2.4 Self-intersection artefacts
在做union操作时,可能会有自相交的局部图形存在:
源码:有7625行源代码
3.3 将Clipper与SVG和Canvas一起使用示例:
Clipper 6 Info and Examples演示例子和源码
3.4 文档使用目录
- Clipper 6使用文档
- ClipperBase
- ClipperBase方法:
- ClipperBase.AddPath()
- ClipperBase.AddPaths()
- ClipperBase.Clear()
- ClipperBase
- Clipper
- ClipperLib.Clipper.ZFillFunction
- ClipperLib.Clipper.StrictlySimple
- ClipperLib.Clipper.ReverseSolution
- ClipperLib.Clipper.PreserveCollinear
- --- Clipper Properties ---
- ClipperLib.Clipper.SimplifyPolygons()
- ClipperLib.Clipper.SimplifyPolygon()
- ClipperLib.Clipper.ReversePaths()
- ClipperLib.Clipper.ReversePath()
- ClipperLib.Clipper.PolyTreeToPaths()
- ClipperLib.Clipper.PointInPolygon()
- ClipperLib.Clipper.Orientation()
- ClipperLib.Clipper.OpenPathsFromPolyTree()
- ClipperLib.Clipper.OffsetPaths()
- ClipperLib.Clipper.MinkowskiSum()
- ClipperLib.Clipper.MinkowskiDiff()
- ClipperLib.Clipper.GetBounds()
- ClipperLib.Clipper.Execute()
- ClipperLib.Clipper.ClosedPathsFromPolyTree()
- ClipperLib.Clipper.CleanPolygons()
- ClipperLib.Clipper.CleanPolygon()
- ClipperLib.Clipper.Area()
- ClipperLib.Clipper()
- --- Clipper methods ---
- Types
- ClipperLib.ClipType()
- ClipperLib.EndType
- ClipperLib.EndType_
- ClipperLib.ExPolygon()
- ClipperLib.ExPolygons()
- InitOptions
- ClipperLib.IntPoint()
- ClipperLib.IntRect()
- ClipperLib.JoinType
- ClipperLib.Path()
- ClipperLib.Paths()
- ClipperLib.PolyFillType
- ClipperLib.PolyType
- ClipperLib.Clipper.ZFillCallback()
- ClipperLib.ClipType()
- PolyTree
- --- PolyTree methods ---
- ClipperLib.PolyTree()
- ClipperLib.PolyTree.Clear()
- ClipperLib.PolyTree.GetFirst()
- ClipperLib.PolyTree.Total()
- PolyNode
- --- PolyNode methods ---
- ClipperLib.PolyNode()
- ClipperLib.PolyNode.ChildCount()
- ClipperLib.PolyNode.Childs()
- ClipperLib.PolyNode.Contour()
- ClipperLib.PolyNode.GetNext()
- ClipperLib.PolyNode.IsHole()
- ClipperLib.PolyNode.Parent()
- --- PolyNode properties ---
- ClipperLib.PolyNode.IsOpen
- ClipperOffset
- --- ClipperOffset methods ---
- ClipperLib.ClipperOffset()
- ClipperLib.ClipperOffset.AddPath()
- ClipperLib.ClipperOffset.AddPaths()
- ClipperLib.ClipperOffset.Clear()
- ClipperLib.ClipperOffset.Execute()
- --- ClipperOffset properties ---
- ClipperLib.ClipperOffset.ArcTolerance
- ClipperLib.ClipperOffset.MiterLimit
- Rounding
- JS
- --- JS methods ---
- ClipperLib.JS.AreaOfPolygon()
- ClipperLib.JS.AreaOfPolygons()
- ClipperLib.JS.BoundsOfPath()
- ClipperLib.JS.BoundsOfPaths()
- ClipperLib.JS.Clone()
- ClipperLib.JS.Clean()
- ClipperLib.JS.Lighten()
- ClipperLib.JS.PerimeterOfPath()
- ClipperLib.JS.PerimeterOfPaths()
- ClipperLib.JS.ScaleDownPath()
- ClipperLib.JS.ScaleDownPaths()
- ClipperLib.JS.ScaleUpPath()
- ClipperLib.JS.ScaleUpPaths()
- ClipperLib.JS.PolyTreeToExPolygons()
- ClipperLib.JS.ExPolygonsToPaths()
- Copyright
- ClipperLib.Clipper.ZFillFunction