Boolean: Implement options.trace, and add unit tests for options.trace = false

Relates to #1221
This commit is contained in:
Jürg Lehni 2017-03-22 15:03:11 +01:00
parent ffa7e16f48
commit 3c9d2eea1d
3 changed files with 77 additions and 15 deletions

View file

@ -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);
},
/**

View file

@ -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;

View file

@ -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]);