mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-08 05:42:07 -05:00
Resolve some bad clipping
This commit is contained in:
parent
e6a98b4f18
commit
3a881e3a14
2 changed files with 167 additions and 159 deletions
|
@ -200,8 +200,8 @@ function _clipBezierFatLine( v1, v2, v2t ){
|
||||||
if( dq3 < dq0 ){
|
if( dq3 < dq0 ){
|
||||||
tmp = dmin; dmin = dmax; dmax = tmp;
|
tmp = dmin; dmin = dmax; dmax = tmp;
|
||||||
}
|
}
|
||||||
// Calculate the convex hull for non-parametric bezier curve D(ti, di(t))
|
|
||||||
var Dt = _convexhull( dq0, dq1, dq2, dq3 );
|
var Dt = _convexhull( dq0, dq1, dq2, dq3 );
|
||||||
|
// Calculate the convex hull for non-parametric bezier curve D(ti, di(t))
|
||||||
// Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax
|
// Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax
|
||||||
// for the coorresponding t values (tmin, tmax):
|
// for the coorresponding t values (tmin, tmax):
|
||||||
// Portions of curve v2 before tmin and after tmax can safely be clipped away
|
// Portions of curve v2 before tmin and after tmax can safely be clipped away
|
||||||
|
@ -230,6 +230,14 @@ function _clipBezierFatLine( v1, v2, v2t ){
|
||||||
// Return the parameter values for v2 for which we can be sure that the
|
// Return the parameter values for v2 for which we can be sure that the
|
||||||
// intersection with v1 lies within.
|
// intersection with v1 lies within.
|
||||||
if(tmin !== Infinity && tmax !== -Infinity){
|
if(tmin !== Infinity && tmax !== -Infinity){
|
||||||
|
var mindmin = Math.min(dmin, dmax);
|
||||||
|
var mindmax = Math.max(dmin, dmax);
|
||||||
|
if( dq3 > mindmin && dq3 < mindmax ){
|
||||||
|
tmax = 1;
|
||||||
|
}
|
||||||
|
if( dq0 > mindmin && dq0 < mindmax ){
|
||||||
|
tmin = 0;
|
||||||
|
}
|
||||||
if( tmaxdmin > tmax ){ tmax = 1; }
|
if( tmaxdmin > tmax ){ tmax = 1; }
|
||||||
// Debug: Plot the non-parametric graph and hull
|
// Debug: Plot the non-parametric graph and hull
|
||||||
// plotD_vs_t( 500, 110, Dt, [dq0, dq1, dq2, dq3], v1, dmin, dmax, tmin, tmax, 1.0 / ( tmax - tmin + 0.3 ) )
|
// plotD_vs_t( 500, 110, Dt, [dq0, dq1, dq2, dq3], v1, dmin, dmax, tmin, tmax, 1.0 / ( tmax - tmin + 0.3 ) )
|
||||||
|
|
|
@ -46,32 +46,32 @@ function runTests() {
|
||||||
return caption;
|
return caption;
|
||||||
}
|
}
|
||||||
|
|
||||||
// var caption = document.createElement('h3');
|
var caption = document.createElement('h3');
|
||||||
// caption.appendChild(document.createTextNode("Randomised tests (may take a while...)"));
|
caption.appendChild(document.createTextNode("Randomised tests (may take a while...)"));
|
||||||
// container.appendChild(caption);
|
container.appendChild(caption);
|
||||||
// var canvas = document.createElement('CANVAS');
|
var canvas = document.createElement('CANVAS');
|
||||||
// container.appendChild( canvas );
|
container.appendChild( canvas );
|
||||||
// paper.setup( canvas );
|
paper.setup( canvas );
|
||||||
// doRandomTests( randomtestdata );
|
doRandomTests( randomtestdata );
|
||||||
// window.d = randomtestdata;
|
window.d = randomtestdata;
|
||||||
// container.removeChild( canvas );
|
container.removeChild( canvas );
|
||||||
|
|
||||||
runTest('random', function(){
|
runTest('random', function(){
|
||||||
pathA = getRandomPath(5);
|
pathA = getRandomPath(10);
|
||||||
pathB = getRandomPath(5);
|
pathB = getRandomPath(10);
|
||||||
return [pathA, pathB];
|
return [pathA, pathB];
|
||||||
});
|
});
|
||||||
|
|
||||||
// runTest('failcase 1', function(){
|
runTest('failcase 1', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'svgrandom1' ) );
|
group = paper.project.importSVG( document.getElementById( 'svgrandom1' ) );
|
||||||
// pathA = group.children[0];
|
pathA = group.children[0];
|
||||||
// pathB = group.children[1];
|
pathB = group.children[1];
|
||||||
// pathA.style = pathB.style = null;
|
pathA.style = pathB.style = null;
|
||||||
// var np1 = new Path( [pathA.segments[0], pathA.segments[1]] );
|
var np1 = new Path( [pathA.segments[0], pathA.segments[1]] );
|
||||||
// var np2 = new Path( [pathB.segments[0], pathB.segments[1]] );
|
var np2 = new Path( [pathB.segments[0], pathB.segments[1]] );
|
||||||
// return [pathA, pathB];
|
return [pathA, pathB];
|
||||||
// return [np1, np2];
|
// return [np1, np2];
|
||||||
// });
|
});
|
||||||
|
|
||||||
// runTest('failcase 2', function(){
|
// runTest('failcase 2', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'svgrandom2' ) );
|
// group = paper.project.importSVG( document.getElementById( 'svgrandom2' ) );
|
||||||
|
@ -84,162 +84,162 @@ function runTests() {
|
||||||
// return [np1, np2];
|
// return [np1, np2];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('Overlapping circles', function(){
|
runTest('Overlapping circles', function(){
|
||||||
// pathA = new Path.Circle(new Point(80, 110), 50);
|
pathA = new Path.Circle(new Point(80, 110), 50);
|
||||||
// pathB = new Path.Circle(new Point(150, 110), 70);
|
pathB = new Path.Circle(new Point(150, 110), 70);
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
// runTest('Polygon and square', function(){
|
||||||
|
// pathA = new Path.RegularPolygon(new Point(80, 110), 12, 80);
|
||||||
|
// pathB = new Path.Rectangle(new Point(100, 80), [80, 80] );
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// // runTest('Polygon and square', function(){
|
// runTest('Circle and square (overlaps exactly on existing segments)', function(){
|
||||||
// // pathA = new Path.RegularPolygon(new Point(80, 110), 12, 80);
|
// pathA = new Path.Circle(new Point(110, 110), 80);
|
||||||
// // pathB = new Path.Rectangle(new Point(100, 80), [80, 80] );
|
// pathB = new Path.Rectangle(new Point(110, 110), [80, 80] );
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Circle and square (overlaps exactly on existing segments)', function(){
|
|
||||||
// // pathA = new Path.Circle(new Point(110, 110), 80);
|
|
||||||
// // pathB = new Path.Rectangle(new Point(110, 110), [80, 80] );
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Circle and square (existing segments overlaps on curves)', function(){
|
|
||||||
// // pathA = new Path.Circle(new Point(110, 110), 80);
|
|
||||||
// // pathB = new Path.Rectangle(new Point(110, 110), [100, 100] );
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Square and square (one segment overlaps on a line)', function(){
|
|
||||||
// // pathA = new Path.Rectangle(new Point(80, 125), [50, 50] );
|
|
||||||
// // pathA.rotate( 45 );
|
|
||||||
// // pathB = new Path.Rectangle(new Point(pathA.segments[2].point.x, 110), [80, 80] );
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Rectangle and rectangle (overlaps exactly on existing curves)', function(){
|
|
||||||
// // pathA = new Path.Rectangle(new Point(30.5, 50.5), [100, 150]);
|
|
||||||
// // pathB = new Path.Rectangle(new Point(130.5, 60.5), [100, 150]);
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Overlapping stars 1', function(){
|
|
||||||
// // pathA = new Path.Star(new Point(80, 110), 10, 20, 80);
|
|
||||||
// // pathB = new Path.Star(new Point(120, 110), 10, 30, 100);
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// // runTest('Overlapping stars 2', function(){
|
|
||||||
// // pathA = new Path.Star(new Point(110, 110), 20, 20, 80);
|
|
||||||
// // pathB = new Path.Star(new Point(110, 110), 6, 30, 100);
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
// runTest('Circle and banana (multiple intersections within same curve segment)', function(){
|
|
||||||
// pathA = new Path.Circle(new Point(80, 110), 80);
|
|
||||||
// pathB = new Path.Circle(new Point(130, 110), 80 );
|
|
||||||
// pathB.segments[3].point = pathB.segments[3].point.add( [ 0, -120 ] );
|
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('Maximum possible intersections between 2 cubic bezier curve segments - 9', function(){
|
// runTest('Circle and square (existing segments overlaps on curves)', function(){
|
||||||
// pathA = new Path();
|
// pathA = new Path.Circle(new Point(110, 110), 80);
|
||||||
// pathA.add( new Segment( [173, 44], [-281, 268], [-86, 152] ) );
|
// pathB = new Path.Rectangle(new Point(110, 110), [100, 100] );
|
||||||
// pathA.add( new Segment( [47, 93], [-89, 100], [240, -239] ) );
|
|
||||||
// pathA.closed = true;
|
|
||||||
// pathB = pathA.clone();
|
|
||||||
// pathB.rotate( -90 );
|
|
||||||
// pathA.translate( [-10,0] );
|
|
||||||
// pathB.translate( [10,0] );
|
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('SVG gears', function(){
|
// runTest('Square and square (one segment overlaps on a line)', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'svggears' ) );
|
// pathA = new Path.Rectangle(new Point(80, 125), [50, 50] );
|
||||||
// pathA = group.children[0];
|
// pathA.rotate( 45 );
|
||||||
// pathB = group.children[1];
|
// pathB = new Path.Rectangle(new Point(pathA.segments[2].point.x, 110), [80, 80] );
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('Glyphs imported from SVG', function(){
|
// runTest('Rectangle and rectangle (overlaps exactly on existing curves)', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsys' ) );
|
// pathA = new Path.Rectangle(new Point(30.5, 50.5), [100, 150]);
|
||||||
// pathA = group.children[0];
|
// pathB = new Path.Rectangle(new Point(130.5, 60.5), [100, 150]);
|
||||||
// pathB = group.children[1];
|
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('CompoundPaths 1', function(){
|
// runTest('Overlapping stars 1', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
// pathA = new Path.Star(new Point(80, 110), 10, 20, 80);
|
||||||
// pathA = group.children[0];
|
// pathB = new Path.Star(new Point(120, 110), 10, 30, 100);
|
||||||
// pathB = group.children[1];
|
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('CompoundPaths 2 - holes', function(){
|
// runTest('Overlapping stars 2', function(){
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
// pathA = new Path.Star(new Point(110, 110), 20, 20, 80);
|
||||||
// pathA = group.children[0];
|
// pathB = new Path.Star(new Point(110, 110), 6, 30, 100);
|
||||||
|
// return [pathA, pathB];
|
||||||
|
// });
|
||||||
|
|
||||||
|
runTest('Circle and banana (multiple intersections within same curve segment)', function(){
|
||||||
|
pathA = new Path.Circle(new Point(80, 110), 80);
|
||||||
|
pathB = new Path.Circle(new Point(130, 110), 80 );
|
||||||
|
pathB.segments[3].point = pathB.segments[3].point.add( [ 0, -120 ] );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('Maximum possible intersections between 2 cubic bezier curve segments - 9', function(){
|
||||||
|
pathA = new Path();
|
||||||
|
pathA.add( new Segment( [173, 44], [-281, 268], [-86, 152] ) );
|
||||||
|
pathA.add( new Segment( [47, 93], [-89, 100], [240, -239] ) );
|
||||||
|
pathA.closed = true;
|
||||||
|
pathB = pathA.clone();
|
||||||
|
pathB.rotate( -90 );
|
||||||
|
pathA.translate( [-10,0] );
|
||||||
|
pathB.translate( [10,0] );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('SVG gears', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'svggears' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = group.children[1];
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('Glyphs imported from SVG', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsys' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = group.children[1];
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 1', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = group.children[1];
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 2 - holes', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = new CompoundPath();
|
||||||
|
group.children[1].clockwise = true;
|
||||||
|
pathB.addChild(group.children[1]);
|
||||||
|
var npath = new Path.Circle([110, 110], 30);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 3 !', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'svggreenland' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = group.children[1];
|
||||||
|
pathB.scale( 0.5, 1 ).translate( [25.5, 0] );
|
||||||
|
// pathA.scale( 2 );
|
||||||
|
// pathB.scale( 2 );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 4 - holes and islands 1', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = new CompoundPath();
|
||||||
|
group.children[1].clockwise = true;
|
||||||
|
pathB.addChild(group.children[1]);
|
||||||
|
var npath = new Path.Circle([40, 80], 20);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 5 - holes and islands 2', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = new CompoundPath();
|
||||||
|
group.children[1].clockwise = true;
|
||||||
|
pathB.addChild(group.children[1]);
|
||||||
|
var npath = new Path.Circle([40, 80], 20);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
npath = new Path.Circle([120, 110], 30);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
runTest('CompoundPaths 6 - holes and islands 3', function(){
|
||||||
|
group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
||||||
|
pathA = group.children[0];
|
||||||
|
pathB = new CompoundPath();
|
||||||
|
var npath = new Path.Circle([110, 110], 100);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
npath = new Path.Circle([110, 110], 60);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
npath = new Path.Circle([110, 110], 30);
|
||||||
|
pathB.addChild( npath );
|
||||||
|
return [pathA, pathB];
|
||||||
|
});
|
||||||
|
|
||||||
|
// runTest('CompoundPaths 6 - holes and islands 4 (curves overlap exactly on existing curves)', function(){
|
||||||
|
// pathA = new Path.Rectangle(new Point(50.5, 50.5), [100, 120]);
|
||||||
// pathB = new CompoundPath();
|
// pathB = new CompoundPath();
|
||||||
// group.children[1].clockwise = true;
|
// pathB.addChild( new Path.Rectangle(new Point(140.5, 30.5), [100, 150]) );
|
||||||
// pathB.addChild(group.children[1]);
|
// pathB.addChild( new Path.Rectangle(new Point(150.5, 65.5), [50, 100]) );
|
||||||
// var npath = new Path.Circle([110, 110], 30);
|
// // pathB = new Path.Rectangle(new Point(150.5, 80.5), [80, 80] );
|
||||||
// pathB.addChild( npath );
|
|
||||||
// return [pathA, pathB];
|
// return [pathA, pathB];
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// runTest('CompoundPaths 3 !', function(){
|
|
||||||
// group = paper.project.importSVG( document.getElementById( 'svggreenland' ) );
|
|
||||||
// pathA = group.children[0];
|
|
||||||
// pathB = group.children[1];
|
|
||||||
// pathB.scale( 0.5, 1 ).translate( [25.5, 0] );
|
|
||||||
// // pathA.scale( 2 );
|
|
||||||
// // pathB.scale( 2 );
|
|
||||||
// return [pathA, pathB];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// runTest('CompoundPaths 4 - holes and islands 1', function(){
|
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
|
||||||
// pathA = group.children[0];
|
|
||||||
// pathB = new CompoundPath();
|
|
||||||
// group.children[1].clockwise = true;
|
|
||||||
// pathB.addChild(group.children[1]);
|
|
||||||
// var npath = new Path.Circle([40, 80], 20);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// return [pathA, pathB];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// runTest('CompoundPaths 5 - holes and islands 2', function(){
|
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
|
||||||
// pathA = group.children[0];
|
|
||||||
// pathB = new CompoundPath();
|
|
||||||
// group.children[1].clockwise = true;
|
|
||||||
// pathB.addChild(group.children[1]);
|
|
||||||
// var npath = new Path.Circle([40, 80], 20);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// npath = new Path.Circle([120, 110], 30);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// return [pathA, pathB];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// runTest('CompoundPaths 6 - holes and islands 3', function(){
|
|
||||||
// group = paper.project.importSVG( document.getElementById( 'glyphsacirc' ) );
|
|
||||||
// pathA = group.children[0];
|
|
||||||
// pathB = new CompoundPath();
|
|
||||||
// var npath = new Path.Circle([110, 110], 100);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// npath = new Path.Circle([110, 110], 60);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// npath = new Path.Circle([110, 110], 30);
|
|
||||||
// pathB.addChild( npath );
|
|
||||||
// return [pathA, pathB];
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // runTest('CompoundPaths 6 - holes and islands 4 (curves overlap exactly on existing curves)', function(){
|
|
||||||
// // pathA = new Path.Rectangle(new Point(50.5, 50.5), [100, 120]);
|
|
||||||
// // pathB = new CompoundPath();
|
|
||||||
// // pathB.addChild( new Path.Rectangle(new Point(140.5, 30.5), [100, 150]) );
|
|
||||||
// // pathB.addChild( new Path.Rectangle(new Point(150.5, 65.5), [50, 100]) );
|
|
||||||
// // // pathB = new Path.Rectangle(new Point(150.5, 80.5), [80, 80] );
|
|
||||||
// // return [pathA, pathB];
|
|
||||||
// // });
|
|
||||||
|
|
||||||
|
|
||||||
// Plot the run times
|
// Plot the run times
|
||||||
function plotData(){
|
function plotData(){
|
||||||
|
|
Loading…
Reference in a new issue