ClipperOffset


Geometric offsetting refers to the process of creating parallel curves that are offset a specified distance from their primary curves.

The ClipperOffset class manages the process of offsetting (inflating/deflating) both open and closed paths using a number of different join types and end types. The library user will rarely need to access this unit directly since it will generally be easier to use the InflatePaths function when doing polygon offsetting.

Notes:

  1. When offsetting closed paths (polygons), a positive offset delta specifies how much outer polygon contours will expand and how much inner "hole" contours will contract. The converse occurs with negative deltas. (Outer polygons should all have the same winding orientation, and holes should have the opposite orientation.)
  2. You cannot offset open paths (polylines) with negative deltas because it's not possible to contract/shrink open paths.
  3. When offsetting, it's important not to confuse EndType.Polygon with EndType.Joined.
    EndType.Polygon should be used when offsetting polygons (closed paths).
    EndType.Joined should be used with polylines (open paths).

  4. Offsetting should not be performed on intersecting closed paths, as doing so will almost always produce undesirable results.
      PathsD pp { MakePathD({ 40,40, 360,360, 360,40, 40,360 }) };
      PathsD sol = InflatePaths(pp, 40, JoinType::Square, EndType::Polygon);
      
    
            

    Intersections must be removed before offsetting, and this can be achieved through a Union clipping operation.
      PathsD pp { MakePathD({ 40,40, 360,360, 360,40, 40,360 }) };
      pp = Union(pp, FillRule::NonZero);
      PathsD sol = InflatePaths(pp, 40, JoinType::Square, EndType::Polygon);  
    
            

    And it's not just self-intersections that must be avoided, offsetting any paths that intersect will very likely produce undesirable results.
     
  5. It is, however, quite OK to offset self-intersecting open paths (polylines), though the intersecting (ie overlapping) regions will be flattened in the solution polygon. This is demonstrated in the following example:
      PathsD paths = PathsD{ MakePathD({10,10, 100,200, 10,200, 100,10}) };
      PathsD sol = InflatePaths(paths, 10, JoinType::Round, EndType::Round);
      
    
            

  6. When offsetting closed paths (polygons), the winding direction of paths in the solution will match that of the paths prior to offsetting. Because of this, polygons with hole regions should comply with NonZero filling.
  7. When offsetting open paths (polylines), the solutions will always have Positive orientation.
  8. Path order following offsetting very likely won't match path order prior to offsetting.
  9. While the ClipperOffset class itself won't accept paths with floating point coordinates, the InflatePaths function that encapsulates the functionality of this class will accept paths with floating point coordinates. (The float-integer conversions will be performed by the InflatePaths function.)
  10. Paths often contain redundant segments that don't contribute to path shape. These segments are either extremely short (< 2 units), or extremely short relative to their adjacent segments. These redundant segments not only slow down offsetting, but they can cause unexpected blemishes in offset solutions (see an example here). So redundant segments should be removed before offsetting (see SimplifyPaths), and between offsetting operations too. (Why aren't redundant segments removed as part of the offset procedure? Because users don't want that additional overhead when they know their paths are free of redundant segments.)

C++ Example:
#include "clipper2/clipper.h"  
...
using namespace Clipper2Lib;

int main()
{
  Paths64 subject;
  subject.push_back(MakePath({ 3480,2570, 3640,1480, 
    3620,1480, 3260,2410, 2950,2190, 2580,880, 
    4400,1290, 3700,1960, 3720,2750 }));
  Paths64 solution;
  ClipperOffset offsetter;
  offsetter.AddPaths(subject, JoinType::Round, EndType::Polygon);
  offsetter.Execute(-70, solution);
  solution = SimplifyPaths(solution, 2.5);
  
  //draw solution ...
  DrawPolygons(solution, 0x4000FF00, 0xFF009900);
}
      

Reference

Methods Properties
AddPath ArcTolerance
AddPaths MiterLimit
Clear ReverseSolution
Constructor
Execute

See Also

InflatePaths, IsPositive, SimplifyPaths, Union, EndType, FillRule