More PatternedLine testing and fixes for minor quirks

This commit is contained in:
David Evans 2018-01-13 00:01:18 +00:00
parent 4eb9ec21d6
commit d1bab06bcc
4 changed files with 192 additions and 63 deletions

View File

@ -5229,26 +5229,24 @@ define('svg/PatternedLine',[],() => {
this.phase = phase; this.phase = phase;
this.x = null; this.x = null;
this.y = null; this.y = null;
this.disconnect = false; this.disconnect = 0;
}
_link() {
if(this.disconnect) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = false;
}
} }
_nextDelta() { _nextDelta() {
return this.pattern.getDelta(this.phase ++); return this.pattern.getDelta(this.phase ++);
} }
cap() { _link() {
if(this.x !== null) { if(this.disconnect === 2) {
this.points.push(this.x + ' ' + this.y); this.points.push(this.x + ' ' + this.y);
this.x = null; this.disconnect = 0;
this.y = null; }
this.disconnect = false; }
cap() {
if(this.disconnect > 0) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
} }
return this; return this;
} }
@ -5257,13 +5255,11 @@ define('svg/PatternedLine',[],() => {
this.cap(); this.cap();
this.x = x; this.x = x;
this.y = y; this.y = y;
this.disconnect = true; this.disconnect = 2;
return this; return this;
} }
line(x, y) { line(x, y) {
this._link();
if(this.pattern) { if(this.pattern) {
const len = Math.sqrt( const len = Math.sqrt(
(x - this.x) * (x - this.x) + (x - this.x) * (x - this.x) +
@ -5281,8 +5277,10 @@ define('svg/PatternedLine',[],() => {
(this.y + pos * dy1 + delta * dy2) (this.y + pos * dy1 + delta * dy2)
); );
} }
this.disconnect = 1;
} else { } else {
this.disconnect = true; this._link();
this.disconnect = 2;
} }
this.x = x; this.x = x;
@ -5291,15 +5289,13 @@ define('svg/PatternedLine',[],() => {
} }
arc(cx, cy, theta) { arc(cx, cy, theta) {
this._link();
const radius = Math.sqrt( const radius = Math.sqrt(
(cx - this.x) * (cx - this.x) + (cx - this.x) * (cx - this.x) +
(cy - this.y) * (cy - this.y) (cy - this.y) * (cy - this.y)
); );
const theta1 = Math.atan2(cx - this.x, cy - this.y); const theta1 = Math.atan2(cx - this.x, cy - this.y);
this.x = cx + Math.sin(theta1 + theta) * radius; const nextX = cx + Math.sin(theta1 + theta) * radius;
this.y = cy - Math.cos(theta1 + theta) * radius; const nextY = cy - Math.cos(theta1 + theta) * radius;
if(this.pattern) { if(this.pattern) {
const dir = (theta < 0 ? 1 : -1); const dir = (theta < 0 ? 1 : -1);
@ -5312,17 +5308,21 @@ define('svg/PatternedLine',[],() => {
(cy - Math.cos(t) * (radius + delta)) (cy - Math.cos(t) * (radius + delta))
); );
} }
this.disconnect = 1;
} else { } else {
this.points.push( this.points.push(
(cx + Math.sin(theta1) * radius) + ' ' + this.x + ' ' + this.y +
(cy - Math.cos(theta1) * radius) +
'A' + radius + ' ' + radius + ' 0 ' + 'A' + radius + ' ' + radius + ' 0 ' +
((theta < 0) ? '0 ' : '1 ') + ((theta < 0) ? '0 ' : '1 ') +
'1 ' + '1 ' +
this.x + ' ' + this.y nextX + ' ' + nextY
); );
this.disconnect = 0;
} }
this.x = nextX;
this.y = nextY;
return this; return this;
} }

File diff suppressed because one or more lines are too long

View File

