doublecmd/components/Image32/source/Img32.Clipper2.pas
2025-03-23 21:11:06 +03:00

197 lines
6.5 KiB
ObjectPascal

unit Img32.Clipper2;
(*******************************************************************************
* Author : Angus Johnson *
* Version : 4.7 *
* Date : 6 January 2025 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2019-2025 *
* Purpose : Wrapper module for the Clipper library *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************)
interface
uses
Img32, Img32.Draw, Img32.Vector, Clipper.Offset;
//nb: InflatePath assumes that there's consistent winding where
//outer paths wind in one direction and inner paths in the other
type
TClipperEndType = Clipper.Offset.TEndType;
function ClipperEndType(endStyle: TEndStyle): TClipperEndType;
function InflatePath(const path: TPathD; delta: Double;
joinStyle: TJoinStyle = jsAuto; endType: TClipperEndType = etPolygon;
miterLimit: double = 2.0; arcTolerance: double = 0.0;
minEdgeLength: double = 0.25): TPathsD;
function InflatePaths(const paths: TPathsD; delta: Double;
joinStyle: TJoinStyle = jsAuto; endType: TClipperEndType = etPolygon;
miterLimit: double = 2.0; arcTolerance: double = 0.0;
minEdgeLength: double = 0): TPathsD;
//UnionPolygon: removes self-intersections
function UnionPolygon(const polygon: TPathD;
fillRule: TFillRule): TPathsD;
function UnionPolygons(const polygons: TPathsD;
fillRule: TFillRule): TPathsD; overload;
function UnionPolygons(const polygon1, polygon2: TPathD;
fillRule: TFillRule): TPathsD; overload;
function UnionPolygons(const polygons1, polygons2: TPathsD;
fillRule: TFillRule): TPathsD; overload;
function IntersectPolygons(const polygons1, polygons2: TPathsD;
fillRule: TFillRule): TPathsD;
function DifferencePolygons(const polygons1, polygons2: TPathsD;
fillRule: TFillRule): TPathsD;
const
etPolygon = Clipper.Offset.etPolygon;
etJoined = Clipper.Offset.etJoined;
etButt = Clipper.Offset.etButt;
etSquare = Clipper.Offset.etSquare;
etRound = Clipper.Offset.etRound;
implementation
uses Clipper, Clipper.Core, Clipper.Engine;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
function ClipperEndType(endStyle: TEndStyle): TClipperEndType;
begin
case endStyle of
esPolygon: Result := etJoined;
esButt: Result := etButt;
esSquare: Result := etSquare;
else Result := etRound;
end;
end;
//------------------------------------------------------------------------------
function InflatePath(const path: Img32.TPathD;
delta: Double; joinStyle: TJoinStyle; endType: TClipperEndType;
miterLimit: double; arcTolerance: double; minEdgeLength: double): Img32.TPathsD;
var
paths: Img32.TPathsD;
begin
setLength(paths, 1);
paths[0] := path;
Result := InflatePaths(paths, delta, joinStyle, endType,
miterLimit, arcTolerance, minEdgeLength);
end;
//------------------------------------------------------------------------------
function InflatePaths(const paths: Img32.TPathsD;
delta: Double; joinStyle: TJoinStyle; endType: TClipperEndType;
miterLimit: double; arcTolerance: double; minEdgeLength: double): Img32.TPathsD;
var
jt: Clipper.Offset.TJoinType;
begin
case joinStyle of
jsSquare : jt := jtSquare;
jsButt : jt := jtBevel;
jsMiter : jt := jtMiter;
jsRound : jt := jtRound;
else if endType = etRound then jt := jtRound
else jt := jtSquare;
end;
Result := Img32.TPathsD(Clipper.InflatePaths(
Clipper.Core.TPathsD(paths), delta, jt, endType));
end;
//------------------------------------------------------------------------------
function UnionPolygon(const polygon: Img32.TPathD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathD(polygon));
Execute(ctUnion,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
function UnionPolygons(const polygons: Img32.TPathsD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathsD(polygons));
Execute(ctUnion,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
function UnionPolygons(const polygon1, polygon2: Img32.TPathD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathD(polygon1));
AddClip(Clipper.Core.TPathD(polygon2));
Execute(ctUnion,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
function UnionPolygons(const polygons1, polygons2: Img32.TPathsD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathsD(polygons1));
AddClip(Clipper.Core.TPathsD(polygons2));
Execute(ctUnion,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
function IntersectPolygons(const polygons1, polygons2: Img32.TPathsD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathsD(polygons1));
AddClip(Clipper.Core.TPathsD(polygons2));
Execute(ctIntersection,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
function DifferencePolygons(const polygons1, polygons2: Img32.TPathsD;
fillRule: Img32.Vector.TFillRule): Img32.TPathsD;
begin
with TClipperD.Create do
try
AddSubject(Clipper.Core.TPathsD(polygons1));
AddClip(Clipper.Core.TPathsD(polygons2));
Execute(ctDifference,
Clipper.Core.TFillRule(fillRule), Clipper.Core.TPathsD(result));
finally
Free;
end;
end;
//------------------------------------------------------------------------------
end.