Skip to content

Commit e0fed65

Browse files
committed
Initial check-in of boolean operation test code, created by @hkrish
0 parents  commit e0fed65

24 files changed

+610936
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.DS_Store
2+
*.nb
3+
*.tern-port
4+
out*/

.tern-project

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"libs": [
3+
"node",
4+
"ecma5",
5+
"jquery"
6+
],
7+
"loadEagerly": [
8+
"../paperjs/src/**/*.js"
9+
],
10+
"plugins": {
11+
"requirejs": {
12+
"baseURL": "./",
13+
"paths": {}
14+
}
15+
}
16+
}

all.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
node boolean-test.js data/union.json
3+
node boolean-test.js data/intersection.json
4+
node boolean-test.js data/subtraction.json

boolean-test.js

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
2+
var utils = require("./utils.js").Utils;
3+
var paper = require("./paperjs/src/load.js");
4+
var colors = require('colors');
5+
var fs = require("fs");
6+
7+
var precision = {
8+
point: 0.01,
9+
area: 20,
10+
bitmap: 20
11+
};
12+
13+
var testModes = {
14+
paths: false,
15+
curves: false,
16+
area: true,
17+
bitmap: true
18+
};
19+
20+
var width = 600, height = 600;
21+
var canvas = new paper.Canvas(width, height);
22+
var ctx = canvas.getContext("2d");
23+
24+
paper.setup(canvas);
25+
26+
var fname = "", fSplit = /(\\|\/)?(.*(\\|\/))*(.*).json/i,
27+
testName, suit, testCount, timeDiff, fn,
28+
casesDone = 0, casesPassed = 0, casesFailed = 0,
29+
i, j, li, lj, cases, tCase, op1, op2, res, resOriginal,
30+
testResult = {}, testRunCount = 0, boolTime = 0, txt,
31+
// Define styles for previewing
32+
style1 = { fillColor: null, strokeColor: new paper.Color(0,0,0) },
33+
style2 = { strokeColor: new paper.Color(1,0,0), fillColor: new paper.Color(1,0,0, 0.4) },
34+
styleBlack = { strokeColor: null, fillColor: new paper.Color(0,0,0) },
35+
styleNull = { strokeColor: null, fillColor: null },
36+
// Export failed cases
37+
failCases = { cases: [] };
38+
39+
// Process args
40+
if(process.argv.length < 3){
41+
console.log("Usage : node boolean-test.js <filename> [options]")
42+
return;
43+
}
44+
45+
var fname = "/" + process.argv[2];
46+
testName = fSplit.exec(fname)[4];
47+
48+
// Load the test suit
49+
utils.log("Loading test suit \"" + testName + "\"...");
50+
utils.timer.start("load");
51+
suit = utils.loadJSONfile(__dirname + fname);
52+
fn = suit.fn;
53+
suit = suit.tests;
54+
timeDiff = utils.timer.end("load", "ms").toFixed(1);
55+
// Find the cumulative test count
56+
testCount = suit.reduce(function(sum, a){ return sum + a.cases.length }, 0);
57+
utils.log(testCount + " tests loaded from test suit \"" + testName + "\"; in " + timeDiff + " ms.");
58+
59+
console.log();
60+
utils.log("Testing paperjs " + fn + " operator.", testName);
61+
62+
63+
// begin the actual test
64+
// TODO: modularize!
65+
utils.progress.setup(testName, testCount);
66+
utils.timer.start("test");
67+
var vectorTest, rasterTest;
68+
for (i = 0, li = suit.length; i < li; i++) {
69+
op1 = utils.getPath(paper, suit[i].op1);
70+
cases = suit[i].cases;
71+
// console.log(suit[i].name);
72+
for (j = 0, lj = cases.length; j < lj; j++) {
73+
// DEBUG:============================================================
74+
// console.log(cases[j].name);
75+
// DEBUG:============================================================
76+
tCase = cases[j];
77+
op2 = utils.getPath(paper, tCase.op2);
78+
resOriginal = utils.getPath(paper, tCase.res);
79+
80+
// Perform the paperjs boolean op
81+
utils.timer.start("bool");
82+
if(fn === "subtract")
83+
res = op2[fn](op1);
84+
else
85+
res = op1[fn](op2);
86+
boolTime += utils.timer.end("bool", "ms");
87+
88+
++casesDone;
89+
vectorTest = compare(res, resOriginal, precision, testResult);
90+
rasterTest = testRasterArea();
91+
if(vectorTest && rasterTest)
92+
++casesPassed;
93+
else{
94+
++casesFailed;
95+
// Save this failed cases
96+
failCases.cases.push({
97+
"name" : suit[i].name + "_" + tCase.name,
98+
"fn" : fn,
99+
"op1" : suit[i].op1,
100+
"op2" : tCase.op2,
101+
"res" : tCase.res,
102+
});
103+
// Save a preview file of the failed case
104+
resOriginal.style = style1;
105+
res.style = style2;
106+
txt = new paper.PointText([10, 20]);
107+
txt.content = (testModes.paths ? "children: " + testResult.child + "(" + testResult.ch1 + ", " + testResult.ch2 + ")" : "") +
108+
(testModes.curves ? ", curves: " + testResult.curves : "") +
109+
(testModes.area ? ", area: " + testResult.area : "");
110+
txt.fillColor = "#000";
111+
paper.view.draw();
112+
fs.writeFileSync(__dirname + "/out/test_" + testName + "_" + suit[i].name + "_" + tCase.name + ".png", canvas.toBuffer());
113+
if(testModes.bitmap)
114+
testRasterArea(__dirname + "/out/test_" + testName + "_" + suit[i].name + "_" + tCase.name + "_v.png", canvas.toBuffer());
115+
txt.remove();
116+
}
117+
// console.log(testResult);
118+
119+
++testRunCount;
120+
op1.remove();
121+
op2.remove();
122+
res.remove();
123+
resOriginal.remove();
124+
utils.progress.update(casesDone, casesPassed, casesFailed);
125+
}
126+
}
127+
timeDiff = formatTimeIvl(utils.timer.end("test", "ms"));
128+
utils.progress.close();
129+
130+
// Save the failed cases to disk, if any.
131+
if(failCases.cases.length){
132+
if(testName)
133+
fs.writeFileSync(__dirname + "/out/" + testName + "-fail.json", JSON.stringify(failCases));
134+
}
135+
136+
// Print the test report
137+
console.log();
138+
console.log(" Test Report [" + testName + "]");
139+
console.log("----------------------------------------------------");
140+
console.log(" Tests run - " + testRunCount.toString());
141+
console.log(" Tests passed - " + casesPassed.toString().green + " " + (casesPassed * 100.0/testRunCount).toFixed(1) + "%");
142+
console.log(" Tests failed - " + casesFailed.toString().red + " " + (casesFailed * 100.0/testRunCount).toFixed(1) + "%");
143+
console.log();
144+
console.log(" Elapsed - " + timeDiff);
145+
console.log(" Boolean op. time - " + formatTimeIvl(boolTime));
146+
console.log(" Boolean avg. time - " + formatTimeIvl(boolTime / testRunCount));
147+
console.log();
148+
// --END--
149+
150+
// Compare raster
151+
function testRasterArea(saveFileName) {
152+
if (!testModes.bitmap)
153+
return true;
154+
155+
res.style = resOriginal.style = styleNull;
156+
paper.view.draw();
157+
ctx.antialias = 'none';
158+
resOriginal.style = res.style = styleBlack;
159+
res.blendMode = 'xor';
160+
paper.view.draw();
161+
// Accumulated pixels
162+
var cumul = 0;
163+
// Run the test
164+
if(!saveFileName){
165+
var image = ctx.getImageData(0, 0, width, height),
166+
pixels = image.data, cw = image.width * 4, ch = image.height,
167+
imgi, imgj;
168+
for (imgj = 0; imgj < ch; imgj++) {
169+
var pixrow = imgj * cw;
170+
for (imgi = 0; imgi < cw; imgi += 4) {
171+
if(pixrow[pixrow + imgi])
172+
++cumul;
173+
}
174+
}
175+
} else
176+
// Save the bitmap
177+
fs.writeFileSync(saveFileName, canvas.toBuffer());
178+
179+
// Reset the default values
180+
ctx.antialias = 'default';
181+
res.blendMode = 'normal';
182+
183+
return cumul < precision.bitmap;
184+
}
185+
186+
// Compare two paths
187+
function compare(p1, p2, precision, results) {
188+
var eqChild = false, eqCurves = false, eqArea = false,
189+
ch1 = p1 instanceof paper.CompoundPath ? p1.children.length : 1,
190+
ch2 = p2 instanceof paper.CompoundPath ? p2.children.length : 1,
191+
crv1 = p1.getCurves(), crv2 = p2.getCurves(),
192+
a1 = Math.abs(p1.getArea()) | 0, a2 = Math.abs(p2.getArea()) | 0;
193+
194+
eqChild = ch1 === ch2;
195+
eqCurves = crv1.length === crv2.length;
196+
eqArea = Math.abs(a1 - a2) < precision.area;
197+
198+
if (results){
199+
results.child = eqChild;
200+
results.ch1 = ch1;
201+
results.ch2 = ch2;
202+
results.curves = eqCurves;
203+
results.area = eqArea;
204+
}
205+
206+
return (!testModes.paths || eqChild) && (!testModes.curves || eqCurves) && (!testModes.area || eqArea);
207+
}
208+
209+
function formatTimeIvl(tms) {
210+
var ts = 0, tm = 0;
211+
if (tms > 1000){
212+
ts = (tms / 1000.0) | 0;
213+
tms -= ts * 1000;
214+
}
215+
if (ts > 60){
216+
tm = (ts / 60.0) | 0;
217+
ts -= tm * 60;
218+
}
219+
return tm + " : " + ts + " : " + tms.toFixed(1);
220+
}

0 commit comments

Comments
 (0)