Detect square paths

This commit is contained in:
Patrick Walton 2018-11-16 15:34:01 -08:00
parent 8c1414e75d
commit bb8aa46c1a
1 changed files with 62 additions and 18 deletions

View File

@ -29,6 +29,8 @@ const QUAD_VERTEX_POSITIONS: Uint8Array = new Uint8Array([
0, 1, 0, 1,
]); ]);
const EPSILON: number = 1e-6;
interface SVGPath { interface SVGPath {
abs(): SVGPath; abs(): SVGPath;
translate(x: number, y: number): SVGPath; translate(x: number, y: number): SVGPath;
@ -37,9 +39,18 @@ interface SVGPath {
SVGPath; SVGPath;
} }
interface Point2D { class Point2D {
x: number; x: number;
y: number; y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
approxEq(other: Point2D): boolean {
return Math.abs(this.x - other.x) <= EPSILON && Math.abs(this.y - other.y) <= EPSILON;
}
} }
interface Size2D { interface Size2D {
@ -228,6 +239,9 @@ class App {
gl.enableVertexAttribArray(coverProgram.attributes.TileIndex); gl.enableVertexAttribArray(coverProgram.attributes.TileIndex);
gl.enableVertexAttribArray(coverProgram.attributes.Color); gl.enableVertexAttribArray(coverProgram.attributes.Color);
// Set up event handlers.
this.canvas.addEventListener('click', event => this.onClick(event), false);
this.scene = null; this.scene = null;
this.primitiveCount = 0; this.primitiveCount = 0;
} }
@ -312,11 +326,12 @@ class App {
point = firstPoint; point = firstPoint;
} else { } else {
point = { point = {
x: parseFloat(segment[segment.length - 2]) - tile.origin.x, x: parseFloat(segment[segment.length - 2]),
y: parseFloat(segment[segment.length - 1]) - tile.origin.y, y: parseFloat(segment[segment.length - 1]),
}; };
} }
/*
if (!(point.x > -1.0)) if (!(point.x > -1.0))
throw new Error("x too low"); throw new Error("x too low");
if (!(point.y > -1.0)) if (!(point.y > -1.0))
@ -325,6 +340,7 @@ class App {
throw new Error("x too high:" + point.x); throw new Error("x too high:" + point.x);
if (!(point.y < TILE_SIZE + 1.0)) if (!(point.y < TILE_SIZE + 1.0))
throw new Error("y too high"); throw new Error("y too high");
*/
if (segment[0] === 'M') { if (segment[0] === 'M') {
firstPoint = point; firstPoint = point;
@ -362,6 +378,10 @@ class App {
this.primitiveCount = primitiveCount; this.primitiveCount = primitiveCount;
console.log(primitiveCount + " primitives"); console.log(primitiveCount + " primitives");
} }
private onClick(event: MouseEvent): void {
this.redraw();
}
} }
class Scene { class Scene {
@ -420,13 +440,16 @@ class Scene {
let x = boundingRect.origin.x - boundingRect.origin.x % TILE_SIZE; let x = boundingRect.origin.x - boundingRect.origin.x % TILE_SIZE;
while (true) { while (true) {
const tileBounds = { const tileBounds = {
origin: {x, y}, origin: new Point2D(x, y),
size: {width: TILE_SIZE, height: TILE_SIZE}, size: {width: TILE_SIZE, height: TILE_SIZE},
}; };
const tilePath = this.clipPathToRect(path, tileBounds); const tilePath = this.clipPathToRect(path, tileBounds);
if (tilePath.toString().length > 0) if (tilePath.toString().length > 0) {
tiles.push(new Tile(pathElementIndex, tilePath, tileBounds.origin)); tilePath.translate(-tileBounds.origin.x, -tileBounds.origin.y);
if (!pathIsSquare(tilePath, TILE_SIZE))
tiles.push(new Tile(pathElementIndex, tilePath, tileBounds.origin));
}
if (x >= boundingRect.origin.x + boundingRect.size.width) if (x >= boundingRect.origin.x + boundingRect.size.width)
break; break;
@ -465,6 +488,7 @@ class Scene {
document.body.removeChild(svgElement); document.body.removeChild(svgElement);
console.log(tiles);
this.tiles = tiles; this.tiles = tiles;
this.pathColors = pathColors; this.pathColors = pathColors;
} }
@ -483,8 +507,8 @@ class Scene {
} }
}); });
if (minX == null || minY == null || maxX == null || maxY == null) if (minX == null || minY == null || maxX == null || maxY == null)
return {origin: {x: 0, y: 0}, size: {width: 0, height: 0}}; return {origin: new Point2D(0, 0), size: {width: 0, height: 0}};
return {origin: {x: minX, y: minY}, size: {width: maxX - minX, height: maxY - minY}}; return {origin: new Point2D(minX, minY), size: {width: maxX - minX, height: maxY - minY}};
} }
private clipPathToRect(path: SVGPath, tileBounds: Rect): SVGPath { private clipPathToRect(path: SVGPath, tileBounds: Rect): SVGPath {
@ -496,17 +520,15 @@ class Scene {
} }
private clipPathToEdge(edge: Edge, edgePos: number, input: SVGPath): SVGPath { private clipPathToEdge(edge: Edge, edgePos: number, input: SVGPath): SVGPath {
let pathStart: Point2D | null = null, from = {x: 0, y: 0}, firstPoint = false; let pathStart: Point2D | null = null, from = new Point2D(0, 0), firstPoint = false;
let output: string[][] = []; let output: string[][] = [];
input.iterate(segment => { input.iterate(segment => {
const event = segment[0]; const event = segment[0];
let to; let to;
switch (event) { switch (event) {
case 'M': case 'M':
from = { from = new Point2D(parseFloat(segment[segment.length - 2]),
x: parseFloat(segment[segment.length - 2]), parseFloat(segment[segment.length - 1]));
y: parseFloat(segment[segment.length - 1]),
};
pathStart = from; pathStart = from;
firstPoint = true; firstPoint = true;
return; return;
@ -516,10 +538,8 @@ class Scene {
to = pathStart; to = pathStart;
break; break;
default: default:
to = { to = new Point2D(parseFloat(segment[segment.length - 2]),
x: parseFloat(segment[segment.length - 2]), parseFloat(segment[segment.length - 1]));
y: parseFloat(segment[segment.length - 1]),
};
break; break;
} }
@ -586,7 +606,7 @@ class Scene {
} }
const intersection = cross(cross(start, end), edgeVector); const intersection = cross(cross(start, end), edgeVector);
return {x: intersection.x / intersection.z, y: intersection.y / intersection.z}; return new Point2D(intersection.x / intersection.z, intersection.y / intersection.z);
} }
} }
@ -687,6 +707,30 @@ function waitForQuery(gl: WebGL2RenderingContext, disjointTimerQueryExt: any, qu
console.log(elapsed + "ms elapsed"); console.log(elapsed + "ms elapsed");
} }
function pathIsSquare(path: SVGPath, squareLength: number): boolean {
const SQUARE_VERTICES = [
new Point2D(0.0, 0.0),
new Point2D(0.0, squareLength),
new Point2D(squareLength, squareLength),
new Point2D(squareLength, 0.0),
];
let result = true;
path.iterate((segment, index) => {
if (index < SQUARE_VERTICES.length) {
const point = new Point2D(parseFloat(segment[1]), parseFloat(segment[2]));
result = result && point.approxEq(SQUARE_VERTICES[index]);
} else if (index === SQUARE_VERTICES.length) {
const point = new Point2D(parseFloat(segment[1]), parseFloat(segment[2]));
result = result && (segment[0] === 'Z' || point.approxEq(SQUARE_VERTICES[0]));
} else if (index === SQUARE_VERTICES.length + 1) {
result = result && segment[0] === 'Z';
} else {
result = false;
}
});
return result;
}
function main(): void { function main(): void {
window.fetch(SVG).then(svg => { window.fetch(SVG).then(svg => {
svg.text().then(svgText => { svg.text().then(svgText => {