From 3c9d2eea1d7de509974e7b995a9a578a646ca6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Wed, 22 Mar 2017 15:03:11 +0100 Subject: [PATCH] Boolean: Implement options.trace, and add unit tests for options.trace = false Relates to #1221 --- src/path/PathItem.Boolean.js | 20 ++++++------ test/helpers.js | 13 ++++++-- test/tests/Path_Boolean.js | 59 ++++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index 8918df64..8bfa38f0 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -78,12 +78,12 @@ PathItem.inject(new function() { return result; } - function computeBoolean(path1, path2, operation, options) { + function traceBoolean(path1, path2, operation, options) { // Only support subtract and intersect operations when computing stroke - // based boolean operations. - if (options && options.stroke && + // based boolean operations (options.split = true). + if (options && (options.trace == false || options.stroke) && /^(subtract|intersect)$/.test(operation)) - return computeStrokeBoolean(path1, path2, operation === 'subtract'); + return splitBoolean(path1, path2, operation === 'subtract'); // We do not modify the operands themselves, but create copies instead, // fas produced by the calls to preparePath(). // NOTE: The result paths might not belong to the same type i.e. @@ -160,7 +160,7 @@ PathItem.inject(new function() { return createResult(CompoundPath, paths, true, path1, path2, options); } - function computeStrokeBoolean(path1, path2, subtract) { + function splitBoolean(path1, path2, subtract) { var _path1 = preparePath(path1), _path2 = preparePath(path2), crossings = _path1.getCrossings(_path2), @@ -194,7 +194,7 @@ PathItem.inject(new function() { } // At the end, add what's left from our path after all the splitting. addPath(_path1); - return createResult(Group, paths, false, path1, path2); + return createResult(CompoundPath, paths, true, path1, path2); } /* @@ -1042,7 +1042,7 @@ PathItem.inject(new function() { * @return {PathItem} the resulting path item */ unite: function(path, options) { - return computeBoolean(this, path, 'unite', options); + return traceBoolean(this, path, 'unite', options); }, /** @@ -1060,7 +1060,7 @@ PathItem.inject(new function() { * @return {PathItem} the resulting path item */ intersect: function(path, options) { - return computeBoolean(this, path, 'intersect', options); + return traceBoolean(this, path, 'intersect', options); }, /** @@ -1078,7 +1078,7 @@ PathItem.inject(new function() { * @return {PathItem} the resulting path item */ subtract: function(path, options) { - return computeBoolean(this, path, 'subtract', options); + return traceBoolean(this, path, 'subtract', options); }, /** @@ -1094,7 +1094,7 @@ PathItem.inject(new function() { * @return {PathItem} the resulting group item */ exclude: function(path, options) { - return computeBoolean(this, path, 'exclude', options); + return traceBoolean(this, path, 'exclude', options); }, /** diff --git a/test/helpers.js b/test/helpers.js index ebfe7d61..85c6da48 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -144,9 +144,15 @@ var comparePixels = function(actual, expected, message, options) { function rasterize(item, group, resolution) { var raster = null; if (group) { + var parent = item.parent, + index = item.index; group.addChild(item); raster = group.rasterize(resolution, false); - item.remove(); + if (parent) { + parent.insertChild(index, item); + } else { + item.remove(); + } } return raster; } @@ -471,8 +477,9 @@ var compareBoolean = function(actual, expected, message, options) { } var style = { strokeColor: 'black', - fillColor: expected && - (expected.closed || expected.children && 'yellow') || null + fillColor: expected && (expected.closed + || expected.firstChild && expected.firstChild.closed && 'yellow') + || null }; if (actual) actual.style = style; diff --git a/test/tests/Path_Boolean.js b/test/tests/Path_Boolean.js index 632129f5..fd8a7a79 100644 --- a/test/tests/Path_Boolean.js +++ b/test/tests/Path_Boolean.js @@ -177,7 +177,7 @@ test('#719', function() { compareBoolean(result, expected); }); -test('#757 (path1.intersect(pat2, { stroke: true }))', function() { +test('#757 (path1.intersect(pat2, { trace: false }))', function() { var rect = new Path.Rectangle({ from: [100, 250], to: [350, 350] @@ -194,7 +194,7 @@ test('#757 (path1.intersect(pat2, { stroke: true }))', function() { ] }); - var res = line.intersect(rect, { stroke: true }); + var res = line.intersect(rect, { trace: false }); var children = res.removeChildren(); var first = children[0]; @@ -864,6 +864,61 @@ test('#1123', function() { 'M100,200v-100h100v100zM180,180v-60h-60v60z'); }); +test('#1221', function() { + var rect1 = new Path.Rectangle({ + point: [100, 100], + size: [200, 200] + }); + + var circle = new Path.Circle({ + center: [100, 100], + radius: 100 + }); + + compareBoolean(function() { return rect1.subtract(circle, { trace: false }); }, + 'M200,100h100v200h-200v-100'); + compareBoolean(function() { return rect1.subtract(circle, { trace: true }); }, + 'M100,300v-100c55.22847,0 100,-44.77153 100,-100h100v200z'); + + + var blob = PathItem.create("M534,273C171.7,111,60.5,117.1,30,158c-40.5,54.3,31.5,210.2,111,222c60.8,9,88-71.9,159-66c81.6,6.8,99.6,118.3,179,128c33.8,4.1,83.1-9.7,150-90") + var rect2 = new Path.Rectangle({ + point: [150, 100], + size: [300, 300] + }); + + compareBoolean(function() { return blob.subtract(rect2, { trace: false }); }, + 'M534,273c-29.65069,-13.2581 -57.61955,-25.39031 -84,-36.46967M150,138.13156c-71.67127,-11.53613 -105.25987,0.10217 -120,19.86844c-40.5,54.3 31.5,210.2 111,222c3.08303,0.45637 6.07967,0.68158 9,0.69867M409.85616,400c18.87105,20.95032 39.82014,38.41763 69.14384,42c33.8,4.1 83.1,-9.7 150,-90'); + compareBoolean(function() { return blob.subtract(rect2, { trace: true }); }, + 'M629,352c-66.9,80.3 -116.2,94.1 -150,90c-29.3237,-3.58237 -50.27279,-21.04968 -69.14384,-42h40.14384v-163.46967c26.38045,11.07937 54.34931,23.21157 84,36.46967M141,380c-79.5,-11.8 -151.5,-167.7 -111,-222c14.74013,-19.76627 48.32873,-31.40457 120,-19.86844v242.56712c-2.92033,-0.01709 -5.91697,-0.24231 -9,-0.69867z'); + + var rect3 = new Path.Rectangle({ + point: [150, 100], + size: [300, 150] + }); + + compareBoolean(function() { return blob.subtract(rect3, { trace: false }); }, + 'M534,273c-29.65069,-13.2581 -57.61955,-25.39031 -84,-36.46967M150,138.13156c-71.67127,-11.53613 -105.25987,0.10217 -120,19.86844c-40.5,54.3 31.5,210.2 111,222c60.8,9 88,-71.9 159,-66c81.6,6.8 99.6,118.3 179,128c33.8,4.1 83.1,-9.7 150,-90'); + compareBoolean(function() { return blob.subtract(rect3, { trace: true }); }, + 'M629,352c-66.9,80.3 -116.2,94.1 -150,90c-79.4,-9.7 -97.4,-121.2 -179,-128c-71,-5.9 -98.2,75 -159,66c-79.5,-11.8 -151.5,-167.7 -111,-222c14.74013,-19.76627 48.32873,-31.40457 120,-19.86844v111.86844h300v-13.46967c26.38045,11.07937 54.34931,23.21157 84,36.46967'); + + + var rect4 = new Path.Rectangle({ + point: [200, 200], + size: [400, 200] + }); + + var line = new Path.Line({ + from: [400, 300], + to: [400, 600] + }); + + var division = line.divide(rect4, { trace: false }); + equals(function() { return division.children.length; }, 2); + compareBoolean(function() { return division.children[0]; }, 'M400,400v200'); + compareBoolean(function() { return division.children[1]; }, 'M400,300v100'); +}); + test('#1239 / #1073', function() { var p1 = new Path([[890.91, 7.52, 0, 0, 85.40999999999997, 94.02], [1024, 351.78, 0, -127.03999999999996, 0, 127.14999999999998], [890.69, 696.28, 85.54999999999995, -94.03999999999996, 0, 0], [843.44, 653.28, 0, 0, 75.20000000000005, -82.66999999999996], [960, 351.78, 0, 111.75, 0, -111.63], [843.65, 50.51999999999998, 75.07000000000005, 82.63999999999999, 0, 0], true]); var p2 = new Path([[960, 352, -0.05999999999994543, 111.67999999999995, 0, 0], [1024, 352, 0, 0, -0.05999999999994543, 127.07], [890.69, 696.28, 85.5, -93.98000000000002, 0, 0], [843.44, 653.28, 0, 0, 75.14999999999998, -82.61000000000001], true]);