ClipperLib

repository·master·Indexed 42 days ago

https://github.com/junmer/clipper-lib

A JavaScript port of the Clipper library for robust polygon and line clipping, offsetting, and boolean operations. Version 6.4.2 provides tools for intersection, union, difference, and XOR operations, as well as Minkowski Sum and Difference, using integer coordinates for numerical robustness.

Tokens
9.7K
Snippets
46
Records
51
Agent score
3%

What's inside ClipperLib

  1. Overview of ClipperLib capabilities

    master

    ClipperLib is a Javascript library used for the clipping and offsetting of lines and polygons. It is designed to be numerically robust and fast, supporting various polygon filling rules.

    Key Terminology

    • Clipping: The process of performing boolean operations (Intersection, Union, Difference, or Exclusive-OR) between geometric shapes. While often used to refer to a rectangular window, in Clipper it refers to any boolean operation between subject and clipping paths.
    • Path: An ordered sequence of vertices defining a geometric contour. It can be an open path (a line/polyline) or a closed path (a polygon).
    • Polygon: A closed path that may contain zero or more holes.
    • Hole: A closed region within a polygon that is not part of the polygon itself.
    • Filling Rule: A rule (e.g., EvenOdd, NonZero) that defines which regions bounded by paths are considered 'inside' (filled) versus 'outside'.
  2. What is a PolyTree and when to use it

    master

    A PolyTree is a read-only data structure used to receive solutions from polygon clipping operations. It is an alternative to the Paths structure.

    **Use PolyTree when you need to:

    1. Represent parent-child relationships between polygons (e.g., knowing which hole belongs to which outer polygon).
    2. Differentiate between open and closed paths.

    Note on Performance: PolyTree is more computationally expensive than Paths. The Execute method using a PolyTree is roughly 5-10% slower. Use it only when the hierarchical relationship or open paths are required.

  3. Understand PolyNode and PolyTree hierarchy

    master

    In Clipper, PolyNode objects are used to represent individual polygons within a PolyTree container. This structure preserves the parent-child relationships of polygon contours returned by the Clipper.Execute method.

    Key Concepts:

    • Hierarchy: A PolyNode can own multiple child PolyNode objects. The relationship alternates: children of outer polygons are holes, and children of holes are nested outer polygons.
    • IsHole: The IsHole() property indicates if the polygon is a hole or an outer polygon.
    • PolyTree Root: A PolyTree object is itself a PolyNode (the root), but its IsHole() property is undefined. Its children are always top-level outer polygons.
    // Example of the hierarchical relationship
    // Outer Polygon -> Hole -> Nested Outer Polygon
  4. How the Clipper class works for polygon clipping

    master

    The Clipper class is the core of the library, used to perform boolean operations on polygons (intersection, union, difference, and XOR), a process known as polygon clipping.

    To use it, you follow this workflow:

    1. Create a new Clipper instance.
    2. Pass input polygons (both the 'subject' set and the 'clip' set) to the instance using AddPath or AddPaths.
    3. Call the Execute method to perform the specified clipping operation.

    You can perform multiple different boolean operations on the same set of input polygons by calling Execute multiple times with different ClipType parameters.

    var c = new ClipperLib.Clipper();
    // Add subject paths
    c.AddPaths(subj, ClipperLib.PolyType.ptSubject, true);
    // Add clip paths
    c.AddPaths(clip, ClipperLib.PolyType.ptClip, true);
    // Execute operation
    var solution = new ClipperLib.Paths();
    c.Execute(ClipperLib.ClipType.ctIntersection, solution);
  5. Understand Path and Paths structures

    master

    The library uses two fundamental structures to manage geometry:

    1. Path: A sequence of IntPoint vertices defining a single contour. Paths can be open (representing line segments with 2+ vertices) or closed (representing polygons).
    2. Paths: An array of one or more Path structures. This is the primary container for multiple contours.

    In JavaScript, both can be initialized as empty arrays [] or via their respective constructors.

    // Creating a Path (single contour)
    var path = new ClipperLib.Path(); 
    // or
    var path = [];
    
    // Creating Paths (multiple contours)
    var paths = new ClipperLib.Paths();
    // or
    var paths = [];
  6. How ClipperOffset works for inflating and deflating paths

    master

    The ClipperOffset class is used to offset (inflate or deflate) both open and closed paths. This replaces the deprecated OffsetPaths function and offers more flexibility, such as performing offsetting on a mixture of open and closed paths in a single operation.

    Key Requirements for Closed Paths (Polygons):

    1. Consistent Orientation: Outer polygons must share the same orientation, while holes must have the opposite orientation.
    2. No Self-Intersection: Paths must not self-intersect.

    Core Workflow:

    1. Instantiate ClipperOffset with optional MiterLimit and ArcTolerance.
    2. Add paths using AddPath() or AddPaths() specifying the JoinType and EndType.
    3. Call Execute() with a delta value. A positive delta expands the paths, while a negative delta shrinks them.
    4. Use Clear() to reset the object for new paths.
    var co = new ClipperLib.ClipperOffset(2.0, 0.25);
    co.AddPath(path, ClipperLib.JoinType.jtMiter, ClipperLib.EndType.etClosedPolygon);
    co.Execute(solution, -7.0); // Shrink by 7 units
  7. How PolyTree structure works

    master

    A PolyTree acts as a container for PolyNode children.

    • Hierarchy: The PolyTree itself is a specialized PolyNode with an empty Contour. Its immediate children are top-level outer polygons.
    • Nesting Rules: Children of outer polygons are always holes, and children of holes are always outers. This creates a nested tree structure.
    • Open Paths: Open paths are always represented by top-level PolyNodes.
    • Separation: You can use ClosedPathsFromPolyTree and OpenPathsFromPolyTree to quickly separate closed and open paths from a single PolyTree.
  8. Traverse a PolyTree using GetFirst and GetNext

    master

    You can easily traverse all nodes in a PolyTree by starting with GetFirst() and following the GetNext() pointers in a loop until you reach a null pointer. GetNext() returns the first child if one exists; otherwise, it returns the next sibling, or the next sibling of the parent, and so on.

    var polytree = new ClipperLib.PolyTree();
    // call to Clipper.Execute method here which fills 'polytree'
    
    var polynode = polytree.GetFirst();
    while (polynode)
    {
      // do stuff with polynode here
    
      polynode = polynode.GetNext();
    }
  9. Configure ClipperLib preprocessor defines

    master

    You can control certain library behaviors by setting specific boolean variables. Note that these are implemented as variables in the Javascript environment.

    • use_xyz: Adds a 'Z' member to IntPoint. Useful for 3D-related logic but has a minor performance cost. (Disabled by default)
    • use_lines: Enables open path (line) clipping. Disabling this can provide a ~5% performance improvement if you only work with closed polygons. (Enabled by default)
    • use_deprecated: Enables compatibility code for projects migrating from versions prior to Clipper 6. (Enabled by default)
    • use_int32: Not implemented in the Javascript version.
    var use_xyz = true;
    var use_lines = true;
    var use_deprecated = true;
  10. Calculate perimeter with ClipperLib.JS.PerimeterOfPath() and PerimeterOfPaths()

    master

    Calculates the perimeter of paths. If a scale is provided, the function returns the downscaled perimeter.

    • PerimeterOfPath(path, closed, scale):
      • If closed is true (polygon), it treats the path as closed by connecting the last vertex to the first.
      • If closed is false (line), it measures only the existing vertices.
    • PerimeterOfPaths(paths, closed, scale): Returns the sum of perimeters for all paths in the collection.
    var path = [{X:10,Y:10},{X:110,Y:10},{X:110,Y:110},{X:10,Y:110}];
    var polygonal_perimeter = ClipperLib.JS.PerimeterOfPath(path, true, 1);
    // polygonal_perimeter is 400
    
    var line_perimeter = ClipperLib.JS.PerimeterOfPath(path, false, 1);
    // line_perimeter is 300
  11. Use ClipperOffset.Execute() to perform offsetting

    master

    The Execute method performs the actual offsetting operation. It accepts two different result structures and a delta value.

    Signatures:

    • void Execute(Paths solution, Number delta)
    • void Execute(PolyTree polytree, Number delta)

    Parameters:

    • solution: The Paths or PolyTree object that will receive the resulting offset paths.
    • delta: The offset amount. Positive values expand the paths; negative values shrink them.

    Important: Coordinate Scaling Because Clipper operates on integer coordinates, you must scale your floating-point coordinates up before offsetting and scale them back down after to maintain precision and ensure smooth arcs. This is especially critical when using jtRound or etOpenRound.

    Use ClipperLib.JS.ScaleUpPaths and ClipperLib.JS.ScaleDownPaths for this process.

    var subj = new ClipperLib.Paths();
    // ... populate subj with coordinates ...
    var scale = 100;
    ClipperLib.JS.ScaleUpPaths(subj, scale);
    
    var co = new ClipperLib.ClipperOffset(2, 0.25);
    var solution = new ClipperLib.Paths();
    co.AddPaths(subj, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
    co.Execute(solution, -7.0);
    
    ClipperLib.JS.ScaleDownPaths(solution, scale);
    // Now 'solution' contains the scaled-down results