More PatternedLine testing and fixes for minor quirks
This commit is contained in:
parent
4eb9ec21d6
commit
d1bab06bcc
|
@ -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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,150 @@
|
||||||
defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => {
|
defineDescribe('PatternedLine', ['./PatternedLine'], (PatternedLine) => {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
describe('unpatterned', () => {
|
function simplify(path, dp) {
|
||||||
describe('line', () => {
|
return path.replace(/[0-9.]+/g, (v) => Number(v).toFixed(dp));
|
||||||
it('connects points with lines', () => {
|
}
|
||||||
const ln = new PatternedLine()
|
|
||||||
.move(10, 20)
|
|
||||||
.line(30, 50)
|
|
||||||
.line(1, 2)
|
|
||||||
.cap();
|
|
||||||
|
|
||||||
expect(ln.asPath()).toEqual(
|
describe('unpatterned', () => {
|
||||||
'M10 20' +
|
it('connects points with simple lines', () => {
|
||||||
'L30 50' +
|
const ln = new PatternedLine()
|
||||||
'L1 2'
|
.move(10, 20)
|
||||||
);
|
.line(30, 50)
|
||||||
});
|
.line(1, 2);
|
||||||
|
|
||||||
|
expect(ln.asPath()).toEqual(
|
||||||
|
'M10 20' +
|
||||||
|
'L30 50' +
|
||||||
|
'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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue