<!DOCTYPE html> <html> <head> <title>Javascript Clipper Library / Open and closed paths</title> <script src="clipper.js"></script> <style> h3{ margin-bottom:2px} body,th,td,input,legend,fieldset,p,b,button,select,textarea { font-size: 14px; font-family: Arial, Helvetica, sans-serif; } </style> <script> var subj_lines = [[{"X":34.5,"Y":24},{"X":93,"Y":86},{"X":168,"Y":119},{"X":250,"Y":79},{"X":308,"Y":23}],[{"X":47.5,"Y":196},{"X":55,"Y":170},{"X":68,"Y":152},{"X":84,"Y":133},{"X":103,"Y":118},{"X":124,"Y":107},{"X":150,"Y":97},{"X":168,"Y":95},{"X":189,"Y":96},{"X":215,"Y":101},{"X":232,"Y":109},{"X":251,"Y":119},{"X":269,"Y":134},{"X":285,"Y":151},{"X":296,"Y":167},{"X":303,"Y":185},{"X":305,"Y":196}]]; var clip_polygons = [[{"X":174.37,"Y":190.93},{"X":167.69,"Y":190.88},{"X":154.56,"Y":190.27},{"X":141.76,"Y":189.06},{"X":129.34,"Y":187.3},{"X":117.32,"Y":185},{"X":105.76,"Y":182.19},{"X":94.69,"Y":178.89},{"X":84.15,"Y":175.14},{"X":79.12,"Y":173.09},{"X":15.37,"Y":185.29},{"X":38.27,"Y":147.83},{"X":35.6,"Y":145.29},{"X":30.75,"Y":140.06},{"X":26.52,"Y":134.63},{"X":22.92,"Y":129.02},{"X":19.98,"Y":123.25},{"X":17.74,"Y":117.32},{"X":16.21,"Y":111.26},{"X":15.44,"Y":105.07},{"X":15.37,"Y":101.93},{"X":15.41,"Y":99.63},{"X":15.82,"Y":95.08},{"X":16.63,"Y":90.59},{"X":17.84,"Y":86.18},{"X":20.32,"Y":79.68},{"X":24.96,"Y":71.32},{"X":31,"Y":63.33},{"X":38.34,"Y":55.77},{"X":46.91,"Y":48.66},{"X":56.63,"Y":42.07},{"X":67.42,"Y":36.03},{"X":79.2,"Y":30.59},{"X":91.89,"Y":25.79},{"X":105.41,"Y":21.68},{"X":119.67,"Y":18.3},{"X":134.61,"Y":15.7},{"X":150.14,"Y":13.92},{"X":166.17,"Y":13.01},{"X":174.37,"Y":12.93},{"X":182.57,"Y":13.01},{"X":198.61,"Y":13.92},{"X":214.13,"Y":15.7},{"X":229.07,"Y":18.3},{"X":243.34,"Y":21.68},{"X":256.85,"Y":25.79},{"X":269.54,"Y":30.59},{"X":281.32,"Y":36.03},{"X":292.11,"Y":42.07},{"X":301.83,"Y":48.66},{"X":310.4,"Y":55.76},{"X":317.75,"Y":63.33},{"X":323.78,"Y":71.31},{"X":328.43,"Y":79.67},{"X":330.91,"Y":86.17},{"X":332.11,"Y":90.59},{"X":332.93,"Y":95.08},{"X":333.34,"Y":99.63},{"X":333.37,"Y":101.93},{"X":333.34,"Y":104.23},{"X":332.93,"Y":108.78},{"X":332.11,"Y":113.27},{"X":330.91,"Y":117.69},{"X":328.43,"Y":124.19},{"X":323.78,"Y":132.55},{"X":317.75,"Y":140.54},{"X":310.4,"Y":148.1},{"X":301.83,"Y":155.2},{"X":292.11,"Y":161.8},{"X":281.32,"Y":167.84},{"X":269.54,"Y":173.28},{"X":256.85,"Y":178.08},{"X":243.34,"Y":182.19},{"X":229.07,"Y":185.57},{"X":214.13,"Y":188.17},{"X":198.61,"Y":189.95},{"X":182.57,"Y":190.86}],[{"X":121.74,"Y":155.91},{"X":148.3,"Y":136.11},{"X":101.83,"Y":101.4},{"X":148.3,"Y":66.72},{"X":121.73,"Y":46.88},{"X":48.72,"Y":101.4}],[{"X":228.6,"Y":155.88},{"X":301.63,"Y":101.35},{"X":228.6,"Y":46.88},{"X":202.06,"Y":66.71},{"X":248.54,"Y":101.39},{"X":202.06,"Y":136.06}]]; var scale = 100; ClipperLib.JS.ScaleUpPaths(subj_lines, scale); ClipperLib.JS.ScaleUpPaths(clip_polygons, scale); function draw_open_closed(delta, title, combined) { cont.innerHTML += "<br><h3>" + title + "</h3>"; var cpr = new ClipperLib.Clipper(); cpr.AddPaths(subj_lines, ClipperLib.PolyType.ptSubject, false); cpr.AddPaths(clip_polygons, ClipperLib.PolyType.ptClip, true); var subject_fillType = ClipperLib.PolyFillType.pftNonZero; var clip_fillType = ClipperLib.PolyFillType.pftNonZero; var clipTypes = [ClipperLib.ClipType.ctUnion, ClipperLib.ClipType.ctDifference, ClipperLib.ClipType.ctXor, ClipperLib.ClipType.ctIntersection]; var clipTypesTexts = "Union, Difference, Xor, Intersection"; var solution_polygons, svg; var i; for (i = 0; i < clipTypes.length; i++) { solution_polytree = new ClipperLib.PolyTree(); cpr.Execute(clipTypes[i], solution_polytree, subject_fillType, clip_fillType); var solution_lines = ClipperLib.Clipper.OpenPathsFromPolyTree(solution_polytree); var solution_polygons = ClipperLib.Clipper.ClosedPathsFromPolyTree(solution_polytree); if (delta == 0) { svg = '<svg width="350" height="222" style="margin-top:10px; margin-right:10px;margin-bottom:10px;background-color:#dddddd">'; svg += '<path stroke="black" fill="yellow" stroke-width="2" d="' + paths2string(solution_polygons, scale) + '"/>'; svg += '<path stroke="red" fill="none" stroke-width="2" d="' + lines2string(solution_lines, scale) + '"/>'; svg += '</svg>'; } else { var co = new ClipperLib.ClipperOffset(2, 0.25); co.AddPaths(solution_polygons, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon); var solution_polytree = new ClipperLib.PolyTree(); co.Execute(solution_polytree, delta * scale); solution_polygons = ClipperLib.Clipper.PolyTreeToPaths(solution_polytree, solution_polygons); if (!combined) co.Clear(); co.AddPaths(solution_lines, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etOpenRound); var solution_lines_polytree = new ClipperLib.PolyTree(); co.Execute(solution_lines_polytree, delta * scale); solution_lines = ClipperLib.Clipper.PolyTreeToPaths(solution_lines_polytree, solution_lines); svg = '<svg width="350" height="222" style="margin-top:10px; margin-right:10px;margin-bottom:10px;background-color:#dddddd">'; svg += '<path stroke="black" fill="yellow" stroke-width="2" d="' + paths2string(solution_polygons, scale) + '"/>'; svg += '<path stroke="black" fill="red" stroke-width="2" d="' + paths2string(solution_lines, scale) + '"/>'; svg += '</svg>'; //console.log(JSON.stringify(solution_polygons)); //console.log(JSON.stringify(solution_lines)); } cont.innerHTML += svg; } cont.innerHTML += "<br>" + clipTypesTexts + "<br>"; } // Converts Paths to SVG path string // and scales down the coordinates function paths2string(paths, scale, isline) { var svgpath = "", i, j; if (!scale) scale = 1; for (i = 0; i < paths.length; i++) { for (j = 0; j < paths[i].length; j++) { if (!j) svgpath += "M"; else svgpath += "L"; svgpath += (paths[i][j].X / scale) + ", " + (paths[i][j].Y / scale); } if (!isline) svgpath += "Z"; } if (svgpath == "") svgpath = "M0,0"; return svgpath; } // converts lines to SVG path string function lines2string(poly, scale) { return paths2string(poly, scale, true); } </script> </head> <body onload="cont = document.getElementById('svgcontainer');; draw_open_closed(0,'Open and closed, Booleans'); draw_open_closed(5, 'Open and closed, Positive offset'); draw_open_closed(5, 'Open and closed, Combined, Positive offset', true); draw_open_closed(-5, 'Open and closed, Negative offset')"> <!-- Boolean test Offset test Open/Closed paths test PolyTree Area test Get bounds test --> <h2>Javascript Clipper Library / Open and closed paths</h2> <div id="svgcontainer" style="width:1500px"></div> </body> </html>