@ -9,26 +9,24 @@ define(() => {
this.phase = phase; this.phase = phase;
this.x = null; this.x = null;
this.y = null; this.y = null;
this.disconnect = false; this.disconnect = 0;
}
_link() {
if(this.disconnect) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = false;
}
} }
_nextDelta() { _nextDelta() {
return this.pattern.getDelta(this.phase ++); return this.pattern.getDelta(this.phase ++);
} }
cap() { _link() {
if(this.x !== null) { if(this.disconnect === 2) {
this.points.push(this.x + ' ' + this.y); this.points.push(this.x + ' ' + this.y);
this.x = null; this.disconnect = 0;
this.y = null; }
this.disconnect = false; }
cap() {
if(this.disconnect > 0) {
this.points.push(this.x + ' ' + this.y);
this.disconnect = 0;
} }
return this; return this;
} }
@ -37,13 +35,11 @@ define(() => {
this.cap(); this.cap();
this.x = x; this.x = x;
this.y = y; this.y = y;
this.disconnect = true; this.disconnect = 2;
return this; return this;
} }
line(x, y) { line(x, y) {
this._link();
if(this.pattern) { if(this.pattern) {
const len = Math.sqrt( const len = Math.sqrt(
(x - this.x) * (x - this.x) + (x - this.x) * (x - this.x) +
@ -61,8 +57,10 @@ define(() => {
(this.y + pos * dy1 + delta * dy2) (this.y + pos * dy1 + delta * dy2)
); );
} }
this.disconnect = 1;
} else { } else {
this.disconnect = true; this._link();
this.disconnect = 2;
} }
this.x = x; this.x = x;
@ -71,15 +69,13 @@ define(() => {
} }
arc(cx, cy, theta) { arc(cx, cy, theta) {
this._link();
const radius = Math.sqrt( const radius = Math.sqrt(
(cx - this.x) * (cx - this.x) + (cx - this.x) * (cx - this.x) +
(cy - this.y) * (cy - this.y) (cy - this.y) * (cy - this.y)
); );
const theta1 = Math.atan2(cx - this.x, cy - this.y); const theta1 = Math.atan2(cx - this.x, cy - this.y);
this.x = cx + Math.sin(theta1 + theta) * radius; const nextX = cx + Math.sin(theta1 + theta) * radius;
this.y = cy - Math.cos(theta1 + theta) * radius; const nextY = cy - Math.cos(theta1 + theta) * radius;
if(this.pattern) { if(this.pattern) {
const dir = (theta < 0 ? 1 : -1); const dir = (theta < 0 ? 1 : -1);
@ -92,17 +88,21 @@ define(() => {
(cy - Math.cos(t) * (radius + delta)) (cy - Math.cos(t) * (radius + delta))
); );
} }
this.disconnect = 1;
} else { } else {
this.points.push( this.points.push(
(cx + Math.sin(theta1) * radius) + ' ' + this.x + ' ' + this.y +
(cy - Math.cos(theta1) * radius) +
'A' + radius + ' ' + radius + ' 0 ' + 'A' + radius + ' ' + radius + ' 0 ' +
((theta < 0) ? '0 ' : '1 ') + ((theta < 0) ? '0 ' : '1 ') +
'1 ' + '1 ' +
this.x + ' ' + this.y nextX + ' ' + nextY
); );
this.disconnect = 0;
} }
this.x = nextX;
this.y = nextY;
return this; return this;
} }

View File

@ -1,14 +1,16 @@
defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => { defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => {
'use strict'; 'use strict';
function simplify(path, dp) {
return path.replace(/[0-9.]+/g, (v) => Number(v).toFixed(dp));
}
describe('unpatterned', () => { describe('unpatterned', () => {
describe('line', () => { it('connects points with simple lines', () => {
it('connects points with lines', () => {
const ln = new PatternedLine() const ln = new PatternedLine()
.move(10, 20) .move(10, 20)
.line(30, 50) .line(30, 50)
.line(1, 2) .line(1, 2);
.cap();
expect(ln.asPath()).toEqual( expect(ln.asPath()).toEqual(
'M10 20' + 'M10 20' +
@ -16,6 +18,133 @@ defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => {
'L1 2' 'L1 2'
); );
}); });
it('supports simple (circular) arcs', () => {
const ln = new PatternedLine()
.move(10, 20)
.arc(10, 30, Math.PI);
expect(simplify(ln.asPath(), 0)).toEqual(
'M10 20' +
'A10 10 0 1 1 10 40'
);
});
it('can combine lines and arcs', () => {
const ln = new PatternedLine()
.move(10, 20)
.line(20, 20)
.arc(20, 30, Math.PI)
.line(10, 40);
expect(simplify(ln.asPath(), 0)).toEqual(
'M10 20' +
'L20 20' +
'A10 10 0 1 1 20 40' +
'L10 40'
);
});
it('ignores cap()', () => {
const ln1 = new PatternedLine()
.move(10, 20)
.line(10, 40)
.cap();
expect(ln1.asPath()).toEqual(
'M10 20' +
'L10 40'
);
const ln2 = new PatternedLine()
.move(10, 20)
.arc(10, 30, Math.PI)
.cap();
expect(simplify(ln2.asPath(), 0)).toEqual(
'M10 20' +
'A10 10 0 1 1 10 40'
);
}); });
}); });
describe('patterned', () => {
const patternDeltas = [-1, 1, -2];
const pattern = {
partWidth: 5,
getDelta: (p) => {
return patternDeltas[p % 3];
},
};
it('draws lines using the given pattern', () => {
const ln = new PatternedLine(pattern)
.move(10, 20)
.line(30, 20);
// last segment of line is not rendered to avoid high frequencies
// near line segment joins
expect(ln.asPath()).toEqual(
'M10 19' +
'L15 21' +
'L20 18' +
'L25 19'
);
});
it('maintains phase between line segments', () => {
const ln = new PatternedLine(pattern)
.move(10, 20)
.line(30, 20)
.line(30, 33);
expect(ln.asPath()).toEqual(
'M10 19' +
'L15 21' +
'L20 18' +
'L25 19' +
'L29 20' +
'L32 25'
);
});
it('completes the line beyond the pattern with cap()', () => {
const ln = new PatternedLine(pattern)
.move(10, 20)
.line(30, 20)
.line(30, 33)
.cap();
expect(ln.asPath()).toEqual(
'M10 19' +
'L15 21' +
'L20 18' +
'L25 19' +
'L29 20' +
'L32 25' +
'L30 33'
);
});
it('supports simple (circular) arcs using straight segments', () => {
const ln = new PatternedLine(pattern)
.move(10, 20)
.arc(10, 30, Math.PI)
.line(0, 40);
expect(simplify(ln.asPath(), 1)).toEqual(
'M10.0 19.0' +
'L14.3 22.1' +
'L20.1 23.5' +
'L21.0 29.2' +
'L18.2 33.7' +
'L17.2 39.6' +
'L10.0 41.0' +
'L5.0 39.0'
);
});
});
}); });